<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>how.wtf</title><link>https://how.wtf/</link><description>Recent content on how.wtf</description><language>en-us</language><copyright>© 2021-2024 how.wtf</copyright><lastBuildDate>Sun, 30 Jun 2024 17:35:00 -0400</lastBuildDate><atom:link href="https://how.wtf/index.xml" rel="self" type="application/rss+xml"/><item><title>API Key Authentication with API Gateway using AWS CDK</title><link>https://how.wtf/api-key-authentication-with-api-gateway-using-aws-cdk.html</link><pubDate>Sun, 30 Jun 2024 17:35:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/api-key-authentication-with-api-gateway-using-aws-cdk.html</guid><description>API key authentication is a common method for securing APIs by controlling access to them. It&amp;rsquo;s important to note that API keys are great for authentication, but further development should be made to ensure proper authorization at the business level. API keys do not ensure that the correct permissions are being enforced, only that the user has access to the API.
Regardless, let&amp;rsquo;s get started! In this post, we&amp;rsquo;re going to touch on a few services:</description><content:encoded><![CDATA[<p>API key authentication is a common method for securing APIs by controlling access to them. It&rsquo;s important to note that API keys are great for authentication, but further development should be made to ensure proper authorization at the business level. API keys do not ensure that the correct permissions are being enforced, only that the user has access to the API.</p>
<p>Regardless, let&rsquo;s get started! In this post, we&rsquo;re going to touch on a few services:</p>
<ol>
<li>API Gateway with Proxy Integration</li>
<li>Lambda Authorizer</li>
<li>AWS CDK</li>
</ol>
<h2 id="get-started">Get started</h2>
<p>Conceptually, the flow of our application will look like this:</p>
<ol>
<li>Client makes a request to API Gateway with API key</li>
<li>The lambda authorizer determines if the API key is valid</li>
<li>If the API key is valid, the policy is generated and the request is allowed to pass through to the lambda function</li>
<li>If the API key is invalid, the request is denied</li>
<li>The lambda function is invoked and returns a response</li>
</ol>
<h3 id="set-up-the-cdk-project">Set up the CDK project</h3>
<p>Firstly, let&rsquo;s create the CDK project. I will choose TypeScript as the language, but you can choose any language you prefer. Please refer to the <a href="https://docs.aws.amazon.com/cdk/v2/guide/hello_world.html">AWS CDK hello world documentation</a> for other supported languages.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">cdk init --language typescript</span></span></code></pre></div><p>Next, let&rsquo;s install the necessary dependencies:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">npm i</span></span></code></pre></div><p>In addition, install the <code>@types/aws-lambda</code> package:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">npm i @types/aws-lambda</span></span></code></pre></div><p>Let&rsquo;s start by finding the primary stack file which is located under the <code>lib</code> directory. In my case, it&rsquo;s <code>lib/api-key-gateway-stack.ts</code>.</p>
<h2 id="edit-the-cdk-stack">Edit the CDK stack</h2>
<p>Luckily, in a few lines of code, we can spin up a full-featured API Gateway with a lambda handler using the AWS CDK.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">Duration</span><span class="p">,</span> <span class="nx">Stack</span><span class="p">,</span> <span class="nx">StackProps</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;aws-cdk-lib&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">Construct</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;constructs&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">Runtime</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;aws-cdk-lib/aws-lambda&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kr">import</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">  <span class="nx">LambdaRestApi</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">  <span class="nx">TokenAuthorizer</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  <span class="nx">AuthorizationType</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;aws-cdk-lib/aws-apigateway&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">NodejsFunction</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;aws-cdk-lib/aws-lambda-nodejs&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="kr">export</span> <span class="kr">class</span> <span class="nx">ApiKeyGatewayStack</span> <span class="kr">extends</span> <span class="nx">Stack</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">  <span class="kr">constructor</span><span class="p">(</span><span class="nx">scope</span>: <span class="kt">Construct</span><span class="p">,</span> <span class="nx">id</span>: <span class="kt">string</span><span class="p">,</span> <span class="nx">props?</span>: <span class="kt">StackProps</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="kr">super</span><span class="p">(</span><span class="nx">scope</span><span class="p">,</span> <span class="nx">id</span><span class="p">,</span> <span class="nx">props</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="kr">const</span> <span class="nx">fn</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">NodejsFunction</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;server&#34;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">      <span class="nx">entry</span><span class="o">:</span> <span class="s2">&#34;bin/server.ts&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">      <span class="nx">handler</span><span class="o">:</span> <span class="s2">&#34;handler&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">      <span class="nx">runtime</span>: <span class="kt">Runtime.NODEJS_20_X</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">      <span class="nx">timeout</span>: <span class="kt">Duration.minutes</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="kr">const</span> <span class="nx">auth</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">NodejsFunction</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;auth&#34;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">      <span class="nx">entry</span><span class="o">:</span> <span class="s2">&#34;bin/auth.ts&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">      <span class="nx">handler</span><span class="o">:</span> <span class="s2">&#34;handler&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">      <span class="nx">runtime</span>: <span class="kt">Runtime.NODEJS_20_X</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">      <span class="nx">timeout</span>: <span class="kt">Duration.seconds</span><span class="p">(</span><span class="mi">10</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">    <span class="kr">const</span> <span class="nx">api</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">LambdaRestApi</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;api&#34;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">      <span class="nx">handler</span>: <span class="kt">fn</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">      <span class="nx">defaultMethodOptions</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">        <span class="nx">authorizationType</span>: <span class="kt">AuthorizationType.CUSTOM</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">        <span class="nx">authorizer</span>: <span class="kt">new</span> <span class="nx">TokenAuthorizer</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;authorizer&#34;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">          <span class="nx">handler</span>: <span class="kt">auth</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">        <span class="p">}),</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Let&rsquo;s break down the code:</p>
<ol>
<li>The first construct, <code>NodejsFunction</code>, is a node lambda function that will serve as our primary handler.</li>
<li>The second construct, another <code>NodejsFunction</code>, is a lambda authorizer that will be used to validate the API key.</li>
<li>The third construct, <code>LambdaRestApi</code>, is the API Gateway that includes the first construct wired as the proxy integration and the second construct as the authorizer.</li>
</ol>
<h2 id="create-the-lambda-handler">Create the lambda handler</h2>
<p>Located at <code>bin/server.ts</code>, we will create a simplistic lambda function that returns <code>Hello, World!</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">APIGatewayProxyEvent</span><span class="p">,</span> <span class="nx">APIGatewayProxyResult</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;aws-lambda&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">handler</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="nx">event</span>: <span class="kt">APIGatewayProxyEvent</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">)</span><span class="o">:</span> <span class="nx">Promise</span><span class="p">&lt;</span><span class="nt">APIGatewayProxyResult</span><span class="p">&gt;</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">  <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="nx">statusCode</span>: <span class="kt">200</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="nx">body</span>: <span class="kt">JSON.stringify</span><span class="p">({</span> <span class="nx">message</span><span class="o">:</span> <span class="s2">&#34;Hello, World!&#34;</span> <span class="p">}),</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">};</span></span></span></code></pre></div><h2 id="create-the-lambda-authorizer">Create the lambda authorizer</h2>
<p>Next, let&rsquo;s create the lambda authorizer located at <code>bin/auth.ts</code>. This lambda function will be responsible for validating the API key.</p>
<p>To keep it simple, we will hardcode the API key to <code>Bearer abc123</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">APIGatewayTokenAuthorizerEvent</span><span class="p">,</span> <span class="nx">Handler</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;aws-lambda&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">handler</span>: <span class="kt">Handler</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="nx">event</span>: <span class="kt">APIGatewayTokenAuthorizerEvent</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">  <span class="kr">const</span> <span class="nx">effect</span> <span class="o">=</span> <span class="nx">event</span><span class="p">.</span><span class="nx">authorizationToken</span> <span class="o">==</span> <span class="s2">&#34;Bearer abc123&#34;</span> <span class="o">?</span> <span class="s2">&#34;Allow&#34;</span> <span class="o">:</span> <span class="s2">&#34;Deny&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="nx">principalId</span><span class="o">:</span> <span class="s2">&#34;abc123&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="nx">policyDocument</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">      <span class="nx">Version</span><span class="o">:</span> <span class="s2">&#34;2012-10-17&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">      <span class="nx">Statement</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">          <span class="nx">Action</span><span class="o">:</span> <span class="s2">&#34;execute-api:Invoke&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">          <span class="nx">Effect</span>: <span class="kt">effect</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">          <span class="nx">Resource</span><span class="o">:</span> <span class="p">[</span><span class="nx">event</span><span class="p">.</span><span class="nx">methodArn</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">      <span class="p">],</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="p">};</span></span></span></code></pre></div><h2 id="deploy-the-stack">Deploy the stack</h2>
<p>Now that we have our stack and lambda handlers setup, let&rsquo;s deploy the stack!</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">npx cdk deploy</span></span></code></pre></div><p>Once the deployment is complete, you should see the API Gateway endpoint as an output.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">Do you wish to deploy these changes (y/n)? y
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">ApiKeyGatewayStack: deploying... [1/1]
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">ApiKeyGatewayStack: creating CloudFormation changeset...
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"> ✅  ApiKeyGatewayStack
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">✨  Deployment time: 45.34s
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">Outputs:
</span></span><span class="line"><span class="ln">10</span><span class="cl">ApiKeyGatewayStack.apiEndpoint9349E63C = https://x2s65m7xyd.execute-api.us-east-1.amazonaws.com/prod/
</span></span><span class="line"><span class="ln">11</span><span class="cl">Stack ARN:
</span></span><span class="line"><span class="ln">12</span><span class="cl">arn:aws:cloudformation:us-east-1:123456789012:stack/ApiKeyGatewayStack/0ca225a0-3727-11ef-ae64-0affd17461c9
</span></span><span class="line"><span class="ln">13</span><span class="cl">✨  Total time: 117.33s</span></span></code></pre></div><h2 id="test-the-api">Test the API</h2>
<p>Let&rsquo;s use <code>curl</code> to test the API without the API key.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl https://&lt;id&gt;.execute-api.us-east-1.amazonaws.com/prod/</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span><span class="nt">&#34;message&#34;</span><span class="p">:</span><span class="s2">&#34;Unauthorized&#34;</span><span class="p">}</span></span></span></code></pre></div><p>As expected, we received an unauthorized response. Now, let&rsquo;s test the API with the API key.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl https://x2s65m7xyd.execute-api.us-east-1.amazonaws.com/prod/ <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    -H <span class="s2">&#34;Authorization: Bearer abc123&#34;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span><span class="nt">&#34;message&#34;</span><span class="p">:</span><span class="s2">&#34;Hello, World!&#34;</span><span class="p">}</span></span></span></code></pre></div><p>Great! We have successfully created an API Gateway with a lambda authorizer using the AWS CDK. At this point, you may choose to extend the Lambda Authorizer to query another data source like DynamoDB that stores API keys.</p>
<h2 id="clean-up">Clean up</h2>
<p>Lastly, let&rsquo;s clean up our AWS resources by destroying the stack:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">npx cdk destroy</span></span></code></pre></div><p>That&rsquo;s it! You successfully created an API Gateway with a lambda authorizer using the AWS CDK.</p>
]]></content:encoded></item><item><title>A step-by-step guide on how to use the Amazon Bedrock Converse API</title><link>https://how.wtf/a-step-by-step-guide-on-how-to-use-the-amazon-bedrock-converse-api.html</link><pubDate>Sun, 02 Jun 2024 13:25:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/a-step-by-step-guide-on-how-to-use-the-amazon-bedrock-converse-api.html</guid><description>On May 30th, 2024, Amazon announced the release of the Bedrock Converse API. This API is designed to provide a consistent experience for &amp;ldquo;conversing&amp;rdquo; with Amazon Bedrock models.
The API supports:
Conversations with multiple turns System messages Tool use Image and text input In this post, we&amp;rsquo;ll walk through how to use the Amazon Bedrock Converse API with the Claude Haiku foundational model.
Please keep in mind that not all foundational models may support all the features of the Converse API.</description><content:encoded><![CDATA[<p>On May 30th, 2024, Amazon announced the <a href="https://aws.amazon.com/about-aws/whats-new/2024/05/amazon-bedrock-new-converse-api/">release of the Bedrock Converse API</a>. This API is designed to provide a consistent experience for &ldquo;conversing&rdquo; with Amazon Bedrock models.</p>
<p>The API supports:</p>
<ol>
<li>Conversations with multiple turns</li>
<li>System messages</li>
<li>Tool use</li>
<li>Image and text input</li>
</ol>
<p>In this post, we&rsquo;ll walk through how to use the Amazon Bedrock Converse API with the Claude Haiku foundational model.</p>
<p>Please keep in mind that not all foundational models may support all the features of the Converse API. For more details per model, see the <a href="https://docs.aws.amazon.com/bedrock/latest/userguide/conversation-inference.html#conversation-inference-supported-models-features">Amazon Bedrock documentation</a>.</p>
<h2 id="getting-started">Getting started</h2>
<p>To get started, let&rsquo;s install the <code>boto3</code> package.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install boto3</span></span></code></pre></div><p>Next, we&rsquo;ll create a new Python script and import the necessary dependencies.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span></span></span></code></pre></div><h2 id="step-1---starting-a-conversation">Step 1 - Starting a conversation</h2>
<p>To start off simple, let&rsquo;s send a single message to Claude.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">messages</span> <span class="o">=</span> <span class="p">[{</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;What is your name?&#34;</span><span class="p">}]}]</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">converse</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-3-haiku-20240307-v1:0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">messages</span><span class="o">=</span><span class="n">messages</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="p">)</span></span></span></code></pre></div><p>The response is a dictionary containing the response and other metadata information from the API. For more information regarding the output, please refer to the <a href="https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_Converse.html#API_runtime_Converse_ResponseSyntax">Amazon Bedrock documentation</a>.</p>
<p>For the purposes of this post, I&rsquo;ll print the response as JSON.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;ResponseMetadata&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="nt">&#34;RequestId&#34;</span><span class="p">:</span> <span class="s2">&#34;6984dcf2-c6aa-4000-a3d6-22e34a43df12&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="nt">&#34;HTTPStatusCode&#34;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="nt">&#34;HTTPHeaders&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">      <span class="nt">&#34;date&#34;</span><span class="p">:</span> <span class="s2">&#34;Sun, 02 Jun 2024 14:54:08 GMT&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">      <span class="nt">&#34;content-type&#34;</span><span class="p">:</span> <span class="s2">&#34;application/json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">      <span class="nt">&#34;content-length&#34;</span><span class="p">:</span> <span class="s2">&#34;222&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">      <span class="nt">&#34;connection&#34;</span><span class="p">:</span> <span class="s2">&#34;keep-alive&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">      <span class="nt">&#34;x-amzn-requestid&#34;</span><span class="p">:</span> <span class="s2">&#34;6984dcf2-c6aa-4000-a3d6-22e34a43df12&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="nt">&#34;RetryAttempts&#34;</span><span class="p">:</span> <span class="mi">0</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">  <span class="nt">&#34;output&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="nt">&#34;message&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">      <span class="nt">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;assistant&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">      <span class="nt">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">          <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;My name is Claude. It&#39;s nice to meet you!&#34;</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">  <span class="nt">&#34;stopReason&#34;</span><span class="p">:</span> <span class="s2">&#34;end_turn&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">  <span class="nt">&#34;usage&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">    <span class="nt">&#34;inputTokens&#34;</span><span class="p">:</span> <span class="mi">12</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">    <span class="nt">&#34;outputTokens&#34;</span><span class="p">:</span> <span class="mi">15</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">    <span class="nt">&#34;totalTokens&#34;</span><span class="p">:</span> <span class="mi">27</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">  <span class="nt">&#34;metrics&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">    <span class="nt">&#34;latencyMs&#34;</span><span class="p">:</span> <span class="mi">560</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>To retrieve the contents of the message, we can access the <code>output</code> key in the response.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">messages</span> <span class="o">=</span> <span class="p">[{</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;What is your name?&#34;</span><span class="p">}]}]</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">converse</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-3-haiku-20240307-v1:0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">messages</span><span class="o">=</span><span class="n">messages</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">ai_message</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;output&#34;</span><span class="p">][</span><span class="s2">&#34;message&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">output_text</span> <span class="o">=</span> <span class="n">ai_message</span><span class="p">[</span><span class="s2">&#34;content&#34;</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s2">&#34;text&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">output_text</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">My name is Claude. It&#39;s nice to meet you!</span></span></code></pre></div><h2 id="step-2---continuing-a-conversation">Step 2 - Continuing a conversation</h2>
<p>Let&rsquo;s continue the conversation by appending the AI&rsquo;s message to the original list of messages. This will allow us to have a multi-turn conversation.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">messages</span> <span class="o">=</span> <span class="p">[{</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;What is your name?&#34;</span><span class="p">}]}]</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">converse</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-3-haiku-20240307-v1:0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">messages</span><span class="o">=</span><span class="n">messages</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">ai_message</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;output&#34;</span><span class="p">][</span><span class="s2">&#34;message&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ai_message</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="c1"># Let&#39;s ask another question</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;Can you help me?&#34;</span><span class="p">}]})</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">converse</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-3-haiku-20240307-v1:0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="n">messages</span><span class="o">=</span><span class="n">messages</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="p">[</span><span class="s2">&#34;output&#34;</span><span class="p">][</span><span class="s2">&#34;message&#34;</span><span class="p">][</span><span class="s2">&#34;content&#34;</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s2">&#34;text&#34;</span><span class="p">])</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Yes, I&#39;d be happy to try and help you with whatever you need assistance with. What can I help you with?</span></span></code></pre></div><h2 id="step-3---using-images">Step 3 - Using images</h2>
<p>The Amazon Bedrock Converse API supports images as input. Let&rsquo;s send an image to Claude and see how it responds. I&rsquo;ll download an <a href="https://upload.wikimedia.org/wikipedia/commons/4/4d/Cat_November_2010-1a.jpg">image of a cat from Wikipedia</a> and send it to claude.</p>
<p>For this example, I used the <code>requests</code> library to download the image. If you don&rsquo;t have it installed, you can install it using <code>pip install requests</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install requests</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">requests</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">messages</span> <span class="o">=</span> <span class="p">[{</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;What is your name?&#34;</span><span class="p">}]}]</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">converse</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-3-haiku-20240307-v1:0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="n">messages</span><span class="o">=</span><span class="n">messages</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">ai_message</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;output&#34;</span><span class="p">][</span><span class="s2">&#34;message&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ai_message</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;Can you help me?&#34;</span><span class="p">}]})</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">converse</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-3-haiku-20240307-v1:0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="n">messages</span><span class="o">=</span><span class="n">messages</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="n">ai_message</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;output&#34;</span><span class="p">][</span><span class="s2">&#34;message&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ai_message</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="n">image_bytes</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="s2">&#34;https://upload.wikimedia.org/wikipedia/commons/4/4d/Cat_November_2010-1a.jpg&#34;</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="p">)</span><span class="o">.</span><span class="n">content</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">        <span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">        <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">            <span class="p">{</span><span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;What is in this image?&#34;</span><span class="p">},</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">            <span class="p">{</span><span class="s2">&#34;image&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;format&#34;</span><span class="p">:</span> <span class="s2">&#34;jpeg&#34;</span><span class="p">,</span> <span class="s2">&#34;source&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;bytes&#34;</span><span class="p">:</span> <span class="n">image_bytes</span><span class="p">}}},</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">        <span class="p">],</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">converse</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-3-haiku-20240307-v1:0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">    <span class="n">messages</span><span class="o">=</span><span class="n">messages</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl">
</span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="n">ai_message</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;output&#34;</span><span class="p">][</span><span class="s2">&#34;message&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">ai_message</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;assistant&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nt">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">      <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;The image shows a domestic cat. The cat appears to be a tabby cat with a striped coat pattern. The cat is sitting upright and its green eyes are clearly visible, with a focused and alert expression. The background suggests an outdoor, snowy environment, with some blurred branches or vegetation visible behind the cat.&#34;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>As you can see, the AI was able to identify the image as a cat and provide a detailed description of the image within a conversational context.</p>
<h2 id="step-4---using-a-single-tool">Step 4 - Using a single tool</h2>
<p>For this section, let&rsquo;s start a new conversation with Claude and provide tools it can use.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">tools</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="s2">&#34;toolSpec&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">            <span class="s2">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;get_weather&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Get the current weather in a given location&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">            <span class="s2">&#34;inputSchema&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">                <span class="s2">&#34;json&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">                    <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">                    <span class="s2">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">                        <span class="s2">&#34;location&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">                            <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">                            <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The city and state, e.g. San Francisco, CA&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">                        <span class="p">},</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">                        <span class="s2">&#34;unit&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">                            <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">                            <span class="s2">&#34;enum&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;celsius&#34;</span><span class="p">,</span> <span class="s2">&#34;fahrenheit&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">                            <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The unit of temperature, either &#39;celsius&#39; or &#39;fahrenheit&#39;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">                        <span class="p">},</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">                    <span class="p">},</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">                    <span class="s2">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;location&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="n">messages</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">        <span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">        <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;What is the weather like right now in New York?&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">converse</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-3-haiku-20240307-v1:0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">    <span class="n">messages</span><span class="o">=</span><span class="n">messages</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl">    <span class="n">toolConfig</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;tools&#34;</span><span class="p">:</span> <span class="n">tools</span><span class="p">},</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">
</span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="p">[</span><span class="s2">&#34;output&#34;</span><span class="p">])</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;message&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="nt">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;assistant&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="nt">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;Okay, let me check the current weather for New York:&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="nt">&#34;toolUse&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">          <span class="nt">&#34;toolUseId&#34;</span><span class="p">:</span> <span class="s2">&#34;tooluse_rRwaOoldTeiRiDZhTadP0A&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">          <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;get_weather&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">          <span class="nt">&#34;input&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">            <span class="nt">&#34;location&#34;</span><span class="p">:</span> <span class="s2">&#34;New York, NY&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="nt">&#34;unit&#34;</span><span class="p">:</span> <span class="s2">&#34;fahrenheit&#34;</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>The output includes a <code>toolUse</code> object that indicates to us, the developers, that the AI is using the <code>get_weather</code> tool to fetch the current weather in New York. We must now fulfill the tool request by responding with the weather information.</p>
<p>But first, let&rsquo;s build a simplistic router that can handle the tool request and respond with the weather information.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">def</span> <span class="nf">get_weather</span><span class="p">(</span><span class="n">location</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">unit</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&#34;fahrenheit&#34;</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="k">return</span> <span class="p">{</span><span class="s2">&#34;temperature&#34;</span><span class="p">:</span> <span class="s2">&#34;78&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">def</span> <span class="nf">tool_router</span><span class="p">(</span><span class="n">tool_name</span><span class="p">,</span> <span class="nb">input</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="k">match</span> <span class="n">tool_name</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">        <span class="k">case</span> <span class="s2">&#34;get_weather&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">            <span class="k">return</span> <span class="n">get_weather</span><span class="p">(</span><span class="nb">input</span><span class="p">[</span><span class="s2">&#34;location&#34;</span><span class="p">],</span> <span class="nb">input</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;unit&#34;</span><span class="p">,</span> <span class="s2">&#34;fahrenheit&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">        <span class="k">case</span> <span class="n">_</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl">            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Unknown tool: </span><span class="si">{</span><span class="n">tool_name</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span></span></span></code></pre></div><p>Now, let&rsquo;s update the code to handle the tool request and respond with the weather information.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="k">def</span> <span class="nf">get_weather</span><span class="p">(</span><span class="n">location</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">unit</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&#34;fahrenheit&#34;</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="k">return</span> <span class="p">{</span><span class="s2">&#34;temperature&#34;</span><span class="p">:</span> <span class="s2">&#34;78&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="k">def</span> <span class="nf">tool_router</span><span class="p">(</span><span class="n">tool_name</span><span class="p">,</span> <span class="nb">input</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="k">match</span> <span class="n">tool_name</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="k">case</span> <span class="s2">&#34;get_weather&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            <span class="k">return</span> <span class="n">get_weather</span><span class="p">(</span><span class="nb">input</span><span class="p">[</span><span class="s2">&#34;location&#34;</span><span class="p">],</span> <span class="nb">input</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;unit&#34;</span><span class="p">,</span> <span class="s2">&#34;fahrenheit&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="k">case</span> <span class="n">_</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Unknown tool: </span><span class="si">{</span><span class="n">tool_name</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="n">tools</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="s2">&#34;toolSpec&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">            <span class="s2">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;get_weather&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">            <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Get the current weather in a given location&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">            <span class="s2">&#34;inputSchema&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">                <span class="s2">&#34;json&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">                    <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">                    <span class="s2">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">                        <span class="s2">&#34;location&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">                            <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">                            <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The city and state, e.g. San Francisco, CA&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">                        <span class="p">},</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">                        <span class="s2">&#34;unit&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">                            <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">                            <span class="s2">&#34;enum&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;celsius&#34;</span><span class="p">,</span> <span class="s2">&#34;fahrenheit&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">                            <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The unit of temperature, either &#39;celsius&#39; or &#39;fahrenheit&#39;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">                        <span class="p">},</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">                    <span class="p">},</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">                    <span class="s2">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;location&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="n">messages</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl">        <span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">43</span><span class="cl">        <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;What is the weather like right now in New York?&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln">44</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">converse</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">47</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-3-haiku-20240307-v1:0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">48</span><span class="cl">    <span class="n">messages</span><span class="o">=</span><span class="n">messages</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl">    <span class="n">toolConfig</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;tools&#34;</span><span class="p">:</span> <span class="n">tools</span><span class="p">},</span>
</span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">51</span><span class="cl">
</span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="n">ai_message</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;output&#34;</span><span class="p">][</span><span class="s2">&#34;message&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ai_message</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">54</span><span class="cl">
</span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="k">if</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;stopReason&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;tool_use&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">56</span><span class="cl">    <span class="n">contents</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;output&#34;</span><span class="p">][</span><span class="s2">&#34;message&#34;</span><span class="p">][</span><span class="s2">&#34;content&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">57</span><span class="cl">    <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">contents</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">58</span><span class="cl">        <span class="k">if</span> <span class="s2">&#34;toolUse&#34;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">59</span><span class="cl">            <span class="k">continue</span>
</span></span><span class="line"><span class="ln">60</span><span class="cl">
</span></span><span class="line"><span class="ln">61</span><span class="cl">        <span class="n">tool_use</span> <span class="o">=</span> <span class="n">c</span><span class="p">[</span><span class="s2">&#34;toolUse&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">62</span><span class="cl">        <span class="n">tool_id</span> <span class="o">=</span> <span class="n">tool_use</span><span class="p">[</span><span class="s2">&#34;toolUseId&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">63</span><span class="cl">        <span class="n">tool_name</span> <span class="o">=</span> <span class="n">tool_use</span><span class="p">[</span><span class="s2">&#34;name&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">64</span><span class="cl">        <span class="nb">input</span> <span class="o">=</span> <span class="n">tool_use</span><span class="p">[</span><span class="s2">&#34;input&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">65</span><span class="cl">
</span></span><span class="line"><span class="ln">66</span><span class="cl">        <span class="n">tool_result</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;toolUseId&#34;</span><span class="p">:</span> <span class="n">tool_id</span><span class="p">}</span>
</span></span><span class="line"><span class="ln">67</span><span class="cl">        <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">68</span><span class="cl">            <span class="n">output</span> <span class="o">=</span> <span class="n">tool_router</span><span class="p">(</span><span class="n">tool_name</span><span class="p">,</span> <span class="nb">input</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">69</span><span class="cl">            <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">output</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">70</span><span class="cl">                <span class="n">tool_result</span><span class="p">[</span><span class="s2">&#34;content&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[{</span><span class="s2">&#34;json&#34;</span><span class="p">:</span> <span class="n">output</span><span class="p">}]</span>
</span></span><span class="line"><span class="ln">71</span><span class="cl">            <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">output</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">72</span><span class="cl">                <span class="n">tool_result</span><span class="p">[</span><span class="s2">&#34;content&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[{</span><span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="n">output</span><span class="p">}]</span>
</span></span><span class="line"><span class="ln">73</span><span class="cl">            <span class="c1"># Add more cases, such as images, if needed</span>
</span></span><span class="line"><span class="ln">74</span><span class="cl">            <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">75</span><span class="cl">                <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Unsupported output type: </span><span class="si">{</span><span class="nb">type</span><span class="p">(</span><span class="n">output</span><span class="p">)</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">76</span><span class="cl">        <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">77</span><span class="cl">            <span class="n">tool_result</span><span class="p">[</span><span class="s2">&#34;content&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[{</span><span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&#34;An unknown error occurred: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">}]</span>
</span></span><span class="line"><span class="ln">78</span><span class="cl">            <span class="n">tool_result</span><span class="p">[</span><span class="s2">&#34;status&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;error&#34;</span>
</span></span><span class="line"><span class="ln">79</span><span class="cl">
</span></span><span class="line"><span class="ln">80</span><span class="cl">        <span class="n">message</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&#34;toolResult&#34;</span><span class="p">:</span> <span class="n">tool_result</span><span class="p">}]}</span>
</span></span><span class="line"><span class="ln">81</span><span class="cl">        <span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">82</span><span class="cl">
</span></span><span class="line"><span class="ln">83</span><span class="cl">    <span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">converse</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">84</span><span class="cl">        <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-3-haiku-20240307-v1:0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">85</span><span class="cl">        <span class="n">messages</span><span class="o">=</span><span class="n">messages</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">86</span><span class="cl">        <span class="n">toolConfig</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;tools&#34;</span><span class="p">:</span> <span class="n">tools</span><span class="p">},</span>
</span></span><span class="line"><span class="ln">87</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">88</span><span class="cl">
</span></span><span class="line"><span class="ln">89</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="p">[</span><span class="s2">&#34;output&#34;</span><span class="p">])</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;message&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="nt">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;assistant&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="nt">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;According to the weather data, the current temperature in New York, NY is 78 degrees Fahrenheit.&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Great! We have successfully responded to the AI tool request and provided the weather information for New York.</p>
<h2 id="step-5---using-multiple-tools">Step 5 - Using multiple tools</h2>
<p>For reference, I&rsquo;m adapting the <a href="https://docs.anthropic.com/en/docs/tool-use-examples#multiple-tools">Anthropic AI Tool examples</a> from their documentation to the Bedrock Converse API.</p>
<p>In the previous example, we only used one tool to fetch the weather information. However, we can use multiple tools in a single conversation.</p>
<p>Let&rsquo;s add another tool to the conversation to fetch the current time and introduce a loop to handle multiple tool requests.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">  1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln">  2</span><span class="cl">
</span></span><span class="line"><span class="ln">  3</span><span class="cl"><span class="k">def</span> <span class="nf">get_weather</span><span class="p">(</span><span class="n">location</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">unit</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&#34;fahrenheit&#34;</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">  4</span><span class="cl">    <span class="k">return</span> <span class="p">{</span><span class="s2">&#34;temperature&#34;</span><span class="p">:</span> <span class="s2">&#34;78&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="ln">  5</span><span class="cl">
</span></span><span class="line"><span class="ln">  6</span><span class="cl"><span class="k">def</span> <span class="nf">get_time</span><span class="p">(</span><span class="n">timezone</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">  7</span><span class="cl">    <span class="k">return</span> <span class="s2">&#34;12:00PM&#34;</span>
</span></span><span class="line"><span class="ln">  8</span><span class="cl">
</span></span><span class="line"><span class="ln">  9</span><span class="cl"><span class="k">def</span> <span class="nf">tool_router</span><span class="p">(</span><span class="n">tool_name</span><span class="p">,</span> <span class="nb">input</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 10</span><span class="cl">    <span class="k">match</span> <span class="n">tool_name</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 11</span><span class="cl">        <span class="k">case</span> <span class="s2">&#34;get_weather&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 12</span><span class="cl">            <span class="k">return</span> <span class="n">get_weather</span><span class="p">(</span><span class="nb">input</span><span class="p">[</span><span class="s2">&#34;location&#34;</span><span class="p">],</span> <span class="nb">input</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;unit&#34;</span><span class="p">,</span> <span class="s2">&#34;fahrenheit&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="ln"> 13</span><span class="cl">        <span class="k">case</span> <span class="s2">&#34;get_time&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 14</span><span class="cl">            <span class="k">return</span> <span class="n">get_time</span><span class="p">(</span><span class="nb">input</span><span class="p">[</span><span class="s2">&#34;timezone&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="ln"> 15</span><span class="cl">        <span class="k">case</span> <span class="n">_</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 16</span><span class="cl">            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Unknown tool: </span><span class="si">{</span><span class="n">tool_name</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 17</span><span class="cl">
</span></span><span class="line"><span class="ln"> 18</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 19</span><span class="cl">
</span></span><span class="line"><span class="ln"> 20</span><span class="cl"><span class="n">tools</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 21</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 22</span><span class="cl">        <span class="s2">&#34;toolSpec&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 23</span><span class="cl">            <span class="s2">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;get_weather&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 24</span><span class="cl">            <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Get the current weather in a given location&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 25</span><span class="cl">            <span class="s2">&#34;inputSchema&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 26</span><span class="cl">                <span class="s2">&#34;json&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 27</span><span class="cl">                    <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 28</span><span class="cl">                    <span class="s2">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 29</span><span class="cl">                        <span class="s2">&#34;location&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 30</span><span class="cl">                            <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 31</span><span class="cl">                            <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The city and state, e.g. San Francisco, CA&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 32</span><span class="cl">                        <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 33</span><span class="cl">                        <span class="s2">&#34;unit&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 34</span><span class="cl">                            <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 35</span><span class="cl">                            <span class="s2">&#34;enum&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;celsius&#34;</span><span class="p">,</span> <span class="s2">&#34;fahrenheit&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln"> 36</span><span class="cl">                            <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The unit of temperature, either &#39;celsius&#39; or &#39;fahrenheit&#39;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 37</span><span class="cl">                        <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 38</span><span class="cl">                    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 39</span><span class="cl">                    <span class="s2">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;location&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln"> 40</span><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 41</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 42</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 43</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 44</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 45</span><span class="cl">        <span class="s2">&#34;toolSpec&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 46</span><span class="cl">            <span class="s2">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;get_time&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 47</span><span class="cl">            <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Get the current time in a given timezone&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 48</span><span class="cl">            <span class="s2">&#34;inputSchema&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 49</span><span class="cl">                <span class="s2">&#34;json&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 50</span><span class="cl">                    <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 51</span><span class="cl">                    <span class="s2">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 52</span><span class="cl">                        <span class="s2">&#34;timezone&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 53</span><span class="cl">                            <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 54</span><span class="cl">                            <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The IANA time zone name, e.g. America/Los_Angeles&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 55</span><span class="cl">                        <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 56</span><span class="cl">                    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 57</span><span class="cl">                    <span class="s2">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;timezone&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln"> 58</span><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 59</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 60</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 61</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 62</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 63</span><span class="cl"><span class="n">messages</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 64</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 65</span><span class="cl">        <span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 66</span><span class="cl">        <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 67</span><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 68</span><span class="cl">                <span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;What is the weather like right now in New York and what time is it there?&#34;</span>
</span></span><span class="line"><span class="ln"> 69</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 70</span><span class="cl">        <span class="p">],</span>
</span></span><span class="line"><span class="ln"> 71</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 72</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 73</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">converse</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 74</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-3-haiku-20240307-v1:0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 75</span><span class="cl">    <span class="n">messages</span><span class="o">=</span><span class="n">messages</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 76</span><span class="cl">    <span class="n">toolConfig</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;tools&#34;</span><span class="p">:</span> <span class="n">tools</span><span class="p">},</span>
</span></span><span class="line"><span class="ln"> 77</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 78</span><span class="cl">
</span></span><span class="line"><span class="ln"> 79</span><span class="cl"><span class="n">ai_message</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;output&#34;</span><span class="p">][</span><span class="s2">&#34;message&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 80</span><span class="cl"><span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ai_message</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 81</span><span class="cl">
</span></span><span class="line"><span class="ln"> 82</span><span class="cl"><span class="n">tool_use_count</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="ln"> 83</span><span class="cl"><span class="k">while</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;stopReason&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;tool_use&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 84</span><span class="cl">    <span class="k">if</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;stopReason&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;tool_use&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 85</span><span class="cl">        <span class="n">contents</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;output&#34;</span><span class="p">][</span><span class="s2">&#34;message&#34;</span><span class="p">][</span><span class="s2">&#34;content&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 86</span><span class="cl">        <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">contents</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 87</span><span class="cl">            <span class="k">if</span> <span class="s2">&#34;toolUse&#34;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 88</span><span class="cl">                <span class="k">continue</span>
</span></span><span class="line"><span class="ln"> 89</span><span class="cl">
</span></span><span class="line"><span class="ln"> 90</span><span class="cl">            <span class="n">tool_use</span> <span class="o">=</span> <span class="n">c</span><span class="p">[</span><span class="s2">&#34;toolUse&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 91</span><span class="cl">            <span class="n">tool_id</span> <span class="o">=</span> <span class="n">tool_use</span><span class="p">[</span><span class="s2">&#34;toolUseId&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 92</span><span class="cl">            <span class="n">tool_name</span> <span class="o">=</span> <span class="n">tool_use</span><span class="p">[</span><span class="s2">&#34;name&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 93</span><span class="cl">            <span class="nb">input</span> <span class="o">=</span> <span class="n">tool_use</span><span class="p">[</span><span class="s2">&#34;input&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 94</span><span class="cl">
</span></span><span class="line"><span class="ln"> 95</span><span class="cl">            <span class="n">tool_result</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;toolUseId&#34;</span><span class="p">:</span> <span class="n">tool_id</span><span class="p">}</span>
</span></span><span class="line"><span class="ln"> 96</span><span class="cl">            <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 97</span><span class="cl">                <span class="n">output</span> <span class="o">=</span> <span class="n">tool_router</span><span class="p">(</span><span class="n">tool_name</span><span class="p">,</span> <span class="nb">input</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 98</span><span class="cl">                <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">output</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 99</span><span class="cl">                    <span class="n">tool_result</span><span class="p">[</span><span class="s2">&#34;content&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[{</span><span class="s2">&#34;json&#34;</span><span class="p">:</span> <span class="n">output</span><span class="p">}]</span>
</span></span><span class="line"><span class="ln">100</span><span class="cl">                <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">output</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">101</span><span class="cl">                    <span class="n">tool_result</span><span class="p">[</span><span class="s2">&#34;content&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[{</span><span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="n">output</span><span class="p">}]</span>
</span></span><span class="line"><span class="ln">102</span><span class="cl">                <span class="c1"># Add more cases such as images if needed</span>
</span></span><span class="line"><span class="ln">103</span><span class="cl">                <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">104</span><span class="cl">                    <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Unsupported output type: </span><span class="si">{</span><span class="nb">type</span><span class="p">(</span><span class="n">output</span><span class="p">)</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">105</span><span class="cl">            <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">106</span><span class="cl">                <span class="n">tool_result</span><span class="p">[</span><span class="s2">&#34;content&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">107</span><span class="cl">                    <span class="p">{</span><span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&#34;An unknown error occurred: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="ln">108</span><span class="cl">                <span class="p">]</span>
</span></span><span class="line"><span class="ln">109</span><span class="cl">                <span class="n">tool_result</span><span class="p">[</span><span class="s2">&#34;status&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;error&#34;</span>
</span></span><span class="line"><span class="ln">110</span><span class="cl">
</span></span><span class="line"><span class="ln">111</span><span class="cl">            <span class="n">message</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&#34;toolResult&#34;</span><span class="p">:</span> <span class="n">tool_result</span><span class="p">}]}</span>
</span></span><span class="line"><span class="ln">112</span><span class="cl">            <span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">113</span><span class="cl">
</span></span><span class="line"><span class="ln">114</span><span class="cl">        <span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">converse</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">115</span><span class="cl">            <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-3-haiku-20240307-v1:0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">116</span><span class="cl">            <span class="n">messages</span><span class="o">=</span><span class="n">messages</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">117</span><span class="cl">            <span class="n">toolConfig</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;tools&#34;</span><span class="p">:</span> <span class="n">tools</span><span class="p">},</span>
</span></span><span class="line"><span class="ln">118</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">119</span><span class="cl">        <span class="n">ai_message</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;output&#34;</span><span class="p">][</span><span class="s2">&#34;message&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">120</span><span class="cl">        <span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ai_message</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">121</span><span class="cl">        <span class="n">tool_use_count</span> <span class="o">+=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="ln">122</span><span class="cl">
</span></span><span class="line"><span class="ln">123</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">tool_use_count</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">124</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="p">[</span><span class="s2">&#34;output&#34;</span><span class="p">])</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;message&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="nt">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;assistant&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="nt">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;The current time in New York is 12:00 PM.\n\nSo in summary, the weather in New York right now is 78 degrees Celsius, and the time is 12:00 PM.&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Tool use count: <code>2</code></p>
<p>We have successfully responded to the AI&rsquo;s tool requests and provided the weather and time information for New York.</p>
<h2 id="conclusion">Conclusion</h2>
<p>In this post, we learned how to use the Amazon Bedrock Converse API to augment converations with AI models. Not only did we leverage text and images, but we also used tools to simulate fetching external data.</p>
<p>The Amazon Bedrock Converse API is a powerful tool that can be used to build conversational AI applications!</p>
]]></content:encoded></item><item><title>Multiple operations in a single DynamoDB update expression</title><link>https://how.wtf/multiple-operations-in-a-single-dynamodb-update-expression.html</link><pubDate>Sun, 28 Apr 2024 13:10:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/multiple-operations-in-a-single-dynamodb-update-expression.html</guid><description>DynamoDB supports an UpdateItem operation that modifies an existing or creates a new item. The UpdateItem accepts an UpdateExpression that dictates which operations will occur on the specified item.
In this post, we&amp;rsquo;ll explore how to perform multiple operations including within a clause/keyword and with multiple clauses/keywords.
What is an update expression An update expression supports four keywords:
SET (modify or add item attributes) REMOVE (deleting attributes from an item) ADD (updating numbers and sets) DELETE (removing elements from a set) The syntax for an update expression is as follows:</description><content:encoded><![CDATA[<p>DynamoDB supports an <code>UpdateItem</code> operation that modifies an existing or creates a new item. The <code>UpdateItem</code> accepts an <code>UpdateExpression</code> that dictates which operations will occur on the specified item.</p>
<p>In this post, we&rsquo;ll explore how to perform multiple operations including within a clause/keyword and with multiple clauses/keywords.</p>
<h2 id="what-is-an-update-expression">What is an update expression</h2>
<p>An update expression supports four keywords:</p>
<ol>
<li><code>SET</code> (modify or add item attributes)</li>
<li><code>REMOVE</code> (deleting attributes from an item)</li>
<li><code>ADD</code> (updating numbers and sets)</li>
<li><code>DELETE</code> (removing elements from a set)</li>
</ol>
<p>The syntax for an update expression is as follows:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">update-expression ::=
</span></span><span class="line"><span class="ln">2</span><span class="cl">    [ SET action [, action] ... ]
</span></span><span class="line"><span class="ln">3</span><span class="cl">    [ REMOVE action [, action] ...]
</span></span><span class="line"><span class="ln">4</span><span class="cl">    [ ADD action [, action] ... ]
</span></span><span class="line"><span class="ln">5</span><span class="cl">    [ DELETE action [, action] ...]</span></span></code></pre></div><p>As you can view, DynamoDB supports four main clauses that begin with one of the specified operations.</p>
<p>For a detailed explanation of update expressions, <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html">please refer to the AWS documentation</a>.</p>
<p>For demonstration purposes, I&rsquo;m going to create a DynamoDB table named <code>books</code> with a number hash key named <code>id</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb create-table <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --table-name books <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --attribute-definitions <span class="nv">AttributeName</span><span class="o">=</span>id,AttributeType<span class="o">=</span>N <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>  --key-schema <span class="nv">AttributeName</span><span class="o">=</span>id,KeyType<span class="o">=</span>HASH <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>  --provisioned-throughput <span class="nv">ReadCapacityUnits</span><span class="o">=</span>5,WriteCapacityUnits<span class="o">=</span><span class="m">5</span></span></span></code></pre></div><p>I&rsquo;ll also add an item to the table:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="nt">&#34;N&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">  <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;Iliad&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">  <span class="nt">&#34;author&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;Homer&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="nt">&#34;genre&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;Epic Poetry&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">  <span class="nt">&#34;publication_year&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="nt">&#34;N&#34;</span><span class="p">:</span> <span class="s2">&#34;1488&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb put-item <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name books <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --item file://book.json</span></span></code></pre></div><h2 id="how-to-specify-a-single-keyword-in-dynamodb-update-expression">How to specify a single keyword in DynamoDB update expression</h2>
<p>Let&rsquo;s showcase a basic use-case of adding an element to an existing item:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb update-item <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name books <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --key <span class="s1">&#39;{&#34;id&#34;:{&#34;N&#34;:&#34;1&#34;}}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>    --update-expression <span class="s2">&#34;SET category = :c&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>    --expression-attribute-values <span class="s1">&#39;{&#34;:c&#34;:{&#34;S&#34;:&#34;Poem&#34;}}&#39;</span></span></span></code></pre></div><p>Now the item has a new <code>category</code> attribute:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb get-item <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name books <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --key <span class="s1">&#39;{&#34;id&#34;:{&#34;N&#34;:&#34;1&#34;}}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>    --projection-expression <span class="s2">&#34;category&#34;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;Item&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nt">&#34;category&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">      <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;Poem&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="how-to-specify-a-single-keyword-with-multiple-actions-in-dynamodb-update-expression">How to specify a single keyword with multiple actions in DynamoDB update expression</h2>
<p>To showcase mutliple <code>SET</code> operations in a single DynamoDB update expression, we&rsquo;ll use a comma (<code>,</code>) to separate them.</p>
<p>In the following example, we&rsquo;re changing the <code>category</code> from <code>poem</code> -&gt; <code>poetry</code> and adding a new element named <code>genre</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb update-item <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name books <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --key <span class="s1">&#39;{&#34;id&#34;:{&#34;N&#34;:&#34;1&#34;}}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>    --update-expression <span class="s2">&#34;SET category = :c, genre = :g&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>    --expression-attribute-values <span class="s1">&#39;{&#34;:c&#34;:{&#34;S&#34;:&#34;poetry&#34;}, &#34;:g&#34;:{&#34;S&#34;:&#34;Epic poetry&#34;}}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="se"></span>    --return-values UPDATED_NEW</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;Attributes&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="nt">&#34;category&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">      <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;poetry&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="nt">&#34;genre&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">      <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;Epic poetry&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>As you see, the <code>update-expression</code> includes a comma between the two operations:</p>
<p><code>SET category = :c, genre = :g</code></p>
<h2 id="how-to-specify-multiple-keywords-with-multiple-actios-in-dynamodb-update-expression">How to specify multiple keywords with multiple actios in DynamoDB update expression</h2>
<p>Lastly, let&rsquo;s showcase leveraging <em>multiple</em> keywords with their respective actions.</p>
<p>We&rsquo;re going to perform the following:</p>
<ol>
<li>Set a new string attribute named <code>product_category</code> with a value of <code>poem</code></li>
<li>Remove the <code>category</code> attribute</li>
<li>Add <code>1</code> to existing <code>checkout_total</code> number or initialize it with the number value of <code>1</code></li>
<li>Add <code>Trojan War</code> to existing <code>subjects</code> set or initialize it with the first index being string value of <code>Trojan War</code></li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb update-item <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name books <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --key <span class="s1">&#39;{&#34;id&#34;:{&#34;N&#34;:&#34;1&#34;}}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>    --update-expression <span class="s2">&#34;SET #pc = :pc REMOVE #c ADD #ct :inc, #s :s&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>    --expression-attribute-names <span class="s1">&#39;{&#34;#s&#34;:&#34;subjects&#34;,&#34;#pc&#34;:&#34;product_category&#34;,&#34;#c&#34;:&#34;category&#34;,&#34;#ct&#34;:&#34;checkout_total&#34;}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="se"></span>    --expression-attribute-values <span class="s1">&#39;{&#34;:s&#34;:{&#34;SS&#34;:[&#34;Trojan War&#34;]},&#34;:pc&#34;:{&#34;S&#34;:&#34;poem&#34;},&#34;:inc&#34;:{&#34;N&#34;:&#34;1&#34;}}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="se"></span>    --return-values UPDATED_NEW</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;Attributes&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="nt">&#34;checkout_total&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">      <span class="nt">&#34;N&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="nt">&#34;subjects&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">      <span class="nt">&#34;SS&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="s2">&#34;Trojan War&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="nt">&#34;product_category&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">      <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;poem&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>It&rsquo;s important to note that because the <code>ADD</code> operation will continue incrementing and the <code>SET</code> data structure doesn&rsquo;t allow duplicates, we can rerun the same operation and <code>checkout_total</code> will increase by <code>1</code>.</p>
<p>For readability, let&rsquo;s substitute the <code>expression-attribute-names</code> and <code>expression-attribute-values</code> back into the <code>update-expression</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">SET product_category = poem REMOVE category ADD checkout_total 1, subjects [&#34;Trojan War&#34;]</span></span></code></pre></div><p>To summarize, using mutliple clauses in a DynamoDB <code>UpdateExpression</code> is supported by simply separating the clauses by keywords.</p>
<p>If you want to perform multiple operations using the same clause, use a comma (<code>,</code>) to separate them.</p>
]]></content:encoded></item><item><title>Detecting and redacting PII using Amazon Bedrock</title><link>https://how.wtf/detecting-and-redacting-pii-using-amazon-bedrock.html</link><pubDate>Tue, 23 Apr 2024 00:25:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/detecting-and-redacting-pii-using-amazon-bedrock.html</guid><description>Typically, AWS recommends leveraging an existing service offering such as Amazon Comprehend to detect and redact PII. However, this post explores an alternative solution using Amazon Bedrock.
This is possible using the Claude, Anthropic&amp;rsquo;s large langauge model, and their publicly available prompt library. In our case, we&amp;rsquo;ll leverage the PII purifier prompt that is maintained by their prompt engineers.
How to extract PII using Amazon Bedrock in Python This demo showcases how to invoke the Amazon Claude 3 models using Python; however, any language and their respective Amazon SDK will suffice.</description><content:encoded><![CDATA[<p>Typically, AWS recommends <a href="https://docs.aws.amazon.com/comprehend/latest/dg/how-pii.html">leveraging an existing service offering such as Amazon Comprehend</a> to detect and redact PII. However, this post explores an alternative solution using Amazon Bedrock.</p>
<p>This is possible using the Claude, Anthropic&rsquo;s large langauge model, and <a href="https://docs.anthropic.com/claude/prompt-library">their publicly available prompt library</a>. In our case, we&rsquo;ll <a href="https://docs.anthropic.com/claude/page/pii-purifier">leverage the PII purifier prompt</a> that is maintained by their prompt engineers.</p>
<h2 id="how-to-extract-pii-using-amazon-bedrock-in-python">How to extract PII using Amazon Bedrock in Python</h2>
<p>This demo showcases how to invoke the Amazon Claude 3 models using Python; however, any language and their respective Amazon SDK will suffice.</p>
<h3 id="install-boto3">Install boto3</h3>
<p>Firstly, let&rsquo;s install the AWS Python SDK, <code>boto3</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install boto3</span></span></code></pre></div><h3 id="instantiate-a-client">Instantiate a client</h3>
<p>Ensure that your environment is authenticated with AWS credentials using any of the <a href="https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html#configuring-credentials">methods described in their documentation</a>.</p>
<p>Instantiate the bedrock runtime client like so:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">bedrock_runtime</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span></span></span></code></pre></div><h3 id="invoke-the-claude-model">Invoke the Claude model</h3>
<p>We can reference the required parameters for the Claude 3 model using the <a href="https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters.html">&ldquo;Inference parameters for foundation models&rdquo; documentation provided by AWS</a>.</p>
<p>In Claude 3&rsquo;s case, the Messages API will be used like so:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">bedrock_runtime</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">bedrock_runtime</span><span class="o">.</span><span class="n">invoke_model</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">body</span><span class="o">=</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">            <span class="s2">&#34;anthropic_version&#34;</span><span class="p">:</span> <span class="s2">&#34;bedrock-2023-05-31&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            <span class="s2">&#34;max_tokens&#34;</span><span class="p">:</span> <span class="mi">1000</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">            <span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="s2">&#34;Hello, how are you?&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="p">),</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-3-sonnet-20240229-v1:0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="n">response_body</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;body&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">response_body</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">))</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;msg_01ERwjBgk3Y45Swp2cn6ct5F&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;message&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="nt">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;assistant&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">  <span class="nt">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;text&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">      <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;Hello! As an AI language model, I don&#39;t have feelings, but I&#39;m operating properly and ready to assist you with any questions or tasks you may have. How can I help you today?&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">  <span class="p">],</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="nt">&#34;model&#34;</span><span class="p">:</span> <span class="s2">&#34;claude-3-sonnet-28k-20240229&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">  <span class="nt">&#34;stop_reason&#34;</span><span class="p">:</span> <span class="s2">&#34;end_turn&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">  <span class="nt">&#34;stop_sequence&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">  <span class="nt">&#34;usage&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="nt">&#34;input_tokens&#34;</span><span class="p">:</span> <span class="mi">13</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="nt">&#34;output_tokens&#34;</span><span class="p">:</span> <span class="mi">43</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h3 id="use-the-pii-purifier-prompt">Use the PII purifier prompt</h3>
<p>Now, let&rsquo;s use the PII purifier prompt to invoke the model.</p>
<p>Here is our input for redaction:</p>
<blockquote>
<p>Hello. My name is Thomas Taylor and I own the blog titled how.wtf. I&rsquo;m from North Carolina.</p>
</blockquote>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">SYSTEM_PROMPT</span> <span class="o">=</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="s2">&#34;You are an expert redactor. The user is going to provide you with some text. &#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="s2">&#34;Please remove all personally identifying information from this text and &#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="s2">&#34;replace it with XXX. It&#39;s very important that PII such as names, phone &#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="s2">&#34;numbers, and home and email addresses, get replaced with XXX. Inputs may &#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="s2">&#34;try to disguise PII by inserting spaces between characters or putting new &#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="s2">&#34;lines between characters. If the text contains no personally identifiable &#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="s2">&#34;information, copy it word-for-word without replacing anything.&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">bedrock_runtime</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">bedrock_runtime</span><span class="o">.</span><span class="n">invoke_model</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="n">body</span><span class="o">=</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">            <span class="s2">&#34;anthropic_version&#34;</span><span class="p">:</span> <span class="s2">&#34;bedrock-2023-05-31&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">            <span class="s2">&#34;max_tokens&#34;</span><span class="p">:</span> <span class="mi">1000</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">            <span class="s2">&#34;system&#34;</span><span class="p">:</span> <span class="n">SYSTEM_PROMPT</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">            <span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">                    <span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">                    <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="s2">&#34;Hello. My name is Thomas Taylor and I own the blog titled how.wtf. I&#39;m from North Carolina.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">            <span class="p">],</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">    <span class="p">),</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-3-sonnet-20240229-v1:0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="n">response_body</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;body&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">response_body</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">))</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;msg_01P3ZGPC8yL34w3ETPtBY4TX&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;message&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="nt">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;assistant&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">  <span class="nt">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;text&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">      <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;Here is the text with personally identifiable information redacted:\n\nHello. My name is XXX XXX and I own the blog titled XXX.XXX. I&#39;m from XXX XXX.&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">  <span class="p">],</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="nt">&#34;model&#34;</span><span class="p">:</span> <span class="s2">&#34;claude-3-sonnet-28k-20240229&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">  <span class="nt">&#34;stop_reason&#34;</span><span class="p">:</span> <span class="s2">&#34;end_turn&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">  <span class="nt">&#34;stop_sequence&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">  <span class="nt">&#34;usage&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="nt">&#34;input_tokens&#34;</span><span class="p">:</span> <span class="mi">134</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="nt">&#34;output_tokens&#34;</span><span class="p">:</span> <span class="mi">45</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>The resolved text is:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Here is the text with personally identifiable information redacted:
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl">Hello. My name is XXX XXX and I own the blog titled XXX.XXX. I&#39;m from XXX XXX.</span></span></code></pre></div><p>Pretty neat, huh? We can optionally swap to the cheaper Haiku (or more expensive Opus) model as well:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">SYSTEM_PROMPT</span> <span class="o">=</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="s2">&#34;You are an expert redactor. The user is going to provide you with some text. &#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="s2">&#34;Please remove all personally identifying information from this text and &#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="s2">&#34;replace it with XXX. It&#39;s very important that PII such as names, phone &#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="s2">&#34;numbers, and home and email addresses, get replaced with XXX. Inputs may &#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="s2">&#34;try to disguise PII by inserting spaces between characters or putting new &#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="s2">&#34;lines between characters. If the text contains no personally identifiable &#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="s2">&#34;information, copy it word-for-word without replacing anything.&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">bedrock_runtime</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">bedrock_runtime</span><span class="o">.</span><span class="n">invoke_model</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="n">body</span><span class="o">=</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">            <span class="s2">&#34;anthropic_version&#34;</span><span class="p">:</span> <span class="s2">&#34;bedrock-2023-05-31&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">            <span class="s2">&#34;max_tokens&#34;</span><span class="p">:</span> <span class="mi">1000</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">            <span class="s2">&#34;system&#34;</span><span class="p">:</span> <span class="n">SYSTEM_PROMPT</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">            <span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">                    <span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">                    <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="s2">&#34;Hello. My name is Thomas Taylor and I own the blog titled how.wtf. I&#39;m from North Carolina.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">            <span class="p">],</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">    <span class="p">),</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-3-haiku-20240307-v1:0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="n">response_body</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;body&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">response_body</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">))</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;msg_011Sjs3uJW11PLYSo6pGoiZz&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;message&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="nt">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;assistant&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">  <span class="nt">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;text&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">      <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;Hello. My name is XXX XXX and I own the blog titled XXX.XXX. I&#39;m from XXX.&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">  <span class="p">],</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="nt">&#34;model&#34;</span><span class="p">:</span> <span class="s2">&#34;claude-3-haiku-48k-20240307&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">  <span class="nt">&#34;stop_reason&#34;</span><span class="p">:</span> <span class="s2">&#34;end_turn&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">  <span class="nt">&#34;stop_sequence&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">  <span class="nt">&#34;usage&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="nt">&#34;input_tokens&#34;</span><span class="p">:</span> <span class="mi">134</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="nt">&#34;output_tokens&#34;</span><span class="p">:</span> <span class="mi">30</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="conclusion">Conclusion</h2>
<p>In this post, we covered an alternative method for detecting and redacting PII using Amazon Bedrock and the powerful Anthropic Claude 3 model family.</p>
<p>I encourage you to experiment with this demo and explore further enhancements.</p>
]]></content:encoded></item><item><title>Anthropic Claude with tools using Python SDK</title><link>https://how.wtf/anthropic-claude-with-tools-using-python-sdk.html</link><pubDate>Sun, 21 Apr 2024 01:35:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/anthropic-claude-with-tools-using-python-sdk.html</guid><description>On April 4th, 2024, Anthropic released official support for tool use through their API. This feature allows developers to define one or more tools that include parameters, descriptions, and schema definitions for Claude to process.
In this post, we&amp;rsquo;ll go over how to leverage these tools using the Python Anthropic SDK.
Claude with tools example in Python Firstly, ensure that your Anthropic API key is available as an environment variable in your shell:</description><content:encoded><![CDATA[<p>On April 4th, 2024, Anthropic released <a href="https://docs.anthropic.com/claude/docs/tool-use">official support for tool use</a> through their API. This feature allows developers to define one or more tools that include parameters, descriptions, and schema definitions for Claude to process.</p>
<p>In this post, we&rsquo;ll go over how to leverage these tools using the Python Anthropic SDK.</p>
<h2 id="claude-with-tools-example-in-python">Claude with tools example in Python</h2>
<p>Firstly, ensure that your Anthropic API key is available as an environment variable in your shell:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">export</span> <span class="nv">ANTHROPIC_API_KEY</span><span class="o">=</span><span class="s2">&#34;sk-......&#34;</span></span></span></code></pre></div><h3 id="install-the-anthropic-sdk">Install the Anthropic SDK</h3>
<p>Next, install the latest version of the Anthropic SDK using <code>pip</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install anthropic</span></span></code></pre></div><h3 id="define-the-tools">Define the tools</h3>
<p>Using the provided <a href="https://docs.anthropic.com/claude/docs/tool-use#best-practices-for-tool-definitions">JSON schema example in the Anthropic documentation</a>, let&rsquo;s define a <code>get_current_stock_price</code> tool:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;get_current_stock_price&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Retrieves the current stock price for a given ticker symbol. The ticker symbol must be a valid symbol for a publicly traded company on a major US stock exchange like NYSE or NASDAQ. The tool will return the latest trade price in USD. It should be used when the user asks about the current or most recent price of a specific stock. It will not provide any other information about the stock or company.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="nt">&#34;input_schema&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="nt">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">      <span class="nt">&#34;ticker&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The stock ticker symbol, e.g. AAPL for Apple Inc.&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="nt">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;ticker&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>In Python,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">anthropic</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">tools</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="s2">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;get_current_stock_price&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Retrieves the current stock price for a given ticker symbol. The ticker symbol must be a valid symbol for a publicly traded company on a major US stock exchange like NYSE or NASDAQ. The tool will return the latest trade price in USD. It should be used when the user asks about the current or most recent price of a specific stock. It will not provide any other information about the stock or company.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="s2">&#34;input_schema&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">            <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            <span class="s2">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">                <span class="s2">&#34;symbol&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">                    <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">                    <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The stock ticker symbol, e.g. AAPL for Apple Inc.&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="s2">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;symbol&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="p">]</span></span></span></code></pre></div><h3 id="instantiate-a-client">Instantiate a client</h3>
<p>To invoke Claude, we need to instantiate a client. The SDK uses the <code>ANTHROPIC_API_KEY</code> environment variable by default for authentication.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">anthropic</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">anthropic</span><span class="o">.</span><span class="n">Anthropic</span><span class="p">()</span></span></span></code></pre></div><h3 id="invoke-claude-with-tools">Invoke Claude with tools</h3>
<p>Now, let&rsquo;s create a new message using Claude and the tools:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">anthropic</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">tools</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="s2">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;get_current_stock_price&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Retrieves the current stock price for a given ticker symbol. The ticker symbol must be a valid symbol for a publicly traded company on a major US stock exchange like NYSE or NASDAQ. The tool will return the latest trade price in USD. It should be used when the user asks about the current or most recent price of a specific stock. It will not provide any other information about the stock or company.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="s2">&#34;input_schema&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">            <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            <span class="s2">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">                <span class="s2">&#34;symbol&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">                    <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">                    <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The stock ticker symbol, e.g. AAPL for Apple Inc.&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="s2">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;symbol&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">anthropic</span><span class="o">.</span><span class="n">Anthropic</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">beta</span><span class="o">.</span><span class="n">tools</span><span class="o">.</span><span class="n">messages</span><span class="o">.</span><span class="n">create</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">    <span class="n">model</span><span class="o">=</span><span class="s2">&#34;claude-3-haiku-20240307&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">    <span class="n">max_tokens</span><span class="o">=</span><span class="mi">1024</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="n">tools</span><span class="o">=</span><span class="n">tools</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">    <span class="n">messages</span><span class="o">=</span><span class="p">[</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">            <span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">            <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="s2">&#34;What is the stock price of Apple?&#34;</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">
</span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">ToolsBetaMessage(id=&#39;msg_01Bedxru94A4Pe1sHgWtymSJ&#39;, content=[ToolUseBlock(id=&#39;toolu_01CbGgyko9mdkKSDPw6LsTvV&#39;, input={&#39;symbol&#39;: &#39;AAPL&#39;}, name=&#39;get_current_stock_price&#39;, type=&#39;tool_use&#39;)], model=&#39;claude-3-haiku-20240307&#39;, role=&#39;assistant&#39;, stop_reason=&#39;tool_use&#39;, stop_sequence=None, type=&#39;message&#39;, usage=Usage(input_tokens=433, output_tokens=60))</span></span></code></pre></div><p>The output includes a <code>ToolUseBlock</code> with the input for the tool. We now need to process the tool and return the result to Claude.</p>
<h3 id="building-a-tool-router">Building a tool router</h3>
<p>Let&rsquo;s build a mock function that returns <code>150.0</code> for the stock price:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">def</span> <span class="nf">get_current_stock_price</span><span class="p">(</span><span class="n">symbol</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="c1"># Fake implementation for demonstration purposes</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="k">return</span> <span class="mf">150.0</span></span></span></code></pre></div><p>And then a &ldquo;router&rdquo; function that accepts the tool name and input:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">def</span> <span class="nf">process_tool</span><span class="p">(</span><span class="n">tool_name</span><span class="p">,</span> <span class="nb">input</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="k">match</span> <span class="n">tool_name</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="k">case</span> <span class="s2">&#34;get_current_stock_price&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">            <span class="k">return</span> <span class="n">get_current_stock_price</span><span class="p">(</span><span class="nb">input</span><span class="p">[</span><span class="s2">&#34;symbol&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">        <span class="k">case</span> <span class="n">_</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Unknown tool: </span><span class="si">{</span><span class="n">tool_name</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span></span></span></code></pre></div><h3 id="responding-with-a-tool-result-example">Responding with a tool result example</h3>
<p>Anthropic provides a <a href="https://github.com/anthropics/anthropic-cookbook/blob/main/tool_use/customer_service_agent.ipynb">Jupyter notebook that showcases a customer service example using tools</a>. We&rsquo;ll adapt some of the functionality to our script:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">while</span> <span class="n">response</span><span class="o">.</span><span class="n">stop_reason</span> <span class="o">==</span> <span class="s2">&#34;tool_use&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="n">tool_use</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">block</span> <span class="k">for</span> <span class="n">block</span> <span class="ow">in</span> <span class="n">response</span><span class="o">.</span><span class="n">content</span> <span class="k">if</span> <span class="n">block</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="s2">&#34;tool_use&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="n">tool_name</span> <span class="o">=</span> <span class="n">tool_use</span><span class="o">.</span><span class="n">name</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="n">tool_input</span> <span class="o">=</span> <span class="n">tool_use</span><span class="o">.</span><span class="n">input</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="n">tool_result</span> <span class="o">=</span> <span class="n">process_tool</span><span class="p">(</span><span class="n">tool_name</span><span class="p">,</span> <span class="n">tool_input</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">messages</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="p">{</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="n">user_message</span><span class="p">},</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="p">{</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;assistant&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="n">response</span><span class="o">.</span><span class="n">content</span><span class="p">},</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">            <span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">            <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">                    <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;tool_result&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">                    <span class="s2">&#34;tool_use_id&#34;</span><span class="p">:</span> <span class="n">tool_use</span><span class="o">.</span><span class="n">id</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">                    <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">tool_result</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">            <span class="p">],</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl">    <span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">beta</span><span class="o">.</span><span class="n">tools</span><span class="o">.</span><span class="n">messages</span><span class="o">.</span><span class="n">create</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">        <span class="n">model</span><span class="o">=</span><span class="n">model</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">        <span class="n">max_tokens</span><span class="o">=</span><span class="mi">4096</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">        <span class="n">tools</span><span class="o">=</span><span class="n">tools</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">        <span class="n">messages</span><span class="o">=</span><span class="n">messages</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="n">final_response</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">    <span class="p">(</span><span class="n">block</span><span class="o">.</span><span class="n">text</span> <span class="k">for</span> <span class="n">block</span> <span class="ow">in</span> <span class="n">response</span><span class="o">.</span><span class="n">content</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">block</span><span class="p">,</span> <span class="n">TextBlock</span><span class="p">)),</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">    <span class="kc">None</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="p">)</span></span></span></code></pre></div><p>The code does the following:</p>
<ol>
<li>Loop while the response is <code>tool_use</code></li>
<li>Extracts the current tool&rsquo;s name and input</li>
<li>Processes the tool by calling the router function</li>
<li>Creates a new Claude message using the prior messages and the tool result</li>
<li>Retrieves the final response from Claude and returns the text</li>
</ol>
<h3 id="putting-it-altogether">Putting it altogether</h3>
<p>Here&rsquo;s the resulting code:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">anthropic</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">anthropic.types</span> <span class="kn">import</span> <span class="n">TextBlock</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">anthropic</span><span class="o">.</span><span class="n">Anthropic</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="k">def</span> <span class="nf">talk</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">tools</span><span class="p">,</span> <span class="n">model</span><span class="p">,</span> <span class="n">user_message</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">beta</span><span class="o">.</span><span class="n">tools</span><span class="o">.</span><span class="n">messages</span><span class="o">.</span><span class="n">create</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="n">model</span><span class="o">=</span><span class="n">model</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="n">max_tokens</span><span class="o">=</span><span class="mi">1024</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="n">tools</span><span class="o">=</span><span class="n">tools</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="n">messages</span><span class="o">=</span><span class="p">[{</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="n">user_message</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="k">while</span> <span class="n">response</span><span class="o">.</span><span class="n">stop_reason</span> <span class="o">==</span> <span class="s2">&#34;tool_use&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="n">tool_use</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">block</span> <span class="k">for</span> <span class="n">block</span> <span class="ow">in</span> <span class="n">response</span><span class="o">.</span><span class="n">content</span> <span class="k">if</span> <span class="n">block</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="s2">&#34;tool_use&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="n">tool_name</span> <span class="o">=</span> <span class="n">tool_use</span><span class="o">.</span><span class="n">name</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">        <span class="n">tool_input</span> <span class="o">=</span> <span class="n">tool_use</span><span class="o">.</span><span class="n">input</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">        <span class="n">tool_result</span> <span class="o">=</span> <span class="n">process_tool</span><span class="p">(</span><span class="n">tool_name</span><span class="p">,</span> <span class="n">tool_input</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl">        <span class="n">messages</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">            <span class="p">{</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="n">user_message</span><span class="p">},</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">            <span class="p">{</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;assistant&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="n">response</span><span class="o">.</span><span class="n">content</span><span class="p">},</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">                <span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">                <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">                    <span class="p">{</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">                        <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;tool_result&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">                        <span class="s2">&#34;tool_use_id&#34;</span><span class="p">:</span> <span class="n">tool_use</span><span class="o">.</span><span class="n">id</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">                        <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">tool_result</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">                    <span class="p">}</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">                <span class="p">],</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">
</span></span><span class="line"><span class="ln">36</span><span class="cl">        <span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">beta</span><span class="o">.</span><span class="n">tools</span><span class="o">.</span><span class="n">messages</span><span class="o">.</span><span class="n">create</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">            <span class="n">model</span><span class="o">=</span><span class="n">model</span><span class="p">,</span> <span class="n">max_tokens</span><span class="o">=</span><span class="mi">4096</span><span class="p">,</span> <span class="n">tools</span><span class="o">=</span><span class="n">tools</span><span class="p">,</span> <span class="n">messages</span><span class="o">=</span><span class="n">messages</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl">
</span></span><span class="line"><span class="ln">40</span><span class="cl">    <span class="n">final_response</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">        <span class="p">(</span><span class="n">block</span><span class="o">.</span><span class="n">text</span> <span class="k">for</span> <span class="n">block</span> <span class="ow">in</span> <span class="n">response</span><span class="o">.</span><span class="n">content</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">block</span><span class="p">,</span> <span class="n">TextBlock</span><span class="p">)),</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl">        <span class="kc">None</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">43</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">44</span><span class="cl">
</span></span><span class="line"><span class="ln">45</span><span class="cl">    <span class="k">return</span> <span class="n">final_response</span>
</span></span><span class="line"><span class="ln">46</span><span class="cl">
</span></span><span class="line"><span class="ln">47</span><span class="cl">
</span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="k">def</span> <span class="nf">get_current_stock_price</span><span class="p">(</span><span class="n">symbol</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl">    <span class="c1"># Fake implementation for demonstration purposes</span>
</span></span><span class="line"><span class="ln">50</span><span class="cl">    <span class="k">return</span> <span class="mf">150.0</span>
</span></span><span class="line"><span class="ln">51</span><span class="cl">
</span></span><span class="line"><span class="ln">52</span><span class="cl">
</span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="k">def</span> <span class="nf">process_tool</span><span class="p">(</span><span class="n">tool_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="nb">input</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">54</span><span class="cl">    <span class="k">match</span> <span class="n">tool_name</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">55</span><span class="cl">        <span class="k">case</span> <span class="s2">&#34;get_current_stock_price&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">56</span><span class="cl">            <span class="k">return</span> <span class="n">get_current_stock_price</span><span class="p">(</span><span class="nb">input</span><span class="p">[</span><span class="s2">&#34;symbol&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">57</span><span class="cl">        <span class="k">case</span> <span class="n">_</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">58</span><span class="cl">            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Unknown tool: </span><span class="si">{</span><span class="n">tool_name</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">59</span><span class="cl">
</span></span><span class="line"><span class="ln">60</span><span class="cl">
</span></span><span class="line"><span class="ln">61</span><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">62</span><span class="cl">    <span class="n">client</span> <span class="o">=</span> <span class="n">anthropic</span><span class="o">.</span><span class="n">Anthropic</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">63</span><span class="cl">    <span class="n">tools</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">64</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln">65</span><span class="cl">            <span class="s2">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;get_current_stock_price&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">66</span><span class="cl">            <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Retrieves the current stock price for a given ticker symbol. The ticker symbol must be a valid symbol for a publicly traded company on a major US stock exchange like NYSE or NASDAQ. The tool will return the latest trade price in USD. It should be used when the user asks about the current or most recent price of a specific stock. It will not provide any other information about the stock or company.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">67</span><span class="cl">            <span class="s2">&#34;input_schema&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">68</span><span class="cl">                <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">69</span><span class="cl">                <span class="s2">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">70</span><span class="cl">                    <span class="s2">&#34;symbol&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">71</span><span class="cl">                        <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">72</span><span class="cl">                        <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The stock ticker symbol, e.g. AAPL for Apple Inc.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">73</span><span class="cl">                    <span class="p">}</span>
</span></span><span class="line"><span class="ln">74</span><span class="cl">                <span class="p">},</span>
</span></span><span class="line"><span class="ln">75</span><span class="cl">                <span class="s2">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;symbol&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">76</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">77</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">78</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">79</span><span class="cl">    <span class="n">response</span> <span class="o">=</span> <span class="n">talk</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">80</span><span class="cl">        <span class="n">client</span><span class="p">,</span> <span class="n">tools</span><span class="p">,</span> <span class="s2">&#34;claude-3-haiku-20240307&#34;</span><span class="p">,</span> <span class="s2">&#34;What is the price of Apple?&#34;</span>
</span></span><span class="line"><span class="ln">81</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">82</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="p">)</span></span></span></code></pre></div><p>Here is the output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">The current stock price for Apple (ticker symbol AAPL) is $150.00.</span></span></code></pre></div><h2 id="conclusion">Conclusion</h2>
<p>In this post, we covered:</p>
<ol>
<li>How to invoke Claude using tools</li>
<li>How to process tool calls using a switch statement</li>
<li>How to respond with a <code>tool_result</code> so that Claude can output a final answer</li>
</ol>
<p>The purpose of this post was to get you started by providing a foundational understanding of Anthropic tool usage using the Python SDK. For more information about <a href="https://docs.anthropic.com/claude/docs/tool-use#best-practices-for-tool-definitions">tool best practices</a> or <a href="https://docs.anthropic.com/claude/docs/tool-use-examples#multiple-tools">multi-tool chaining</a>, please refer to Anthropic&rsquo;s documentation.</p>
]]></content:encoded></item><item><title>Applying event filters to AWS Lambda Functions with the AWS CDK</title><link>https://how.wtf/applying-event-filters-to-aws-lambda-functions-with-the-aws-cdk.html</link><pubDate>Sun, 14 Apr 2024 12:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/applying-event-filters-to-aws-lambda-functions-with-the-aws-cdk.html</guid><description>The primary motive for writing this article is to address the common error I repeatedly received while troubleshooting event filters:
Invalid filter pattern definition. (Service: AWSLambda; Status Code: 400; Error Code: InvalidParameterValueException
For my case, the goal was to invoke an AWS Lambda function via a DynamoDB stream.
What are Lambda Event Filters Lambda event filters allow developers to specify which types of records from a stream or queue are submitted to a Lambda.</description><content:encoded><![CDATA[<p>The primary motive for writing this article is to address the common error I repeatedly received while troubleshooting event filters:</p>
<blockquote>
<p>Invalid filter pattern definition. (Service: AWSLambda; Status Code: 400; Error Code: InvalidParameterValueException</p>
</blockquote>
<p>For my case, the goal was to invoke an AWS Lambda function via a DynamoDB stream.</p>
<h2 id="what-are-lambda-event-filters">What are Lambda Event Filters</h2>
<p>Lambda event filters allow developers to specify <a href="https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html">which types of records from a stream or queue are submitted to a Lambda</a>. Event filters are included in event source mapping definitions so that Lambda functions are only invoked when the filter criteria is met.</p>
<h2 id="dynamodb-ttl-deletion-event-filter">DynamoDB TTL deletion event filter</h2>
<p>My use case involved invoking a lambda function to archive resources when a DynamoDB TTL expiry was met. Fortunately, the DynamoDB documentation <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/time-to-live-ttl-streams.html#streams-archive-ttl-deleted-items">has a section that describes how to achieve this</a>.</p>
<p>The required filter criteria is as follows:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;Filters&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">      <span class="nt">&#34;Pattern&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="nt">&#34;userIdentity&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">          <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;Service&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">          <span class="nt">&#34;principalId&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;dynamodb.amazonaws.com&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>This filter patterns suggests that only actions submitted by the service principal <code>dynamodb.amazonaws.com</code> should be processed by the receiving consumer. This makes sense because the DynamoDB service deletes expired TTL items on our behalf.</p>
<h2 id="adding-event-filters-to-lambda-functions-with-aws-cdk">Adding event filters to Lambda Functions with AWS CDK</h2>
<p>The following example demonstrates how to add event filters to a Lambda function using the AWS CDK in TypeScript:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">path</span> <span class="kr">from</span> <span class="s1">&#39;path&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kr">import</span> <span class="p">{</span> 
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="nx">Code</span><span class="p">,</span> 
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">  <span class="nx">FilterCriteria</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">  <span class="nb">Function</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  <span class="nx">Runtime</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">  <span class="nx">StartingPosition</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;aws-cdk-lib/aws-lambda&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">AttributeType</span><span class="p">,</span> <span class="nx">StreamViewType</span><span class="p">,</span> <span class="nx">Table</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;aws-cdk-lib/aws-dynamodb&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">DynamoEventSource</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;aws-cdk-lib/aws-lambda-event-sources&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="kr">const</span> <span class="nx">table</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Table</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s1">&#39;Table&#39;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">  <span class="nx">partitionKey</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;id&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="kr">type</span><span class="o">:</span> <span class="nx">AttributeType</span><span class="p">.</span><span class="nx">STRING</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">  <span class="nx">stream</span>: <span class="kt">StreamViewType.NEW_IMAGE</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="kr">const</span> <span class="nx">lambda</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Function</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s1">&#39;Function&#39;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">  <span class="nx">runtime</span>: <span class="kt">Runtime.NODEJS_20_X</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">  <span class="nx">handler</span><span class="o">:</span> <span class="s1">&#39;index.handler&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">  <span class="nx">code</span>: <span class="kt">Code.fromAsset</span><span class="p">(</span><span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">__dirname</span><span class="p">,</span> <span class="s1">&#39;lambda-handler&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="nx">lambda</span><span class="p">.</span><span class="nx">addEventSource</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">  <span class="k">new</span> <span class="nx">DynamoEventSource</span><span class="p">(</span><span class="nx">databaseTable</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">    <span class="nx">startingPosition</span>: <span class="kt">StartingPosition.TRIM_HORIZON</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">    <span class="nx">filters</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">      <span class="nx">FilterCriteria</span><span class="p">.</span><span class="nx">filter</span><span class="p">({</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">        <span class="nx">userIdentity</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">          <span class="kr">type</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;Service&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">          <span class="nx">principalId</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;dynamodb.amazonaws.com&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">      <span class="p">})</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl">  <span class="p">})</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="p">)</span></span></span></code></pre></div><p>The crucial part is the inner <code>filters</code> attribute within the event source definition:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nx">lambda</span><span class="p">.</span><span class="nx">addEventSource</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="k">new</span> <span class="nx">DynamoEventSource</span><span class="p">(</span><span class="nx">databaseTable</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="nx">startingPosition</span>: <span class="kt">StartingPosition.TRIM_HORIZON</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="nx">filters</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">      <span class="nx">FilterCriteria</span><span class="p">.</span><span class="nx">filter</span><span class="p">({</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="nx">userIdentity</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">          <span class="kr">type</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;Service&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">          <span class="nx">principalId</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;dynamodb.amazonaws.com&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">      <span class="p">})</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">  <span class="p">})</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="p">)</span></span></span></code></pre></div><p>It&rsquo;s important to note that the <a href="https://github.com/aws/aws-cdk/blob/bb90b4ccdbddbbce08a7d6f1b7d7e625263a70cf/packages/aws-cdk-lib/aws-lambda/lib/event-source-filter.ts#L75">static method of <code>FilterCriteria.filter</code></a> <strong>adds the <code>pattern</code> top-level attribute and marshals the inner JSON on our behalf.</strong></p>
<p>As of April 2024, the <code>filters</code> attribute is available on many supported event sources:</p>
<ul>
<li>The <code>DynamoEventSource</code> <a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_event_sources.DynamoEventSourceProps.html">documentation definition</a></li>
<li>The <code>KafkaEventSource</code> <a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_event_sources.KafkaEventSourceProps.html">documentation definition</a></li>
<li>The <code>KinesisEventSource</code> <a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_event_sources.KinesisEventSourceProps.html">documentation definition</a></li>
<li>The <code>ManagedKafkaEventSource</code> <a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_event_sources.ManagedKafkaEventSourceProps.html">documentation definition</a></li>
<li>The <code>S3EventSource</code> <a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_event_sources.S3EventSourceProps.html">documentation definition</a></li>
<li>The <code>SelfManagedKafkaEventSourceProps</code> <a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_event_sources.SelfManagedKafkaEventSourceProps.html">documentation definition</a></li>
<li>The <code>SqsEventSourceProps</code> <a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_event_sources.SqsEventSourceProps.html">documentation definition</a></li>
</ul>
]]></content:encoded></item><item><title>Deploy serverless Lambda TypeScript API with function url using AWS CDK</title><link>https://how.wtf/deploy-serverless-lambda-typescript-api-with-function-url-using-aws-cdk.html</link><pubDate>Sat, 06 Apr 2024 16:20:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/deploy-serverless-lambda-typescript-api-with-function-url-using-aws-cdk.html</guid><description>In November 2023, I wrote a post describing how to deploy a lambda function with a function url in Python. For this post, I want to showcase how streamlined and practical it is to deploy a &amp;ldquo;Lambdalith&amp;rdquo; (a single Lambda function) that contains an entire API.
What this means:
No API Gateway API requests can take longer than 30 seconds Faster deployments Local testing without cloud deployment Reduced costs * Easy management * = Depends on the use-case How to deploy a serverless API using Fastify To begin, let&amp;rsquo;s initialize a CDK application for Typescript:</description><content:encoded><![CDATA[<p>In November 2023, I wrote a post <a href="https://how.wtf/create-lambda-function-url-using-aws-cdk.html">describing how to deploy a lambda function with a function url</a> in Python. For this post, I want to showcase how streamlined and practical it is to deploy a &ldquo;Lambdalith&rdquo; (a single Lambda function) that contains an entire API.</p>
<p>What this means:</p>
<ol>
<li>No API Gateway</li>
<li><strong>API requests can take longer than 30 seconds</strong></li>
<li>Faster deployments</li>
<li>Local testing without cloud deployment</li>
<li>Reduced costs *</li>
<li>Easy management *</li>
</ol>
<ul>
<li>= Depends on the use-case</li>
</ul>
<h2 id="how-to-deploy-a-serverless-api-using-fastify">How to deploy a serverless API using Fastify</h2>
<p>To begin, let&rsquo;s initialize a CDK application for Typescript:</p>





<pre tabindex="0"><code>cdk init app --language typescript</code></pre><p>This creates the boilerplate directories and files we&rsquo;ll need:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">serverless-api
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">├── README.md
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">├── bin
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">│   └── serverless-api.ts
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">├── cdk.json
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">├── jest.config.js
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">├── lib
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">│   └── serverless-api-stack.ts
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">├── package-lock.json
</span></span><span class="line"><span class="ln">10</span><span class="cl">├── package.json
</span></span><span class="line"><span class="ln">11</span><span class="cl">├── test
</span></span><span class="line"><span class="ln">12</span><span class="cl">│   └── serverless-api.test.ts
</span></span><span class="line"><span class="ln">13</span><span class="cl">└── tsconfig.json</span></span></code></pre></div><h2 id="install-and-configure-fastify">Install and configure Fastify</h2>
<p><a href="https://fastify.dev/">Fastify is a JavaScript web framework</a> that intentionally aims for low overhead and speed over other frameworks such as express. I have arbitrarily chose it for this tutorial, but any web framework that supports routing will work.</p>
<h3 id="install-fastify">Install fastify</h3>
<p>Install <code>fastify</code> using one of the methods <a href="https://fastify.dev/docs/latest/Guides/Getting-Started/">described in their documentation</a> and <a href="https://fastify.dev/docs/latest/Guides/Serverless/">their AWS Lambda adapter <code>@fastify/aws-lambda</code></a>.</p>
<p>For this tutorial, I&rsquo;ll use <code>npm</code>.</p>





<pre tabindex="0"><code>npm i fastify @fastify/aws-lambda @types/aws-lambda</code></pre><h3 id="create-an-entry-file">Create an entry file</h3>
<p>To make it easy, we&rsquo;ll create an entry point for the lambda at <code>handler/index.ts</code> with the following contents:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kr">import</span> <span class="nx">Fastify</span> <span class="kr">from</span> <span class="s2">&#34;fastify&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kr">import</span> <span class="nx">awsLambdaFastify</span> <span class="kr">from</span> <span class="s2">&#34;@fastify/aws-lambda&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kd">function</span> <span class="nx">init() {</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">  <span class="kr">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">Fastify</span><span class="p">();</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">  <span class="nx">app</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">request</span><span class="p">,</span> <span class="nx">reply</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">reply</span><span class="p">.</span><span class="nx">send</span><span class="p">({</span> <span class="nx">hello</span><span class="o">:</span> <span class="s1">&#39;world&#39;</span> <span class="p">}));</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  <span class="k">return</span> <span class="nx">app</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="kr">require</span><span class="p">.</span><span class="nx">main</span> <span class="o">===</span> <span class="nx">module</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="c1">// called directly i.e. &#34;node app&#34;
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"></span>  <span class="nx">init</span><span class="p">().</span><span class="nx">listen</span><span class="p">({</span> <span class="nx">port</span>: <span class="kt">3000</span> <span class="p">},</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;server listening on 3000&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">  <span class="c1">// required as a module =&gt; executed on aws lambda
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"></span>  <span class="nx">exports</span><span class="p">.</span><span class="nx">handler</span> <span class="o">=</span> <span class="nx">awsLambdaFastify</span><span class="p">(</span><span class="nx">init</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>The directory structure should look like the following tree:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">serverless-api
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">├── README.md
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">├── bin
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">│   └── serverless-api.ts
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">├── cdk.json
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">├── handler
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">│   └── index.ts
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">├── jest.config.js
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">├── lib
</span></span><span class="line"><span class="ln">10</span><span class="cl">│   └── serverless-api-stack.ts
</span></span><span class="line"><span class="ln">11</span><span class="cl">├── package-lock.json
</span></span><span class="line"><span class="ln">12</span><span class="cl">├── package.json
</span></span><span class="line"><span class="ln">13</span><span class="cl">├── test
</span></span><span class="line"><span class="ln">14</span><span class="cl">│   └── serverless-api.test.ts
</span></span><span class="line"><span class="ln">15</span><span class="cl">└── tsconfig.json</span></span></code></pre></div><p>With this method, we are able to test locally <em>without</em> deploying to the cloud.</p>
<p>First, transpile the Typescript files to JavaScript:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">npm run build</span></span></code></pre></div><p>Then execute the <code>handler/index.js</code> file with <code>node</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">node handler/index.js</span></span></code></pre></div><p>If you visit <a href="http://localhost:3000">http://localhost:3000</a> in your browser, it should display:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;hello&#34;</span><span class="p">:</span> <span class="s2">&#34;world&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="deploying-the-function-with-the-function-url-enabled">Deploying the function with the function url enabled</h2>
<p>Fortunately, the AWS CDK enables users to quickly deploy using the <code>NodeJSFunction</code> construct. Replace the contents of <code>serverless-api-stack.ts</code> with the following snippet:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">cdk</span> <span class="kr">from</span> <span class="s1">&#39;aws-cdk-lib&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">Construct</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;constructs&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">NodejsFunction</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;aws-cdk-lib/aws-lambda-nodejs&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">FunctionUrlAuthType</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;aws-cdk-lib/aws-lambda&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="kr">export</span> <span class="kr">class</span> <span class="nx">ServerlessApiStack</span> <span class="kr">extends</span> <span class="nx">cdk</span><span class="p">.</span><span class="nx">Stack</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  <span class="kr">constructor</span><span class="p">(</span><span class="nx">scope</span>: <span class="kt">Construct</span><span class="p">,</span> <span class="nx">id</span>: <span class="kt">string</span><span class="p">,</span> <span class="nx">props?</span>: <span class="kt">cdk.StackProps</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="kr">super</span><span class="p">(</span><span class="nx">scope</span><span class="p">,</span> <span class="nx">id</span><span class="p">,</span> <span class="nx">props</span><span class="p">);</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="kr">const</span> <span class="nx">handler</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">NodejsFunction</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s1">&#39;handler&#39;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">      <span class="nx">entry</span><span class="o">:</span> <span class="s1">&#39;./handler/index.ts&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">      <span class="nx">timeout</span>: <span class="kt">cdk.Duration.minutes</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="kr">const</span> <span class="nx">url</span> <span class="o">=</span> <span class="nx">handler</span><span class="p">.</span><span class="nx">addFunctionUrl</span><span class="p">({</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">      <span class="nx">authType</span>: <span class="kt">FunctionUrlAuthType.NONE</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="k">new</span> <span class="nx">cdk</span><span class="p">.</span><span class="nx">CfnOutput</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s1">&#39;url&#39;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">      <span class="nx">value</span>: <span class="kt">url.url</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>The code creates a <code>NodejsFunction</code> lambda, enables the function url without authentication, and outputs the url as a CloudFormation export.</p>
<p>Deploy the stack using the cdk:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">npx cdk deploy</span></span></code></pre></div><p>The command output contains the <code>CfnOutput</code> value:</p>





<pre tabindex="0"><code>Do you wish to deploy these changes (y/n)? y
ServerlessApiStack: deploying... [1/1]
ServerlessApiStack: creating CloudFormation changeset...

 ✅  ServerlessApiStack

✨  Deployment time: 38.19s

Outputs:
ServerlessApiStack.url = https://{id}.lambda-url.us-east-1.on.aws/
Stack ARN:
arn:aws:cloudformation:us-east-1:123456789012:stack/ServerlessApiStack/{id}</code></pre><p>If you navigate to the url, you will view the expected results displayed:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;hello&#34;</span><span class="p">:</span> <span class="s2">&#34;world&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>All of this was completed with <em>very</em> little infrastructure to manage and a single <code>index.ts</code> file. From here, you can expand the project to include as many routes as you prefer.</p>
]]></content:encoded></item><item><title>Using Claude 3 Opus with Anthropic API in Python</title><link>https://how.wtf/using-claude-3-opus-with-anthropic-api-in-python.html</link><pubDate>Sat, 09 Mar 2024 12:45:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/using-claude-3-opus-with-anthropic-api-in-python.html</guid><description>With the recent release of the Claude 3 family, this was the perfect opportunity to use the Claude API access that I was recently granted.
The Claude 3 family boasts a huge improvement from the prior family, Claude 2. The introductory post goes into greater detail.
In this post, we&amp;rsquo;ll explore how to invoke Claude 3 Opus using the Anthropic SDK.
Getting started For the purposes of this post, we&amp;rsquo;ll leverage the Python Anthropic SDK.</description><content:encoded><![CDATA[<p>With the <a href="https://www.anthropic.com/news/claude-3-family">recent release of the Claude 3 family</a>, this was the perfect opportunity to use the Claude API access that I was recently granted.</p>
<p>The Claude 3 family boasts a <em>huge</em> improvement from the prior family, Claude 2. The <a href="https://www.anthropic.com/news/claude-3-family">introductory post</a> goes into greater detail.</p>
<p>In this post, we&rsquo;ll explore how to invoke Claude 3 Opus using the Anthropic SDK.</p>
<h2 id="getting-started">Getting started</h2>
<p>For the purposes of this post, we&rsquo;ll leverage the Python Anthropic SDK.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip3 install anthropic</span></span></code></pre></div><p>To authorize requests, please export the <code>ANTHROPIC_API_KEY</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">export</span> <span class="nv">ANTHROPIC_API_KEY</span><span class="o">=</span><span class="s2">&#34;sk...&#34;</span></span></span></code></pre></div><h2 id="how-to-invoke-claude-3-opus">How to invoke Claude 3 Opus</h2>
<p>The API for invoking Anthropic models is simple.</p>
<p>The model id we&rsquo;ll use is the Opus release from Feb. 29th, 2024: <code>claude-3-opus-20240229</code>.</p>
<p>If you wish to target other models, please refer to <a href="https://docs.anthropic.com/claude/docs/models-overview">Anthropic&rsquo;s model page for more information</a>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">anthropic</span> <span class="kn">import</span> <span class="n">Anthropic</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="s2">&#34;claude-3-opus-20240229&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">Anthropic</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">message</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">messages</span><span class="o">.</span><span class="n">create</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">max_tokens</span><span class="o">=</span><span class="mi">1024</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">messages</span><span class="o">=</span><span class="p">[{</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="s2">&#34;Hello! How are you?&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="n">model</span><span class="o">=</span><span class="n">model</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Input tokens: </span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">usage</span><span class="o">.</span><span class="n">input_tokens</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Output tokens: </span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">usage</span><span class="o">.</span><span class="n">output_tokens</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">[ContentBlock(text=&#34;Hello! I&#39;m doing well, thank you for asking. As an AI language model, I don&#39;t have feelings, but I&#39;m functioning properly and ready to assist you with any questions or tasks you may have. How can I help you today?&#34;, type=&#39;text&#39;)]
</span></span><span class="line"><span class="ln">2</span><span class="cl">Input tokens 13
</span></span><span class="line"><span class="ln">3</span><span class="cl">Output tokens 53</span></span></code></pre></div><p>In the example above, the <code>Anthropic()</code> client was instantiated and automatically referenced the environment variable from earlier.</p>
<p>Then, <a href="https://docs.anthropic.com/claude/reference/messages_post">using the Messages API</a>, we created a new message.</p>
<h2 id="how-to-invoke-claude-3-opus-with-streaming">How to invoke Claude 3 Opus with Streaming</h2>
<p>Similarly to before, we also have the option to stream output using Anthropic&rsquo;s API.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">anthropic</span> <span class="kn">import</span> <span class="n">Anthropic</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="s2">&#34;claude-3-opus-20240229&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">Anthropic</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">stream</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">messages</span><span class="o">.</span><span class="n">create</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">max_tokens</span><span class="o">=</span><span class="mi">1024</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">messages</span><span class="o">=</span><span class="p">[</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">            <span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">            <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="s2">&#34;Hello! How are you?&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="n">model</span><span class="o">=</span><span class="n">model</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="n">stream</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="n">message</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="n">input_tokens</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="n">output_tokens</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="k">for</span> <span class="n">event</span> <span class="ow">in</span> <span class="n">stream</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">    <span class="k">match</span> <span class="n">event</span><span class="o">.</span><span class="n">type</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">        <span class="k">case</span> <span class="s2">&#34;message_start&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">            <span class="n">input_tokens</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">usage</span><span class="o">.</span><span class="n">input_tokens</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">        <span class="k">case</span> <span class="s2">&#34;content_block_start&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">            <span class="n">message</span> <span class="o">+=</span> <span class="n">event</span><span class="o">.</span><span class="n">content_block</span><span class="o">.</span><span class="n">text</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">        <span class="k">case</span> <span class="s2">&#34;content_block_delta&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">            <span class="n">message</span> <span class="o">+=</span> <span class="n">event</span><span class="o">.</span><span class="n">delta</span><span class="o">.</span><span class="n">text</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">        <span class="k">case</span> <span class="s2">&#34;message_delta&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">            <span class="n">output_tokens</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="n">usage</span><span class="o">.</span><span class="n">output_tokens</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">        <span class="k">case</span> <span class="s2">&#34;content_block_stop&#34;</span> <span class="o">|</span> <span class="s2">&#34;message_stop&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">            <span class="o">...</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">
</span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Input tokens: </span><span class="si">{</span><span class="n">input_tokens</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Output tokens: </span><span class="si">{</span><span class="n">output_tokens</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Hello! As an AI language model, I don&#39;t have feelings, but I&#39;m functioning well and ready to assist you. How can I help you today?
</span></span><span class="line"><span class="ln">2</span><span class="cl">Input tokens: 13
</span></span><span class="line"><span class="ln">3</span><span class="cl">Output tokens: 35</span></span></code></pre></div><p>For the sake of the example, I concatenated the &ldquo;text&rdquo;-based events together to showcase the full output.</p>
<p>For asynchronous eventing, please <a href="https://github.com/anthropics/anthropic-sdk-python?tab=readme-ov-file#async-usage">refer to the Anthropic SDK documentation</a>.</p>
]]></content:encoded></item><item><title>Amazon Bedrock with images using Claude 3 Sonnet with Python</title><link>https://how.wtf/amazon-bedrock-with-images-using-claude-3-sonnet-with-python.html</link><pubDate>Mon, 04 Mar 2024 23:30:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/amazon-bedrock-with-images-using-claude-3-sonnet-with-python.html</guid><description>On March 4th, 2024, the Claude 3 Sonnet foundational model was made available in Amazon Bedrock. Not only is the model a major improvement over the Claude 2.0 family, but it allows for vision input.
In the post, we&amp;rsquo;ll explore how to invoke Claude 3 Sonnet using Amazon&amp;rsquo;s boto3 library in Python.
Getting started For those unfamiliar with the Bedrock runtime API, I have a post that demonstrates how to invoke it using Claude 2.</description><content:encoded><![CDATA[<p>On <a href="https://aws.amazon.com/blogs/aws/anthropics-claude-3-sonnet-foundation-model-is-now-available-in-amazon-bedrock/">March 4th, 2024</a>, the Claude 3 Sonnet foundational model was made available in Amazon Bedrock. Not only is the model a major improvement over the Claude 2.0 family, but it allows for vision input.</p>
<p>In the post, we&rsquo;ll explore how to invoke Claude 3 Sonnet using Amazon&rsquo;s boto3 library in Python.</p>
<h2 id="getting-started">Getting started</h2>
<p>For those unfamiliar with the Bedrock runtime API, I have <a href="https://how.wtf/amazon-bedrock-runtime-examples-using-boto3.html">a post that demonstrates how to invoke it using Claude 2.0 and Python boto3</a>. For this post, I&rsquo;ll be focusing specifically on image invocations.</p>
<p>Firstly, install <code>boto3</code></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip3 install boto3</span></span></code></pre></div><h2 id="how-to-send-images-to-amazon-bedrock">How to send images to Amazon Bedrock</h2>
<p>Fortunately, the API is straight forward to use. Let&rsquo;s instantiate the Amazon Bedrock Runtime client:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">runtime</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span></span></span></code></pre></div><p>For Claude 3 Sonnet, we are <a href="https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-messages.html">required to use the Anthropic Claude Messages API</a> as the inference parameter input.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="nt">&#34;anthropic_version&#34;</span><span class="p">:</span> <span class="s2">&#34;bedrock-2023-05-31&#34;</span><span class="p">,</span> 
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="nt">&#34;max_tokens&#34;</span><span class="p">:</span> <span class="mi">1024</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="nt">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">            <span class="nt">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">            <span class="nt">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">                    <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;image&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">                    <span class="nt">&#34;source&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">                        <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;base64&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">                        <span class="nt">&#34;media_type&#34;</span><span class="p">:</span> <span class="s2">&#34;image/jpeg&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">                        <span class="nt">&#34;data&#34;</span><span class="p">:</span> <span class="s2">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">                    <span class="p">}</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">                <span class="p">},</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">                    <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;text&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">                    <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;What is in this image?&#34;</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">            <span class="p">]</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>For the Claude 3 Sonnet model, the image is supplied using base64.</p>
<p>For my case, I will be using a local file for the model.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;image.jpg&#34;</span><span class="p">,</span> <span class="s2">&#34;rb&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">image_file</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="n">image_bytes</span> <span class="o">=</span> <span class="n">image_file</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">encoded_image</span> <span class="o">=</span> <span class="n">base64</span><span class="o">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">image_bytes</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">&#34;utf-8&#34;</span><span class="p">)</span></span></span></code></pre></div><p>You may choose to download image using the <code>requests</code> library.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">image_url</span> <span class="o">=</span> <span class="s2">&#34;https://url-to-the-image.com/file.jpg&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">image_bytes</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span><span class="o">.</span><span class="n">content</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">encoded_image</span> <span class="o">=</span> <span class="n">base64</span><span class="o">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">image_bytes</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">&#34;utf-8&#34;</span><span class="p">)</span></span></span></code></pre></div><p>The image I&rsquo;m using is the <a href="https://upload.wikimedia.org/wikipedia/commons/8/8a/Schloss_Sigmaringen_2022.jpg">Hohenzollern Castle in Germany</a>.</p>
<p>Here is the full example:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">base64</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">runtime</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;image.jpg&#34;</span><span class="p">,</span> <span class="s2">&#34;rb&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">image_file</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">image_bytes</span> <span class="o">=</span> <span class="n">image_file</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">encoded_image</span> <span class="o">=</span> <span class="n">base64</span><span class="o">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">image_bytes</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">&#34;utf-8&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">body</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="s2">&#34;anthropic_version&#34;</span><span class="p">:</span> <span class="s2">&#34;bedrock-2023-05-31&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="s2">&#34;max_tokens&#34;</span><span class="p">:</span> <span class="mi">1000</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">                <span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">                <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">                    <span class="p">{</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">                        <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;image&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">                        <span class="s2">&#34;source&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">                            <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;base64&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">                            <span class="s2">&#34;media_type&#34;</span><span class="p">:</span> <span class="s2">&#34;image/jpeg&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">                            <span class="s2">&#34;data&#34;</span><span class="p">:</span> <span class="n">encoded_image</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">                        <span class="p">},</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">                    <span class="p">},</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">                    <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;text&#34;</span><span class="p">,</span> <span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;What is in this image?&#34;</span><span class="p">},</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">                <span class="p">],</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">        <span class="p">],</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">
</span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">runtime</span><span class="o">.</span><span class="n">invoke_model</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-3-sonnet-20240229-v1:0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">    <span class="n">body</span><span class="o">=</span><span class="n">body</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl">
</span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="n">response_body</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;body&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl">
</span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response_body</span><span class="p">)</span></span></span></code></pre></div><p>Here&rsquo;s the <code>response_body</code> converted to a JSON payload:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;id&#34;</span><span class="p">:</span><span class="s2">&#34;msg_01315rokf5kw6LSnnW6aWyVb&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  <span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;message&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="nt">&#34;role&#34;</span><span class="p">:</span><span class="s2">&#34;assistant&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">  <span class="nt">&#34;content&#34;</span><span class="p">:[</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;text&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">      <span class="nt">&#34;text&#34;</span><span class="p">:</span><span class="s2">&#34;This image shows the famous Hohenzollern Castle in Germany. The castle sits majestically atop a cliff, overlooking a river or lake in the foreground. The massive medieval fortress features ornate towers, spires, and archways in a Romanesque architectural style with red tiled roofs. The castle appears to be well-preserved and maintained, set against a picturesque blue sky with fluffy white clouds. The surrounding scenery includes bare trees and a small playground area near the water&#39;s edge, suggesting this is a popular tourist destination showcasing Germany&#39;s rich historical heritage and stunning natural landscapes.&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">  <span class="p">],</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="nt">&#34;model&#34;</span><span class="p">:</span><span class="s2">&#34;claude-3-sonnet-28k-20240229&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">  <span class="nt">&#34;stop_reason&#34;</span><span class="p">:</span><span class="s2">&#34;end_turn&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">  <span class="nt">&#34;stop_sequence&#34;</span><span class="p">:</span><span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">  <span class="nt">&#34;usage&#34;</span><span class="p">:{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="nt">&#34;input_tokens&#34;</span><span class="p">:</span><span class="mi">1606</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="nt">&#34;output_tokens&#34;</span><span class="p">:</span><span class="mi">130</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Sure enough, the model accurately depicted the image shown.</p>
]]></content:encoded></item><item><title>Create and run Bash programs with LangChain</title><link>https://how.wtf/create-and-run-bash-programs-with-langchain.html</link><pubDate>Sun, 11 Feb 2024 11:45:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/create-and-run-bash-programs-with-langchain.html</guid><description>Using LangChain, we can create a prompt to output a bash, which is then executed via the BashProcess tool.
All of this is as easy as a few lines of Python code!
How to generate bash scripts using LangChain First, let&amp;rsquo;s install the necessary dependencies:
1pip install langchain-core langchain-experimental langchain-openaiNow, let&amp;rsquo;s write a simplistic prompt to get OpenAI to output bash code.
For this example, we&amp;rsquo;ll target a script that outputs:</description><content:encoded><![CDATA[<p>Using LangChain, we can create a prompt to output a <code>bash</code>, which is then executed via the <code>BashProcess</code> tool.</p>
<p>All of this is as easy as a few lines of Python code!</p>
<h2 id="how-to-generate-bash-scripts-using-langchain">How to generate bash scripts using LangChain</h2>
<p>First, let&rsquo;s install the necessary dependencies:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install langchain-core langchain-experimental langchain-openai</span></span></code></pre></div><p>Now, let&rsquo;s write a simplistic prompt to get OpenAI to output bash code.</p>
<p>For this example, we&rsquo;ll target a script that outputs:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Hello world!</span></span></code></pre></div><p>Script:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_core.output_parsers</span> <span class="kn">import</span> <span class="n">StrOutputParser</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_experimental.llm_bash.bash</span> <span class="kn">import</span> <span class="n">BashProcess</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_openai</span> <span class="kn">import</span> <span class="n">ChatOpenAI</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_core.prompts</span> <span class="kn">import</span> <span class="n">ChatPromptTemplate</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="k">def</span> <span class="nf">sanitize_output</span><span class="p">(</span><span class="n">text</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">_</span><span class="p">,</span> <span class="n">after</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&#34;```bash&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="k">return</span> <span class="n">after</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&#34;```&#34;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">template</span> <span class="o">=</span> <span class="s2">&#34;&#34;&#34;Write some bash code to solve the user&#39;s problem. 
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="s2">Return only bash code in Markdown format, e.g.:
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="s2">```bash
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="s2">....
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="s2">```&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="n">prompt</span> <span class="o">=</span> <span class="n">ChatPromptTemplate</span><span class="o">.</span><span class="n">from_messages</span><span class="p">([(</span><span class="s2">&#34;system&#34;</span><span class="p">,</span> <span class="n">template</span><span class="p">),</span> <span class="p">(</span><span class="s2">&#34;human&#34;</span><span class="p">,</span> <span class="s2">&#34;</span><span class="si">{input}</span><span class="s2">&#34;</span><span class="p">)])</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="n">ChatOpenAI</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="n">chain</span> <span class="o">=</span> <span class="n">prompt</span> <span class="o">|</span> <span class="n">model</span> <span class="o">|</span> <span class="n">StrOutputParser</span><span class="p">()</span> <span class="o">|</span> <span class="n">sanitize_output</span> <span class="o">|</span> <span class="n">BashProcess</span><span class="p">()</span><span class="o">.</span><span class="n">run</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">chain</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span><span class="s2">&#34;input&#34;</span><span class="p">:</span> <span class="s2">&#34;Print &#39;Hello world!&#39; to the console&#34;</span><span class="p">}))</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Hello world!</span></span></code></pre></div><p>Using LangChain Expression Language (LCEL), we constructed a <code>chain</code> by using the pipe operator to combine:</p>
<ol>
<li>prompt</li>
<li>model</li>
<li>StrOutputParser</li>
<li>sanitize_output</li>
<li>BashProcess().run</li>
</ol>
<p>This example was adapted from the <a href="https://python.langchain.com/docs/expression_language/cookbook/code_writing">&ldquo;Code Writing&rdquo; cookbook</a> provided in the Langchain documentation.</p>
<p>The <code>sanitize_output</code> function extracts the <code>bash</code> code from the markdown output and pipes it to the <code>BashProcess</code> tool. To learn more about the <a href="https://api.python.langchain.com/en/stable/llm_bash/langchain_experimental.llm_bash.bash.BashProcess.html#langchain_experimental.llm_bash.bash.BashProcess">bash process tool, visit the documentation</a>.</p>
]]></content:encoded></item><item><title>Step by step guide for the date in Bash</title><link>https://how.wtf/step-by-step-guide-for-the-date-in-bash.html</link><pubDate>Sat, 10 Feb 2024 22:00:07 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/step-by-step-guide-for-the-date-in-bash.html</guid><description>Unix provides a utility named date. As its name implies, it allows you to fetch your system&amp;rsquo;s date.
Display the current date Displaying the current date is simple:
1echo $(date)Output:
1Sat Feb 10 21:29:37 EST 2024The system date was printed with the timezone information.
Display the current date in UTC Similarly, we can display the current date in UTC (Coordinated Universal Time) using the -u flag:
1echo $(date -u)Output:
1Sun Feb 11 02:31:06 UTC 2024The datetime was printed with the UTC timezone information.</description><content:encoded><![CDATA[<p>Unix provides a utility named <code>date</code>. As its name implies, it allows you to fetch your system&rsquo;s date.</p>
<h2 id="display-the-current-date">Display the current date</h2>
<p>Displaying the current date is simple:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="k">$(</span>date<span class="k">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Sat Feb 10 21:29:37 EST 2024</span></span></code></pre></div><p>The system date was printed with the timezone information.</p>
<h2 id="display-the-current-date-in-utc">Display the current date in UTC</h2>
<p>Similarly, we can display the current date in UTC (Coordinated Universal Time) using the <code>-u</code> flag:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="k">$(</span>date -u<span class="k">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Sun Feb 11 02:31:06 UTC 2024</span></span></code></pre></div><p>The datetime was printed with the UTC timezone information.</p>
<h2 id="format-the-current-date">Format the current date</h2>
<p>The default <code>date</code> output can easily be formatted in a bash script:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">now</span><span class="o">=</span><span class="s2">&#34;</span><span class="k">$(</span>date <span class="s1">&#39;+%Y-%m-%d&#39;</span><span class="k">)</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">echo</span> <span class="nv">$now</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">2024-02-10</span></span></code></pre></div><p>The <code>date</code> manual page <a href="https://man7.org/linux/man-pages/man1/date.1.html">showcases all the formatting options</a> available.</p>
<h2 id="getting-a-date-from-days-ago">Getting a date from days ago</h2>
<p>Using the <code>-d</code> or <code>--date</code> option, we can display a different date:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">now</span><span class="o">=</span><span class="s2">&#34;</span><span class="k">$(</span>date -d <span class="s1">&#39;2 days ago&#39;</span> <span class="s1">&#39;+%Y-%m-%d&#39;</span><span class="k">)</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">echo</span> <span class="nv">$now</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">2024-02-08</span></span></code></pre></div><p>For MacOS users, use the <code>-v</code> option:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">now</span><span class="o">=</span><span class="s2">&#34;</span><span class="k">$(</span>date -v-2d <span class="s1">&#39;+%Y-%m-%d&#39;</span><span class="k">)</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">echo</span> <span class="nv">$now</span></span></span></code></pre></div><h2 id="iso-8601-date-in-bash">ISO-8601 date in Bash</h2>
<p>In 2011, the <code>-I</code> or <code>--iso-8601</code> <a href="https://git.savannah.gnu.org/gitweb/?p=coreutils.git;a=commitdiff;h=2f1384b7">option was reintroduced</a> to the <code>date</code> utility.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">now</span><span class="o">=</span><span class="s2">&#34;</span><span class="k">$(</span>date -Iseconds<span class="k">)</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">echo</span> <span class="nv">$now</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">2024-02-11T02:47:41+00:00</span></span></code></pre></div><p>For MacOS users, the <code>-I</code> option does not exist. You must format instead:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">now</span><span class="o">=</span><span class="s2">&#34;</span><span class="k">$(</span>date -u <span class="s1">&#39;+%Y-%m-%dT%H:%M:%SZ&#39;</span><span class="k">)</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">echo</span> <span class="nv">$now</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">2024-02-11T02:54:53Z</span></span></code></pre></div><h2 id="comparing-two-dates-in-bash">Comparing two dates in Bash</h2>
<p>Using <code>-d</code> to convert the dates to unix timestamp, we can compare them.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">dateOne</span><span class="o">=</span><span class="k">$(</span>date -d 2022-02-10 +%s<span class="k">)</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nv">dateTwo</span><span class="o">=</span><span class="k">$(</span>date -d 2021-12-12 +%s<span class="k">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">if</span> <span class="o">[</span> <span class="nv">$dateOne</span> -ge <span class="nv">$dateTwo</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;woah!&#34;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p>For MacOS users, the equivalent option is:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">dateOne</span><span class="o">=</span><span class="k">$(</span>date -j -f <span class="s2">&#34;%F&#34;</span> 2022-02-10 +<span class="s2">&#34;%s&#34;</span><span class="k">)</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nv">dateTwo</span><span class="o">=</span><span class="k">$(</span>date -j -f <span class="s2">&#34;%F&#34;</span> 2021-12-12 +<span class="s2">&#34;%s&#34;</span><span class="k">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">if</span> <span class="o">[</span> <span class="nv">$dateOne</span> -ge <span class="nv">$dateTwo</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;woah!&#34;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Get Anthropic Claude Amazon Bedrock token counts</title><link>https://how.wtf/get-anthropic-claude-amazon-bedrock-token-counts.html</link><pubDate>Sat, 10 Feb 2024 01:10:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/get-anthropic-claude-amazon-bedrock-token-counts.html</guid><description>Last year, I wrote a post showcasing how to tokenize words using the Anthropic SDK to track token usage.
While this method continues to work, it&amp;rsquo;s not necessary since the Amazon Bedrock team added token metrics to the SDK response metadata.
In this guide, we&amp;rsquo;ll explore the SDK and how to get those token counts.
Install the AWS SDK To begin, install boto3, the AWS SDK for Python, using pip:</description><content:encoded><![CDATA[<p>Last year, I wrote a post showcasing how to <a href="https://how.wtf/how-to-count-amazon-bedrock-claude-tokens-step-by-step-guide.html">tokenize words using the Anthropic SDK</a> to track token usage.</p>
<p>While this method continues to work, it&rsquo;s not necessary since the Amazon Bedrock team added token metrics to the SDK response metadata.</p>
<p>In this guide, we&rsquo;ll explore the SDK and how to get those token counts.</p>
<h2 id="install-the-aws-sdk">Install the AWS SDK</h2>
<p>To begin, install <code>boto3</code>, the AWS SDK for Python, using <code>pip</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install boto3</span></span></code></pre></div><h2 id="list-model-access">List model access</h2>
<p>The <a href="https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-runtime/client/invoke_model.html"><code>invoke_model</code> call requires a model id</a>. To determine which models are accessible in your AWS account, run the following command using the <code>aws</code> cli:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws bedrock list-foundation-models <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --by-provider anthropic <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --query <span class="s2">&#34;modelSummaries[*].modelId&#34;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="s2">&#34;anthropic.claude-instant-v1:2:100k&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="s2">&#34;anthropic.claude-instant-v1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="s2">&#34;anthropic.claude-v1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="s2">&#34;anthropic.claude-v2:0:18k&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="s2">&#34;anthropic.claude-v2:0:100k&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="s2">&#34;anthropic.claude-v2:1:18k&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="s2">&#34;anthropic.claude-v2:1:200k&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="s2">&#34;anthropic.claude-v2:1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="s2">&#34;anthropic.claude-v2&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="p">]</span></span></span></code></pre></div><h2 id="call-claude-using-bedrock-client">Call Claude using Bedrock client</h2>
<p>The AWS SDK <a href="https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-runtime/client/invoke_model.html">provides a <code>bedrock-runtime</code> client with an <code>invoke_model</code> function</a>. We&rsquo;ll use this and <a href="https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-claude.html">the Claude inference parameters documentation</a> to invoke it.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">bedrock</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">params</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="s2">&#34;prompt&#34;</span><span class="p">:</span> <span class="s2">&#34;</span><span class="se">\n\n</span><span class="s2">Human: Who are you?</span><span class="se">\n\n</span><span class="s2">Assistant:&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="s2">&#34;max_tokens_to_sample&#34;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">bedrock</span><span class="o">.</span><span class="n">invoke_model</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="n">body</span><span class="o">=</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">params</span><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(),</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-instant-v1&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="p">)</span></span></span></code></pre></div><p>Here&rsquo;s the output pretty-printed in <code>json</code> format:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;ResponseMetadata&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="nt">&#34;RequestId&#34;</span><span class="p">:</span> <span class="s2">&#34;d72967be-90c2-4118-951e-a555455d5d7a&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="nt">&#34;HTTPStatusCode&#34;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="nt">&#34;HTTPHeaders&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">      <span class="nt">&#34;date&#34;</span><span class="p">:</span> <span class="s2">&#34;Sat, 10 Feb 2024 05:55:23 GMT&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">      <span class="nt">&#34;content-type&#34;</span><span class="p">:</span> <span class="s2">&#34;application/json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">      <span class="nt">&#34;content-length&#34;</span><span class="p">:</span> <span class="s2">&#34;117&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">      <span class="nt">&#34;connection&#34;</span><span class="p">:</span> <span class="s2">&#34;keep-alive&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">      <span class="nt">&#34;x-amzn-requestid&#34;</span><span class="p">:</span> <span class="s2">&#34;d72967be-90c2-4118-951e-a555455d5d7a&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">      <span class="nt">&#34;x-amzn-bedrock-invocation-latency&#34;</span><span class="p">:</span> <span class="s2">&#34;430&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">      <span class="nt">&#34;x-amzn-bedrock-output-token-count&#34;</span><span class="p">:</span> <span class="s2">&#34;17&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">      <span class="nt">&#34;x-amzn-bedrock-input-token-count&#34;</span><span class="p">:</span> <span class="s2">&#34;13&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="nt">&#34;RetryAttempts&#34;</span><span class="p">:</span> <span class="mi">0</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">  <span class="nt">&#34;contentType&#34;</span><span class="p">:</span> <span class="s2">&#34;application/json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">  <span class="nt">&#34;body&#34;</span><span class="p">:</span> <span class="s2">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Notice the information it provides us in the <code>ResponseMetadata.HTTPHeaders</code>?</p>
<h2 id="count-the-anthropic-claude-token-input-and-output">Count the Anthropic Claude token input and output</h2>
<p>We can modify the code snippet above to reveal the model&rsquo;s output and token usage:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">bedrock</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">params</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="s2">&#34;prompt&#34;</span><span class="p">:</span> <span class="s2">&#34;</span><span class="se">\n\n</span><span class="s2">Human: Who are you?</span><span class="se">\n\n</span><span class="s2">Assistant:&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="s2">&#34;max_tokens_to_sample&#34;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">bedrock</span><span class="o">.</span><span class="n">invoke_model</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="n">body</span><span class="o">=</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">params</span><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(),</span> <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-instant-v1&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="n">body</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;body&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">body</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="n">completion</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;completion&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="n">input_token_count</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;ResponseMetadata&#34;</span><span class="p">][</span><span class="s2">&#34;HTTPHeaders&#34;</span><span class="p">][</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="s2">&#34;x-amzn-bedrock-input-token-count&#34;</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="n">output_token_count</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;ResponseMetadata&#34;</span><span class="p">][</span><span class="s2">&#34;HTTPHeaders&#34;</span><span class="p">][</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">    <span class="s2">&#34;x-amzn-bedrock-output-token-count&#34;</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">completion</span><span class="p">,</span> <span class="n">input_token_count</span><span class="p">,</span> <span class="n">output_token_count</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl"> My name is Claude. I&#39;m an AI assistant created by Anthropic.
</span></span><span class="line"><span class="ln">2</span><span class="cl">13
</span></span><span class="line"><span class="ln">3</span><span class="cl">20</span></span></code></pre></div><p>That was easy!</p>
]]></content:encoded></item><item><title>The right way to test exit codes in Bash</title><link>https://how.wtf/the-right-way-to-test-exit-codes-in-bash.html</link><pubDate>Sat, 03 Feb 2024 22:45:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/the-right-way-to-test-exit-codes-in-bash.html</guid><description>In this article, we&amp;rsquo;ll go over how to properly test exit codes in Bash scripts.
Testing exit codes with $? When I first started writing Bash, I often wrote the following code to test whether a program&amp;rsquo;s execution was successful:
1some_command 2if [ &amp;#34;$?&amp;#34; -eq 0 ]; then 3 echo &amp;#34;It worked!&amp;#34; 4fiHowever, this introduces complexity in the flow of the script. For example, one minor mistake like adding en echo statement:</description><content:encoded><![CDATA[<p>In this article, we&rsquo;ll go over how to properly test exit codes in Bash scripts.</p>
<h2 id="testing-exit-codes-with-">Testing exit codes with $?</h2>
<p>When I first started writing Bash, I often wrote the following code to test whether a program&rsquo;s execution was successful:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">some_command
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">if</span> <span class="o">[</span> <span class="s2">&#34;</span><span class="nv">$?</span><span class="s2">&#34;</span> -eq <span class="m">0</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;It worked!&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p>However, this introduces complexity in the flow of the script. For example, one minor mistake like adding en echo statement:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">some_command
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;some_command&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">if</span> <span class="o">[</span> <span class="s2">&#34;</span><span class="nv">$?</span><span class="s2">&#34;</span> -eq <span class="m">0</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;It worked!&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p>can introduce unintended side effects that are not immediately clear. In this case, the <code>echo</code> statement&rsquo;s exit status is <code>0</code> and skips the <code>if</code> conditional.</p>
<p>Therefore, <strong>if status codes are used as true/false indictators, do not use this method</strong></p>
<h2 id="testing-for-successful-exit-codes">Testing for successful exit codes</h2>
<p>For the majority of my use cases, I need to evaluate whether a program&rsquo;s execution is or is not successful.</p>
<p>Using the following syntax clearly informs readers what is happening:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">if</span> some_command<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;It worked!&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p>If <code>some_command</code> executes correctly, <code>echo &quot;It worked!&quot;</code>.</p>
<h2 id="testing-for-failed-exit-codes">Testing for failed exit codes</h2>
<p>Similarly, we can test for failed exit codes by negating the <code>if</code> statement:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">if</span> ! some_command<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;It did not work!&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p>If <code>some_command</code> executes incorrectly, <code>echo &quot;It did not work!&quot;</code></p>
<h2 id="testing-for-specific-exit-codes">Testing for specific exit codes</h2>
<p>If your use case requires testing for specific exit codes, then I recommend collecting the exit status on the same line and using a <code>case</code> statement.</p>
<p>For example:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">some_command<span class="p">;</span> <span class="nv">some_command_exit_code</span><span class="o">=</span><span class="nv">$?</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">case</span> <span class="nv">$some_command_exit_code</span> in
</span></span><span class="line"><span class="ln">3</span><span class="cl">    0<span class="o">)</span> <span class="nb">echo</span> <span class="s2">&#34;It worked!&#34;</span> <span class="p">;;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    *<span class="o">)</span> <span class="nb">echo</span> <span class="s2">&#34;It did not work!&#34;</span> <span class="p">;;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="k">esac</span></span></span></code></pre></div><p>Using a <code>case</code> statement allows us to control the flow in an easy-to-digest manner.</p>
<p>After all, code maintainability should be prioritized.</p>
]]></content:encoded></item><item><title>How to use Embedchain with AWS Bedrock</title><link>https://how.wtf/how-to-use-embedchain-with-aws-bedrock.html</link><pubDate>Sat, 03 Feb 2024 11:50:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-use-embedchain-with-aws-bedrock.html</guid><description>LangChain is a framework that streamlines developing LLM applications. In a nutshell, it provides abstractions that help build out common steps and flows for working with LLMs.
In this post, we&amp;rsquo;ll go over how to integrate Embedchain, an open source RAG framework, with AWS Bedrock!
What is Embedchain Embedchain is an open source RAG framework aimed at allowing developers to quickly gather necessary knowledge for LLM context when answering user prompts.</description><content:encoded><![CDATA[<p><a href="https://www.langchain.com/">LangChain is a framework</a> that streamlines developing LLM applications. In a nutshell, it provides abstractions that help build out common steps and flows for working with LLMs.</p>
<p>In this post, we&rsquo;ll go over how to integrate <a href="https://docs.embedchain.ai/get-started/quickstart:wqa">Embedchain, an open source RAG framework</a>, with AWS Bedrock!</p>
<h2 id="what-is-embedchain">What is Embedchain</h2>
<p>Embedchain is an open source RAG framework aimed at allowing developers to quickly gather necessary knowledge for LLM context when answering user prompts.</p>
<p>In particular, it shines with its easy-to-use API for adding unstructured data into manageable and optimized chunks for retrieval. In addition, it has synchronization options to ensure data sources are frequently updated.</p>
<h2 id="getting-started-with-embedchain">Getting started with Embedchain</h2>
<p>To showcase the power of Embedchain, let&rsquo;s spin up a quick demo about Ada Lovelace - &ldquo;The world&rsquo;s first programmer&rdquo;.</p>
<p>To begin, install the necessary dependencies:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install embedchain</span></span></code></pre></div><p>For the sake of this example, I&rsquo;m using OpenAI&rsquo;s API. Embedchain <a href="https://docs.embedchain.ai/components/llms">supports many other models</a> as well.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">export</span> <span class="nv">OPENAI_API_KEY</span><span class="o">=</span><span class="s2">&#34;...&#34;</span></span></span></code></pre></div><h2 id="embedchain-example-rag">Embedchain example RAG</h2>
<p>The following code is a basic example of RAG using Embedchain.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">embedchain</span> <span class="kn">import</span> <span class="n">App</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">bot</span> <span class="o">=</span> <span class="n">App</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">bot</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&#34;https://en.wikipedia.org/wiki/Ada_Lovelace&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">bot</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="s2">&#34;Who is Ada Lovelace?&#34;</span><span class="p">))</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Inserting batches in chromadb: 100% 1/1 [00:00&lt;00:00,  1.26it/s]
</span></span><span class="line"><span class="ln">2</span><span class="cl">Successfully saved https://en.wikipedia.org/wiki/Ada_Lovelace (DataType.WEB_PAGE). New chunks count: 33
</span></span><span class="line"><span class="ln">3</span><span class="cl">Ada Lovelace was an English mathematician and writer known for her work on Charles Babbage&#39;s proposed mechanical general-purpose computer, the Analytical Engine. She was the first to recognize that the machine had applications beyond pure calculation. Ada Lovelace was the only legitimate child of poet Lord Byron and reformer Lady Byron. She made significant contributions to the field of mathematics and is considered to be the world&#39;s first computer programmer.</span></span></code></pre></div><p>Steps:</p>
<ol>
<li>Instantiate a <code>Pipeline</code> from <code>embedchain</code></li>
<li>Insert new documents into the pipeline</li>
<li>Automatically chunk and batch the documents into <code>chromadb</code></li>
<li>Query the <code>chromadb</code> store for relevant documents and answer the question using OpenAI&rsquo;s API</li>
</ol>
<p>For more information on <a href="https://how.wtf/how-to-use-chroma-db-step-by-step-guide.html">ChromaDB as a vector store, checkout my guide</a>.</p>
<h2 id="using-embedchain-with-aws-bedrock-and-claude">Using Embedchain with AWS Bedrock and Claude</h2>
<p>Fortunately, Embedchain directly supports AWS Bedrock as an LLM.</p>
<h3 id="install-the-dependencies">Install the dependencies</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install embedchain<span class="o">[</span>aws-bedrock<span class="o">]</span></span></span></code></pre></div><p>We must install the <code>aws-bedrock</code> extension for <code>embedchain</code>.</p>
<h3 id="create-a-configyaml-file">Create a config.yaml file</h3>
<p>Add the following <code>config.yaml</code> file:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="nt">llm</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w">  </span><span class="nt">provider</span><span class="p">:</span><span class="w"> </span><span class="l">aws_bedrock</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w">  </span><span class="nt">config</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="w">    </span><span class="nt">model</span><span class="p">:</span><span class="w"> </span><span class="l">anthropic.claude-v2</span><span class="w">
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="w">    </span><span class="nt">model_kwargs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="w">      </span><span class="nt">temperature</span><span class="p">:</span><span class="w"> </span><span class="m">0.5</span><span class="w">
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="w">      </span><span class="nt">top_p</span><span class="p">:</span><span class="w"> </span><span class="m">1</span><span class="w">
</span></span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="w">      </span><span class="nt">top_k</span><span class="p">:</span><span class="w"> </span><span class="m">250</span><span class="w">
</span></span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="w">      </span><span class="nt">max_tokens_to_sample</span><span class="p">:</span><span class="w"> </span><span class="m">200</span></span></span></code></pre></div><p>The <code>model_kwargs</code> in this configuration are the defaults from the <a href="https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters.html">model&rsquo;s arguments specified in the AWS documentation</a>.</p>
<h3 id="create-mainpy-file">Create main.py file</h3>
<p>Before running the code, ensure you have AWS access. In my case, I&rsquo;m using an AWS profile, but you can use any of the <a href="https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html#configuring-credentials">supported boto3 authentication methods</a>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">embedchain</span> <span class="kn">import</span> <span class="n">App</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">bot</span> <span class="o">=</span> <span class="n">App</span><span class="o">.</span><span class="n">from_config</span><span class="p">(</span><span class="n">config_path</span><span class="o">=</span><span class="s2">&#34;config.yaml&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">bot</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&#34;https://en.wikipedia.org/wiki/Ada_Lovelace&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">bot</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="s2">&#34;Who is Ada Lovelace?&#34;</span><span class="p">))</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">Ada Lovelace was an English mathematician and writer. Some key facts about her:
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">- She was the only legitimate child of poet Lord Byron and his wife Lady Byron.
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">- She is chiefly known for her work on Charles Babbage&#39;s proposed mechanical general-purpose computer, the Analytical Engine. She recognized the machine had applications beyond pure calculation and published the first algorithm intended to be carried out by such a machine.
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">- She was the first to recognize the full potential of a &#34;computing machine&#34; and of &#34;programming&#34;. For this reason she is often considered the first computer programmer.
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">- She was interested in mathematics and logic from an early age, and pursued studies assiduously despite often being ill in her childhood.
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">- She married William King in 1835. He was made Earl of Lovelace in 1838, making her Countess of Lovelace.
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl">- She died of uterine cancer in 1852 at age</span></span></code></pre></div>]]></content:encoded></item><item><title>How to use JSON files in vector stores with Langchain</title><link>https://how.wtf/how-to-use-json-files-in-vector-stores-with-langchain.html</link><pubDate>Sun, 28 Jan 2024 05:35:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-use-json-files-in-vector-stores-with-langchain.html</guid><description>Retrieval-Augmented Generation (RAG) is a technique for including contextual information from external sources in a large language model&amp;rsquo;s (LLM) prompt. In other terms, RAG is used to supplement an LLM&amp;rsquo;s answer by providing more information in the prompt; thus, removing the need to retrain or fine-tune a model.
For the purposes of this post, we will implement RAG by using Chroma DB as a vector store with the Nobel Prize data set.</description><content:encoded><![CDATA[<p><img src="images/6YHOAH.webp" alt="How to use JSON files in vector stores with langchain step by step"></p>
<p>Retrieval-Augmented Generation (RAG) is a technique for including contextual information from external sources in a large language model&rsquo;s (LLM) prompt. In other terms, RAG is used to supplement an LLM&rsquo;s answer by providing more information in the prompt; thus, removing the need to retrain or fine-tune a model.</p>
<p>For the purposes of this post, we will implement RAG by using Chroma DB as a vector store with the <a href="https://api.nobelprize.org/v1/prize.json">Nobel Prize data set</a>.</p>
<h2 id="langchain-with-json-data-in-a-vector-store">Langchain with JSON data in a vector store</h2>
<p>Chroma DB will be the vector storage system for this post. It&rsquo;s easy to use, open-source, and provides additional filtering options for associated metadata.</p>
<h3 id="getting-started">Getting started</h3>
<p>To begin, install <code>langchain</code>, <code>langchain-community</code>, <code>chromadb</code> and <code>jq</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install langchain langchain-community chromadb jq</span></span></code></pre></div><p><code>jq</code> is required for the <code>JSONLoader</code> class. Its purpose is to parse the JSON file and its contents.</p>
<h3 id="fetching-relevant-documents-using-document-loaders">Fetching relevant documents using document loaders</h3>
<p>For reference, the <code>prize.json</code> file has the following schema:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="nt">&#34;prizes&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">            <span class="nt">&#34;year&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">            <span class="nt">&#34;category&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">            <span class="nt">&#34;laureates&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">                    <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">                    <span class="nt">&#34;firstname&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">                    <span class="nt">&#34;surname&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">                    <span class="nt">&#34;motivation&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">                    <span class="nt">&#34;share&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="p">]</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>with the <code>laureates</code> being optional since some years do not have any winners.</p>
<p>The following code is used to simply fetch relevant documents from Chroma.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_community.document_loaders</span> <span class="kn">import</span> <span class="n">JSONLoader</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.embeddings.sentence_transformer</span> <span class="kn">import</span> <span class="n">SentenceTransformerEmbeddings</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_community.vectorstores</span> <span class="kn">import</span> <span class="n">Chroma</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">embedding_function</span> <span class="o">=</span> <span class="n">SentenceTransformerEmbeddings</span><span class="p">(</span><span class="n">model_name</span><span class="o">=</span><span class="s2">&#34;all-MiniLM-L6-v2&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">loader</span> <span class="o">=</span> <span class="n">JSONLoader</span><span class="p">(</span><span class="n">file_path</span><span class="o">=</span><span class="s2">&#34;./prize.json&#34;</span><span class="p">,</span> <span class="n">jq_schema</span><span class="o">=</span><span class="s2">&#34;.prizes[]&#34;</span><span class="p">,</span> <span class="n">text_content</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">documents</span> <span class="o">=</span> <span class="n">loader</span><span class="o">.</span><span class="n">load</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">db</span> <span class="o">=</span> <span class="n">Chroma</span><span class="o">.</span><span class="n">from_documents</span><span class="p">(</span><span class="n">documents</span><span class="p">,</span> <span class="n">embedding_function</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">query</span> <span class="o">=</span> <span class="s2">&#34;What year did albert einstein win the nobel prize?&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">docs</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">similarity_search</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">docs</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">page_content</span><span class="p">)</span></span></span></code></pre></div><p><strong>Steps</strong>:</p>
<ol>
<li>Use the <code>SentenceTransformerEmbeddings</code> to create an embedding function using the open source model of <code>all-MiniLM-L6-v2</code> from huggingface.</li>
<li>Instantiate the loader for the JSON file using the <code>./prize.json</code> path.</li>
<li>Load the files</li>
<li>Instantiate a Chroma DB instance from the documents &amp; the embedding model</li>
<li>Perform a cosine similarity search</li>
<li>Print out the contents of the first retrieved document</li>
</ol>
<p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span><span class="nt">&#34;year&#34;</span><span class="p">:</span> <span class="s2">&#34;1921&#34;</span><span class="p">,</span> <span class="nt">&#34;category&#34;</span><span class="p">:</span> <span class="s2">&#34;physics&#34;</span><span class="p">,</span> <span class="nt">&#34;laureates&#34;</span><span class="p">:</span> <span class="p">[{</span><span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;26&#34;</span><span class="p">,</span> <span class="nt">&#34;firstname&#34;</span><span class="p">:</span> <span class="s2">&#34;Albert&#34;</span><span class="p">,</span> <span class="nt">&#34;surname&#34;</span><span class="p">:</span> <span class="s2">&#34;Einstein&#34;</span><span class="p">,</span> <span class="nt">&#34;motivation&#34;</span><span class="p">:</span> <span class="s2">&#34;\&#34;for his services to Theoretical Physics, and especially for his discovery of the law of the photoelectric effect\&#34;&#34;</span><span class="p">,</span> <span class="nt">&#34;share&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span><span class="p">}]}</span></span></span></code></pre></div><p>The <code>text_content=False</code> flag allows each array JSON document entry to be vectorized. This works for this use case, but you may want something different.</p>
<p>For example, let&rsquo;s vectorize the contents of the <code>motivation</code> text attribute and add metadata about each motivation:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_community.document_loaders</span> <span class="kn">import</span> <span class="n">JSONLoader</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.embeddings.sentence_transformer</span> <span class="kn">import</span> <span class="n">SentenceTransformerEmbeddings</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_community.vectorstores</span> <span class="kn">import</span> <span class="n">Chroma</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="k">def</span> <span class="nf">metadata_func</span><span class="p">(</span><span class="n">record</span><span class="p">:</span> <span class="nb">dict</span><span class="p">,</span> <span class="n">metadata</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">metadata</span><span class="p">[</span><span class="s2">&#34;id&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="n">record</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">metadata</span><span class="p">[</span><span class="s2">&#34;firstname&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="n">record</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;firstname&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">metadata</span><span class="p">[</span><span class="s2">&#34;surname&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="n">record</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;surname&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="n">metadata</span><span class="p">[</span><span class="s2">&#34;share&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="n">record</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;share&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="k">return</span> <span class="n">metadata</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">embedding_function</span> <span class="o">=</span> <span class="n">SentenceTransformerEmbeddings</span><span class="p">(</span><span class="n">model_name</span><span class="o">=</span><span class="s2">&#34;all-MiniLM-L6-v2&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="n">loader</span> <span class="o">=</span> <span class="n">JSONLoader</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="n">file_path</span><span class="o">=</span><span class="s2">&#34;./prize.json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="n">jq_schema</span><span class="o">=</span><span class="s2">&#34;.prizes[].laureates[]?&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="n">content_key</span><span class="o">=</span><span class="s2">&#34;motivation&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="n">metadata_func</span><span class="o">=</span><span class="n">metadata_func</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="n">documents</span> <span class="o">=</span> <span class="n">loader</span><span class="o">.</span><span class="n">load</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">documents</span><span class="p">)</span></span></span></code></pre></div><p><strong>Steps</strong>:</p>
<ol>
<li>Use the <code>SentenceTransformerEmbeddings</code> to create an embedding function using the open source model of <code>all-MiniLM-L6-v2</code> from huggingface.</li>
<li>Instantiate the loader for the JSON file using the <code>./prize.json</code> path.</li>
<li>Use the <code>?</code> jq syntax to ignore nullables if <code>laureates</code> does not exist on the entry</li>
<li>Use a <code>metadata_func</code> to grab the fields of the JSON to put in the document&rsquo;s metadata</li>
<li>Use the <code>content_key</code> to specify which field is used for the vector text</li>
<li>Load the files</li>
<li>Instantiate a Chroma DB instance from the documents &amp; the embedding model</li>
<li>Print out the loaded documents</li>
</ol>
<p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">[
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    Document(
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        page_content=&#39;&#34;for the discovery and synthesis of quantum dots&#34;&#39;,
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        metadata={
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">            &#39;source&#39;: &#39;path/to/prize.json&#39;,
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">            &#39;seq_num&#39;: 1,
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">            &#39;id&#39;: &#39;1029&#39;,
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">            &#39;firstname&#39;: &#39;Moungi&#39;,
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            &#39;surname&#39;: &#39;Bawendi&#39;,
</span></span><span class="line"><span class="ln">10</span><span class="cl">            &#39;share&#39;: &#39;3&#39;
</span></span><span class="line"><span class="ln">11</span><span class="cl">        }
</span></span><span class="line"><span class="ln">12</span><span class="cl">    ),
</span></span><span class="line"><span class="ln">13</span><span class="cl">    ...
</span></span><span class="line"><span class="ln">14</span><span class="cl">]</span></span></code></pre></div><p><strong>Note</strong>: The <code>metadata_func</code> is only required if you want to add your own arbitrary metadata. If that&rsquo;s not a concern, you can omit it and use the <code>jq_schema</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_community.document_loaders</span> <span class="kn">import</span> <span class="n">JSONLoader</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.embeddings.sentence_transformer</span> <span class="kn">import</span> <span class="n">SentenceTransformerEmbeddings</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_community.vectorstores</span> <span class="kn">import</span> <span class="n">Chroma</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">embedding_function</span> <span class="o">=</span> <span class="n">SentenceTransformerEmbeddings</span><span class="p">(</span><span class="n">model_name</span><span class="o">=</span><span class="s2">&#34;all-MiniLM-L6-v2&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">loader</span> <span class="o">=</span> <span class="n">JSONLoader</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">file_path</span><span class="o">=</span><span class="s2">&#34;./prize.json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">jq_schema</span><span class="o">=</span><span class="s2">&#34;.prizes[].laureates[]?.motivation&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">documents</span> <span class="o">=</span> <span class="n">loader</span><span class="o">.</span><span class="n">load</span><span class="p">()</span></span></span></code></pre></div><h2 id="langchain-expression-with-chroma-db-json-rag">Langchain Expression with Chroma DB JSON (RAG)</h2>
<p>After exploring how to use JSON files in a vector store, let&rsquo;s integrate Chroma DB using JSON data in a chain.</p>
<p>For the purposes of this code, I used OpenAI model and embeddings.</p>
<p>Install the following dependencies:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install langchain langchain-community langchain-openai chromadb jq</span></span></code></pre></div><p>Then run the following code:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.prompts</span> <span class="kn">import</span> <span class="n">ChatPromptTemplate</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_community.vectorstores</span> <span class="kn">import</span> <span class="n">Chroma</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_community.document_loaders</span> <span class="kn">import</span> <span class="n">JSONLoader</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_community.embeddings</span> <span class="kn">import</span> <span class="n">OpenAIEmbeddings</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_core.output_parsers</span> <span class="kn">import</span> <span class="n">StrOutputParser</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_core.runnables</span> <span class="kn">import</span> <span class="n">RunnableLambda</span><span class="p">,</span> <span class="n">RunnablePassthrough</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_openai</span> <span class="kn">import</span> <span class="n">ChatOpenAI</span><span class="p">,</span> <span class="n">OpenAIEmbeddings</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">embedding_function</span> <span class="o">=</span> <span class="n">OpenAIEmbeddings</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">loader</span> <span class="o">=</span> <span class="n">JSONLoader</span><span class="p">(</span><span class="n">file_path</span><span class="o">=</span><span class="s2">&#34;./prize.json&#34;</span><span class="p">,</span> <span class="n">jq_schema</span><span class="o">=</span><span class="s2">&#34;.prizes[]&#34;</span><span class="p">,</span> <span class="n">text_content</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="n">documents</span> <span class="o">=</span> <span class="n">loader</span><span class="o">.</span><span class="n">load</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="n">db</span> <span class="o">=</span> <span class="n">Chroma</span><span class="o">.</span><span class="n">from_documents</span><span class="p">(</span><span class="n">documents</span><span class="p">,</span> <span class="n">embedding_function</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="n">retriever</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">as_retriever</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="n">template</span> <span class="o">=</span> <span class="s2">&#34;&#34;&#34;Answer the question based only on the following context:
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="s2"></span><span class="si">{context}</span><span class="s2">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="s2">Question: </span><span class="si">{question}</span><span class="s2">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="s2">&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="n">prompt</span> <span class="o">=</span> <span class="n">ChatPromptTemplate</span><span class="o">.</span><span class="n">from_template</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="n">ChatOpenAI</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="n">chain</span> <span class="o">=</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">    <span class="p">{</span><span class="s2">&#34;context&#34;</span><span class="p">:</span> <span class="n">retriever</span><span class="p">,</span> <span class="s2">&#34;question&#34;</span><span class="p">:</span> <span class="n">RunnablePassthrough</span><span class="p">()}</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">    <span class="o">|</span> <span class="n">prompt</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">    <span class="o">|</span> <span class="n">model</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">    <span class="o">|</span> <span class="n">StrOutputParser</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">
</span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="n">query</span> <span class="o">=</span> <span class="s2">&#34;What year did albert einstein win the nobel prize?&#34;</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">chain</span><span class="o">.</span><span class="n">invoke</span><span class="p">(</span><span class="n">query</span><span class="p">))</span></span></span></code></pre></div><p><strong>Steps</strong>:</p>
<ol>
<li>Use the <code>OpenAIEmbeddings</code> to create an embedding function</li>
<li>Load the JSON file</li>
<li>Instantiate the Chroma DB instance from the documents &amp; embedding model</li>
<li>Create a prompt template with <code>context</code> and <code>question</code> variables</li>
<li>Create a chain using the <code>ChatOpenAI</code> model with a retriever</li>
<li>Invoke the chain with the question <code>What year did albert einstein win the nobel prize?</code></li>
</ol>
<p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Albert Einstein won the Nobel Prize in the year 1921.</span></span></code></pre></div><p>This tutorial only includes the basic functionality for Chroma DB. Please visit my <a href="https://how.wtf/how-to-use-chroma-db-step-by-step-guide.html">Chroma DB guide</a> where I walk step-by-step on how to use it for a more in-depth tutorial.</p>
]]></content:encoded></item><item><title>DynamoDB PartiQL guide</title><link>https://how.wtf/dynamodb-partiql-guide.html</link><pubDate>Sat, 27 Jan 2024 22:30:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/dynamodb-partiql-guide.html</guid><description>AWS introduced a PartiQL in 2019 as a &amp;ldquo;query language for all your data&amp;rdquo; that resembles SQL-like expressions. In November 2020, it was natively integrated with DynamoDB.
In this post, we&amp;rsquo;ll explore using PartiQL with DynamoDB.
What is PartiQL PartiQL is an open source initiative that is maintained by Amazon under the Apache 2.0 license. Its goal is to be a SQL-compatible query language for accessing relational, semi-structured, and nested data.</description><content:encoded><![CDATA[<p><img src="images/BdySwv.webp" alt="DynamoDB and PartiQL logos in a simple architecture image"></p>
<p>AWS <a href="https://aws.amazon.com/blogs/opensource/announcing-partiql-one-query-language-for-all-your-data/">introduced a PartiQL in 2019</a> as a &ldquo;query language for all your data&rdquo; that resembles SQL-like expressions. In November 2020, it was <a href="https://aws.amazon.com/about-aws/whats-new/2020/11/you-now-can-use-a-sql-compatible-query-language-to-query-insert-update-and-delete-table-data-in-amazon-dynamodb/">natively integrated with DynamoDB</a>.</p>
<p>In this post, we&rsquo;ll explore using PartiQL with DynamoDB.</p>
<h2 id="what-is-partiql">What is PartiQL</h2>
<p><a href="https://partiql.org/">PartiQL is an open source initiative</a> that is maintained by Amazon under the Apache 2.0 license. Its goal is to be a SQL-compatible query language for accessing relational, semi-structured, and nested data.</p>
<p>Many AWS services support PartiQL:</p>
<ul>
<li><a href="https://aws.amazon.com/about-aws/whats-new/2020/11/you-now-can-use-a-sql-compatible-query-language-to-query-insert-update-and-delete-table-data-in-amazon-dynamodb/">Amazon DynamoDB</a></li>
<li><a href="https://aws.amazon.com/about-aws/whats-new/2020/12/amazon-redshift-announces-support-native-json-semi-structured-data-processing/">Amazon Redshift</a></li>
<li><a href="https://aws.amazon.com/blogs/aws/now-available-amazon-quantum-ledger-database-qldb/">Amazon QLDB (Quantum Ledger Database)</a></li>
<li><a href="https://aws.amazon.com/about-aws/whats-new/2022/11/twinmaker-knowledge-graph-generally-available-aws-iot-twinmaker/">AWS TwinMaker</a></li>
</ul>
<h2 id="note-about-dynamodb">Note about DynamoDB</h2>
<p>While PartiQL introduces SQL-like expressions for DynamoDB, DynamoDB is a <strong>NoSQL</strong> database. Optimizing your access patterns, understanding key structure, using secondary indexes, and ensuring you&rsquo;re not scanning over large amounts of data is still required.</p>
<p>PartiQL cannot escape DynamoDB&rsquo;s rigidness - a simple SELECT statement can mistakenly scan over the entire table&rsquo;s data. Because of this, ensure you&rsquo;re using <code>WHERE</code> clauses appropriately.</p>
<h2 id="creating-a-table-using-aws-cli">Creating a table using AWS CLI</h2>
<p>Let&rsquo;s first create a table using the <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-adjacency-graphs.html#bp-adjacency-lists">many-to-many relationship model from AWS&rsquo;s documentation</a>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln"> 1</span><span class="cl">aws dynamodb create-table <span class="se">\
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="se"></span>    --table-name ExampleTable <span class="se">\
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="se"></span>    --attribute-definitions <span class="se">\
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="se"></span>        <span class="nv">AttributeName</span><span class="o">=</span>pk,AttributeType<span class="o">=</span>S <span class="se">\
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="se"></span>        <span class="nv">AttributeName</span><span class="o">=</span>sk,AttributeType<span class="o">=</span>S <span class="se">\
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="se"></span>    --key-schema <span class="se">\
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="se"></span>        <span class="nv">AttributeName</span><span class="o">=</span>pk,KeyType<span class="o">=</span>HASH <span class="se">\
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="se"></span>        <span class="nv">AttributeName</span><span class="o">=</span>sk,KeyType<span class="o">=</span>RANGE <span class="se">\
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="se"></span>    --provisioned-throughput <span class="se">\
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="se"></span>        <span class="nv">ReadCapacityUnits</span><span class="o">=</span>5,WriteCapacityUnits<span class="o">=</span><span class="m">5</span></span></span></code></pre></div><p>This creates a table with a hash key of <code>pk</code> and a range key of <code>sk</code>.</p>
<h2 id="inserting-data-using-partiql">Inserting data using PartiQL</h2>
<p>With our <code>ExampleTable</code> in AWS, let&rsquo;s insert a single row of mock data using the <code>INSERT INTO</code> operator:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">INSERT</span><span class="w"> </span><span class="k">INTO</span><span class="w"> </span><span class="n">ExampleTable</span><span class="w"> </span><span class="n">VALUE</span><span class="w"> </span><span class="err">{</span><span class="s1">&#39;pk&#39;</span><span class="p">:</span><span class="s1">&#39;INVOICE#92551&#39;</span><span class="p">,</span><span class="s1">&#39;sk&#39;</span><span class="p">:</span><span class="s1">&#39;INVOICE#92551&#39;</span><span class="p">,</span><span class="s1">&#39;date&#39;</span><span class="p">:</span><span class="s1">&#39;2018-02-07&#39;</span><span class="err">}</span></span></span></code></pre></div><p>Using the AWS CLI</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb execute-statement <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --statement <span class="s2">&#34;INSERT INTO ExampleTable VALUE {&#39;pk&#39;:&#39;INVOICE#92551&#39;,&#39;sk&#39;:&#39;INVOICE#92551&#39;,&#39;date&#39;:&#39;2018-02-07&#39;}&#34;</span></span></span></code></pre></div><h2 id="transactions-using-partiql">Transactions using PartiQL</h2>
<p>For the next bit, we&rsquo;re going to use the <code>transactions</code> API. DynamoDB <a href="https://docs.aws.amazon.com/cli/latest/reference/dynamodb/execute-transaction.html">restricts all transactions to the same operation</a>: either <code>read</code> or <code>write</code>. In our case, we&rsquo;re going to write all the following records:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb execute-transaction <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --transact-statements <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>        <span class="s2">&#34;{\&#34;Statement\&#34;:\&#34;INSERT INTO ExampleTable VALUE {&#39;pk&#39;:&#39;INVOICE#92551&#39;,&#39;sk&#39;:&#39;BILL#4224663&#39;,&#39;date&#39;:&#39;2018-02-07&#39;}\&#34;}&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>        <span class="s2">&#34;{\&#34;Statement\&#34;:\&#34;INSERT INTO ExampleTable VALUE {&#39;pk&#39;:&#39;INVOICE#92551&#39;,&#39;sk&#39;:&#39;BILL#4224687&#39;,&#39;date&#39;:&#39;2018-01-09&#39;}\&#34;}&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>        <span class="s2">&#34;{\&#34;Statement\&#34;:\&#34;INSERT INTO ExampleTable VALUE {&#39;pk&#39;:&#39;INVOICE#92552&#39;,&#39;sk&#39;:&#39;INVOICE#92552&#39;,&#39;date&#39;:&#39;2018-03-04&#39;}\&#34;}&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="se"></span>        <span class="s2">&#34;{\&#34;Statement\&#34;:\&#34;INSERT INTO ExampleTable VALUE {&#39;pk&#39;:&#39;INVOICE#92552&#39;,&#39;sk&#39;:&#39;BILL#4224687&#39;,&#39;date&#39;:&#39;2018-01-09&#39;}\&#34;}&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="se"></span>        <span class="s2">&#34;{\&#34;Statement\&#34;:\&#34;INSERT INTO ExampleTable VALUE {&#39;pk&#39;:&#39;BILL#4224663&#39;,&#39;sk&#39;:&#39;BILL#4224663&#39;,&#39;date&#39;:&#39;2017-12-03&#39;}\&#34;}&#34;</span></span></span></code></pre></div><h2 id="inserting-data-using-partiql-with-parameters">Inserting data using PartiQL with parameters</h2>
<p>For the last insertion, we&rsquo;ll use the <code>--parameters</code> option. Like SQL, we can use the <code>?</code> question mark syntax to denote a parameter.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb execute-statement <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --statement <span class="s2">&#34;INSERT INTO ExampleTable VALUE {&#39;pk&#39;:?,&#39;sk&#39;: ?,&#39;date&#39;:?}&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --parameters <span class="s1">&#39;[{&#34;S&#34;:&#34;BILL#4224687&#34;},{&#34;S&#34;:&#34;BILL#4224687&#34;},{&#34;S&#34;:&#34;2018-01-09&#34;}]&#39;</span></span></span></code></pre></div><h2 id="updating-data-using-partiql">Updating data using PartiQL</h2>
<p>PartiQL only supports updating <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.update.html">a single item at a time</a>. Let&rsquo;s update the <code>BILL#4224663</code> item with a new attribute named <code>foo</code> with a value of <code>bar</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb execute-statement <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --statement <span class="s2">&#34;UPDATE ExampleTable SET foo=&#39;bar&#39; WHERE pk=&#39;BILL#4224663&#39; and sk=&#39;BILL#4224663&#39;&#34;</span></span></span></code></pre></div><p>The statement above creates a new attribute named <code>foo</code> with a vlaue of <code>bar</code> on the item with a <code>pk</code> and an <code>sk</code> of <code>BILL#4224663</code>. Like the DynamoDB <code>put-item</code> API call, we must specify the hash and range key values in the <code>WHERE</code> clause.</p>
<p>The following error will happen if we don&rsquo;t specify both:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">An error occurred (ValidationException) when calling the ExecuteStatement operation: Where clause does not contain a mandatory equality on all key attributes</span></span></code></pre></div><h2 id="removing-an-attribute-or-field-using-partiql">Removing an attribute or field using PartiQL</h2>
<p>PartiQL also supports removing attributes using the following syntax:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb execute-statement <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --statement <span class="s2">&#34;UPDATE ExampleTable REMOVE foo WHERE pk=&#39;BILL#4224663&#39; and sk=&#39;BILL#4224663&#39;&#34;</span></span></span></code></pre></div><p>This removes the <code>foo</code> field we created in the last section.</p>
<h2 id="query-examples-using-partiql">Query examples using PartiQL</h2>
<p><a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.select.html">As documented by AWS</a>, the supported <code>SELECT</code> syntax for PartiQL is the following:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">expression</span><span class="w">  </span><span class="p">[,</span><span class="w"> </span><span class="p">...]</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="k">table</span><span class="p">[.</span><span class="k">index</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w"></span><span class="p">[</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">condition</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="p">[</span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="k">key</span><span class="w"> </span><span class="p">[</span><span class="k">DESC</span><span class="o">|</span><span class="k">ASC</span><span class="p">]</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="p">...]</span></span></span></code></pre></div><p><strong>YOU MUST SPECIFY PARTITION KEYS IF YOU DO NOT WANT TO PERFORM A FULL TABLE SCAN</strong>.</p>
<p>Using our table with its data from the prior examples, let&rsquo;s select <code>BILL#4224663</code>&rsquo;s record:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">ExampleTable</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w"></span><span class="k">WHERE</span><span class="w"> </span><span class="n">pk</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;BILL#4224663&#39;</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">sk</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;BILL#4224663&#39;</span></span></span></code></pre></div><p>AWS CLI:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb execute-statement <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --statement <span class="s2">&#34;SELECT * FROM ExampleTable WHERE pk = &#39;BILL#4224663&#39; AND sk = &#39;BILL#4224663&#39;&#34;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="nt">&#34;Items&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">            <span class="nt">&#34;sk&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;BILL#4224663&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">            <span class="nt">&#34;date&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;2017-12-03&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">            <span class="nt">&#34;pk&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;BILL#4224663&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>We can additionally select multiple records:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">aws</span><span class="w"> </span><span class="n">dynamodb</span><span class="w"> </span><span class="k">execute</span><span class="o">-</span><span class="k">statement</span><span class="w"> </span><span class="err">\</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w">    </span><span class="c1">--statement &#34;SELECT pk, sk FROM ExampleTable WHERE pk IN [&#39;INVOICE#92551&#39;, &#39;INVOICE#92552&#39;]&#34;</span></span></span></code></pre></div><p>PartiQL will execute two DynamoDB queries on our behalf since it&rsquo;s searching for two <code>pk</code> values.</p>
<h2 id="querying-with-begins_with-in-partiql">Querying with begins_with in PartiQL</h2>
<p>Similarly, we can use the DynamoDB <code>begins_with</code> functionality in PartiQL.</p>
<p>In the example below, we query for all bills associated with <code>INVOICE#92551</code></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">ExampleTable</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w"></span><span class="k">where</span><span class="w"> </span><span class="n">pk</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;INVOICE#92551&#39;</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">begins_with</span><span class="p">(</span><span class="n">sk</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;BILL#&#39;</span><span class="p">)</span></span></span></code></pre></div><p>AWS CLI:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb execute-statement <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --statement <span class="s2">&#34;SELECT * FROM ExampleTable where pk = &#39;INVOICE#92551&#39; AND begins_with(sk, &#39;BILL#&#39;)&#34;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="nt">&#34;Items&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">            <span class="nt">&#34;sk&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;BILL#4224663&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">            <span class="nt">&#34;date&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;2018-02-07&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">            <span class="nt">&#34;pk&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;INVOICE#92551&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="nt">&#34;sk&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;BILL#4224687&#34;</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">            <span class="nt">&#34;date&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;2018-01-09&#34;</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">            <span class="nt">&#34;pk&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;INVOICE#92551&#34;</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="protecting-against-scans-using-partiql">Protecting against scans using PartiQL</h2>
<p>PartiQL, while powerful, can be dangerous.</p>
<p>Let&rsquo;s try to find items with a <code>date</code> attribute that is greater than <code>2018-01-09</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">ExampleTable</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w"></span><span class="k">WHERE</span><span class="w"> </span><span class="s2">&#34;date&#34;</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="s1">&#39;2018-01-09&#39;</span></span></span></code></pre></div><p>AWS CLI:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb execute-statement <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --statement <span class="s2">&#34;SELECT * FROM ExampleTable WHERE \&#34;date\&#34; &gt; &#39;2018-01-09&#39;&#34;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="nt">&#34;Items&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">            <span class="nt">&#34;sk&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;BILL#4224663&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">            <span class="nt">&#34;date&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;2018-02-07&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">            <span class="nt">&#34;pk&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;INVOICE#92551&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="nt">&#34;sk&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;INVOICE#92551&#34;</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">            <span class="nt">&#34;date&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;2018-02-07&#34;</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">            <span class="nt">&#34;pk&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;INVOICE#92551&#34;</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">            <span class="nt">&#34;sk&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;INVOICE#92552&#34;</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">            <span class="nt">&#34;date&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;2018-03-04&#34;</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">            <span class="nt">&#34;pk&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;INVOICE#92552&#34;</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>A seemingly harmless query just completed an entire table scan because it used a non-key attribute in the <code>WHERE</code> clause.</p>
<p>To protect against these kinds of queries, <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-iam.html#access-policy-ql-iam-example6">AWS recommends using a</a> <code>DENY</code> IAM policy:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">   <span class="nt">&#34;Version&#34;</span><span class="p">:</span><span class="s2">&#34;2012-10-17&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">   <span class="nt">&#34;Statement&#34;</span><span class="p">:[</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">         <span class="nt">&#34;Effect&#34;</span><span class="p">:</span><span class="s2">&#34;Deny&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">         <span class="nt">&#34;Action&#34;</span><span class="p">:[</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">            <span class="s2">&#34;dynamodb:PartiQLSelect&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">         <span class="p">],</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">         <span class="nt">&#34;Resource&#34;</span><span class="p">:[</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">            <span class="s2">&#34;arn:aws:dynamodb:us-east-1:123456789012:table/ExampleTable&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">         <span class="p">],</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">         <span class="nt">&#34;Condition&#34;</span><span class="p">:{</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">            <span class="nt">&#34;Bool&#34;</span><span class="p">:{</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">               <span class="nt">&#34;dynamodb:FullTableScan&#34;</span><span class="p">:[</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">                  <span class="s2">&#34;true&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">               <span class="p">]</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">         <span class="p">}</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">         <span class="nt">&#34;Effect&#34;</span><span class="p">:</span><span class="s2">&#34;Allow&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">         <span class="nt">&#34;Action&#34;</span><span class="p">:[</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">            <span class="s2">&#34;dynamodb:PartiQLSelect&#34;</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">         <span class="p">],</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">         <span class="nt">&#34;Resource&#34;</span><span class="p">:[</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">            <span class="s2">&#34;arn:aws:dynamodb:us-east-1:123456789012:table/ExampleTable&#34;</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">         <span class="p">]</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">   <span class="p">]</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="deleting-data-using-partiql">Deleting data using PartiQL</h2>
<p>Like updating, PartiQL can only delete 1 item from a table at a time.</p>
<p>We must specify all the keys associated with an item:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb execute-statement <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --statement <span class="s2">&#34;DELETE FROM ExampleTable WHERE pk=&#39;INVOICE#92551&#39; AND sk=&#39;BILL#4224663&#39;&#34;</span></span></span></code></pre></div><h2 id="conclusion">Conclusion</h2>
<p>In this post, we went over how to insert, update, query, and delete data from DynamoDB using PartiQL. PartiQL is a fun way to query DynamoDB, but, as we discussed, can <em>easily</em> turn into a DynamoDB killer with full table scans.</p>
]]></content:encoded></item><item><title>Using type annotations with kwargs in Python</title><link>https://how.wtf/using-type-annotations-with-kwargs-in-python.html</link><pubDate>Fri, 26 Jan 2024 03:40:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/using-type-annotations-with-kwargs-in-python.html</guid><description>Historically in Python, adding explicit typing for kwargs was not directly supported; however, Python 3.12 added that ability.
In this post, we&amp;rsquo;ll go over methods for adding types to the kwargs argument.
Adding type annotations to kwargs Python 3.12 released a new method for explicitly typing kwargs: using a TypedDict + Unpack.
1from typing import NotRequired, TypedDict, Unpack 2 3 4class Parameters(TypedDict): 5 foo: int 6 bar: str 7 baz: NotRequired[str] 8 9 10def some_function(**kwargs: Unpack[Parameters]) -&amp;gt; None: 11 .</description><content:encoded><![CDATA[<p>Historically in Python, adding explicit typing for <code>kwargs</code> was not directly supported; however, Python 3.12 added that ability.</p>
<p>In this post, we&rsquo;ll go over methods for adding types to the <code>kwargs</code> argument.</p>
<h2 id="adding-type-annotations-to-kwargs">Adding type annotations to kwargs</h2>
<p>Python 3.12 <a href="https://peps.python.org/pep-0692/">released a new method</a> for explicitly typing <code>kwargs</code>: using a <code>TypedDict</code> + <code>Unpack</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">NotRequired</span><span class="p">,</span> <span class="n">TypedDict</span><span class="p">,</span> <span class="n">Unpack</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="k">class</span> <span class="nc">Parameters</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="n">foo</span><span class="p">:</span> <span class="nb">int</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">bar</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">baz</span><span class="p">:</span> <span class="n">NotRequired</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="k">def</span> <span class="nf">some_function</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">:</span> <span class="n">Unpack</span><span class="p">[</span><span class="n">Parameters</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="o">...</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">some_function</span><span class="p">(</span><span class="n">foo</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">bar</span><span class="o">=</span><span class="s2">&#34;qux&#34;</span><span class="p">)</span></span></span></code></pre></div><p>Here&rsquo;s what happened:</p>
<ul>
<li><code>Parameters</code> inherits from <code>TypedDict</code></li>
<li><code>NotRequired</code> represents an optional argument</li>
<li><code>kwargs</code> is typed using the <code>Unpack[Parameters]</code> type</li>
</ul>
<p><code>mypy</code> respects the typing.</p>
<h2 id="adding-type-annotations-before-python-312">Adding type annotations before Python 3.12</h2>
<p>Before Python 3.12, there was not a clear way to explicitly declare typing for <code>kwargs</code>. The closest solutions are covered below.</p>
<h3 id="using-typeddict">Using TypedDict</h3>
<p>Instead of using <code>kwargs</code>, ditch it for a <a href="https://peps.python.org/pep-0589/">TypedDict</a>. For example:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TypedDict</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="k">class</span> <span class="nc">Parameters</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="n">foo</span><span class="p">:</span> <span class="nb">int</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">bar</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">baz</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="k">def</span> <span class="nf">some_function</span><span class="p">(</span><span class="n">params</span><span class="p">:</span> <span class="n">Parameters</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="o">...</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">some_function</span><span class="p">(</span><span class="n">Parameters</span><span class="p">(</span><span class="n">foo</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">bar</span><span class="o">=</span><span class="s2">&#34;test&#34;</span><span class="p">,</span> <span class="n">baz</span><span class="o">=</span><span class="kc">None</span><span class="p">))</span></span></span></code></pre></div><p>It&rsquo;s not great, but it provides structured typing and feedback using <code>mypy</code>.</p>
<h3 id="using-any">Using Any</h3>
<p>Simply using <code>Any</code> will suffice with <code>mypy</code> as well:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Any</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">def</span> <span class="nf">some_function</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="o">...</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl">
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="n">some_function</span><span class="p">(</span><span class="n">foo</span><span class="o">=</span><span class="s2">&#34;bar&#34;</span><span class="p">)</span></span></span></code></pre></div><p>But this is obviously not type safe since it disables type checking.</p>
<h3 id="using-a-single-type">Using a single type</h3>
<p>If your use-case allows it, you may define one type for the entire <code>kwargs</code> argument:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">def</span> <span class="nf">some_function</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="o">...</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">some_function</span><span class="p">(</span><span class="n">foo</span><span class="o">=</span><span class="s2">&#34;bar&#34;</span><span class="p">,</span> <span class="n">bar</span><span class="o">=</span><span class="s2">&#34;qux&#34;</span><span class="p">)</span></span></span></code></pre></div><p>Unfortunately, this locks you into having the same type supplied per each argument.</p>
]]></content:encoded></item><item><title>Bruno: The Postman alternative you are looking for</title><link>https://how.wtf/bruno-the-postman-alternative-you-are-looking-for.html</link><pubDate>Sun, 21 Jan 2024 22:50:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/bruno-the-postman-alternative-you-are-looking-for.html</guid><description>Postman used to be my favorite API testing tool, but the company&amp;rsquo;s decision to phase out the final local collection storage feature, Scratchpad, in favor of mandatory cloud services, has changed that.
What is the best Postman alternative? Finding an alternative means it must satisfy the following requirements:
Local collection storage Git-friendly collection definitions for my team members CLI that can invoke collections Beautiful desktop GUI No forced account login with a nice-to-have being open-source.</description><content:encoded><![CDATA[<p>Postman used to be my favorite API testing tool, but the company&rsquo;s decision to phase out the final local collection storage feature, Scratchpad, in favor of mandatory cloud services, has changed that.</p>
<h2 id="what-is-the-best-postman-alternative">What is the best Postman alternative?</h2>
<p>Finding an alternative means it must satisfy the following requirements:</p>
<ol>
<li>Local collection storage</li>
<li>Git-friendly collection definitions for my team members</li>
<li>CLI that can invoke collections</li>
<li>Beautiful desktop GUI</li>
<li><strong>No forced account login</strong></li>
</ol>
<p>with a nice-to-have being open-source.</p>
<p>With that in mind, I came across a service that fulfills all the requirements: <a href="https://www.usebruno.com/">bruno</a>.</p>
<h2 id="what-is-bruno">What is Bruno</h2>
<p>Bruno is an open-source Postman alternative that aims to provide a seamless offline experience for testing APIs.</p>
<p>It also plays nicely with Git by using a <a href="https://www.usebruno.com/bru">markdown language, Bru</a>, for defining collections.</p>
<h2 id="installing-bruno">Installing Bruno</h2>
<p>For MacOS users, installing <code>bruno</code> is easy with <code>brew</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">brew install bruno</span></span></code></pre></div><p>It&rsquo;s also supported in many other popular package managers:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># On Windows via Chocolatey</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">choco install bruno
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># On Windows via Scoop</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">scoop bucket add extras
</span></span><span class="line"><span class="ln">6</span><span class="cl">scoop install bruno
</span></span><span class="line"><span class="ln">7</span><span class="cl">
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="c1"># On Linux via Snap</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl">snap install bruno</span></span></code></pre></div><h2 id="migrating-from-postman">Migrating from Postman</h2>
<p>If you&rsquo;re planning to migrate from Postman to Bruno, there are import options for collections and environments. For me, it was as simple as exporting the collections/environments in JSON format and importing them.</p>
<h2 id="scripting-in-bruno">Scripting in Bruno</h2>
<p>Like Postman, Bruno offers scripting capabilities for automating your workflow. I do not use this feature in either solution, but there is <a href="https://docs.usebruno.com/scripting/introduction.html">more information about it in the Bruno documentation</a>.</p>
<h2 id="using-bruno-cli">Using Bruno CLI</h2>
<p>In this section, I will use <a href="https://catfact.ninja/">the Cat Fact API</a> as an example collection.</p>
<h3 id="installing-bruno-cli">Installing Bruno CLI</h3>
<p>Firstly, let&rsquo;s install the Bruno CLI using <code>npm</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">npm install -g @usebruno/cli</span></span></code></pre></div><h3 id="define-a-collection-for-catfacts">Define a collection for catfacts</h3>
<p>I opened Bruno and created a new collection named <code>Cat Facts API</code> with a single <code>GET</code> request named <code>Get Random Fact</code>.</p>
<p><img src="images/AAlbBK.webp" alt="The cat facts api collection shown in the Bruno desktop application"></p>
<p>When creating my collection, Bruno prompted me to select a folder to store my collection in.</p>
<p>That folder had this structure:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">catfacts
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── Get Random Fact.bru
</span></span><span class="line"><span class="ln">3</span><span class="cl">├── bruno.json
</span></span><span class="line"><span class="ln">4</span><span class="cl">└── environments
</span></span><span class="line"><span class="ln">5</span><span class="cl">    └── production.bru</span></span></code></pre></div><p><code>Get Random Fact.bru</code> had file contents like this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">meta {
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  name: Get Random Fact
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  type: http
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  seq: 1
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">}
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">get {
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">  url: {{baseUrl}}/fact
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">  body: none
</span></span><span class="line"><span class="ln">10</span><span class="cl">  auth: none
</span></span><span class="line"><span class="ln">11</span><span class="cl">}</span></span></code></pre></div><p><code>bruno.json</code> had file contents like this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{
</span></span><span class="line"><span class="ln">2</span><span class="cl">  &#34;version&#34;: &#34;1&#34;,
</span></span><span class="line"><span class="ln">3</span><span class="cl">  &#34;name&#34;: &#34;Cat Facts API&#34;,
</span></span><span class="line"><span class="ln">4</span><span class="cl">  &#34;type&#34;: &#34;collection&#34;
</span></span><span class="line"><span class="ln">5</span><span class="cl">}</span></span></code></pre></div><p>and the <code>production.bru</code> file looked like this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">vars {
</span></span><span class="line"><span class="ln">2</span><span class="cl">  baseUrl: https://catfact.ninja
</span></span><span class="line"><span class="ln">3</span><span class="cl">}</span></span></code></pre></div><h3 id="invoke-a-collection-from-the-bruno-cli">Invoke a collection from the Bruno CLI</h3>
<p>I navigated to the collection folder and ran the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">bru run --env production</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Running Folder Recursively 
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl">Get Random Fact (200 OK) - 177 ms
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl">Requests:    1 passed, 1 total
</span></span><span class="line"><span class="ln">6</span><span class="cl">Tests:       0 passed, 0 total
</span></span><span class="line"><span class="ln">7</span><span class="cl">Assertions:  0 passed, 0 total
</span></span><span class="line"><span class="ln">8</span><span class="cl">Ran all requests - 177 ms</span></span></code></pre></div><p>This executes every <code>.bru</code> file in the folder.</p>
<p>Bruno additionally gives the ability to run single requests:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">bru run Get<span class="se">\ </span>Random<span class="se">\ </span>Fact.bru --env production</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Running Request 
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl">Get Random Fact (200 OK) - 175 ms
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl">Requests:    1 passed, 1 total
</span></span><span class="line"><span class="ln">6</span><span class="cl">Tests:       0 passed, 0 total
</span></span><span class="line"><span class="ln">7</span><span class="cl">Assertions:  0 passed, 0 total
</span></span><span class="line"><span class="ln">8</span><span class="cl">Ran all requests - 175 ms</span></span></code></pre></div>]]></content:encoded></item><item><title>Tagging in AWS CDK</title><link>https://how.wtf/tagging-in-aws-cdk.html</link><pubDate>Wed, 17 Jan 2024 00:45:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/tagging-in-aws-cdk.html</guid><description>Tags are key/value metadata that enable users to categorize their AWS infrastructure. This is useful for identifying groups of resources, monitoring cloud spending, creating reports, etc.
In this post, we&amp;rsquo;ll explore different methods for tagging infrastructure using the AWS CDK. The code samples are in Python, but the techniques are applicable to all languages.
Tagging constructs Constructs are the basic &amp;ldquo;building blocks&amp;rdquo; of the AWS CDK. They act as components and encapsulate necessary information for CloudFormation.</description><content:encoded><![CDATA[<p>Tags are <a href="https://aws.amazon.com/solutions/guidance/tagging-on-aws">key/value metadata</a> that enable users to categorize their AWS infrastructure. This is useful for identifying groups of resources, monitoring cloud spending, creating reports, etc.</p>
<p>In this post, we&rsquo;ll explore different methods for tagging infrastructure using the AWS CDK. The code samples are in Python, but the techniques are applicable to all languages.</p>
<h2 id="tagging-constructs">Tagging constructs</h2>
<p>Constructs are the <a href="https://docs.aws.amazon.com/cdk/v2/guide/constructs.html">basic &ldquo;building blocks&rdquo; of the AWS CDK</a>. They act as components and encapsulate necessary information for CloudFormation. Fortunately, the AWS CDK provides an easy-to-use API.</p>
<p>The standard method for tagging resources is:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">Tags</span><span class="o">.</span><span class="n">of</span><span class="p">(</span><span class="n">construct</span><span class="p">)</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&#34;key&#34;</span><span class="p">,</span> <span class="s2">&#34;value&#34;</span><span class="p">)</span></span></span></code></pre></div><h3 id="tag-resources-in-aws-cdk">Tag resources in AWS CDK</h3>
<p>As shown above, tagging an individual resource is easy.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_cdk</span> <span class="kn">import</span> <span class="n">App</span><span class="p">,</span> <span class="n">Stack</span><span class="p">,</span> <span class="n">Tags</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_cdk</span> <span class="kn">import</span> <span class="n">aws_iam</span> <span class="k">as</span> <span class="n">iam</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">class</span> <span class="nc">MyStack</span><span class="p">(</span><span class="n">Stack</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scope</span><span class="p">:</span> <span class="n">App</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">scope</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="n">my_role</span> <span class="o">=</span> <span class="n">iam</span><span class="o">.</span><span class="n">Role</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;role&#34;</span><span class="p">,</span> <span class="n">assumed_by</span><span class="o">=</span><span class="n">iam</span><span class="o">.</span><span class="n">AnyPrincipal</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="n">Tags</span><span class="o">.</span><span class="n">of</span><span class="p">(</span><span class="n">my_role</span><span class="p">)</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&#34;owner&#34;</span><span class="p">,</span> <span class="s2">&#34;team@example.com&#34;</span><span class="p">)</span></span></span></code></pre></div><p>A tag with &ldquo;owner&rdquo; and &ldquo;<a href="mailto:team@example.com">team@example.com</a>&rdquo; was added to the role construct.</p>
<h3 id="tag-stacks-in-aws-cdk">Tag stacks in AWS CDK</h3>
<p>Tagging a stack will apply tags to the stack construct <em>and</em> all resources within it.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_cdk</span> <span class="kn">import</span> <span class="n">App</span><span class="p">,</span> <span class="n">Tags</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">stack</span> <span class="kn">import</span> <span class="n">MyStack</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">app</span> <span class="o">=</span> <span class="n">App</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">my_stack</span> <span class="o">=</span> <span class="n">MyStack</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="s2">&#34;Stack&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">Tags</span><span class="o">.</span><span class="n">of</span><span class="p">(</span><span class="n">my_stack</span><span class="p">)</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&#34;owner&#34;</span><span class="p">,</span> <span class="s2">&#34;team@example.com&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">app</span><span class="o">.</span><span class="n">synth</span><span class="p">()</span></span></span></code></pre></div><p>A tag with &ldquo;owner&rdquo; and &ldquo;<a href="mailto:team@example.com">team@example.com</a>&rdquo; was added to the stack construct and all constructs within the stack.</p>
<h3 id="tag-apps-using-aws-cdk">Tag apps using AWS CDK</h3>
<p>Like the previous example, tagging an app will auto tag the sub-constructs as well.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_cdk</span> <span class="kn">import</span> <span class="n">App</span><span class="p">,</span> <span class="n">Tags</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">stack</span> <span class="kn">import</span> <span class="n">MyStack</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">app</span> <span class="o">=</span> <span class="n">App</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">my_stack</span> <span class="o">=</span> <span class="n">MyStack</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="s2">&#34;Stack&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">Tags</span><span class="o">.</span><span class="n">of</span><span class="p">(</span><span class="n">app</span><span class="p">)</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&#34;owner&#34;</span><span class="p">,</span> <span class="s2">&#34;team@example.com&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">app</span><span class="o">.</span><span class="n">synth</span><span class="p">()</span></span></span></code></pre></div><p>A tag with &ldquo;owner&rdquo; and &ldquo;<a href="mailto:team@example.com">team@example.com</a>&rdquo; was added to the app construct and all constructs within the app.</p>
<h3 id="tag-stacks-using-aws-cdk-cli">Tag stacks using AWS CDK CLI</h3>
<p>If you prefer specifying a tag at <code>cdk deploy</code> time, the <code>--tags</code> flag is available:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">cdk deploy Stack <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --tags <span class="nv">owner</span><span class="o">=</span>team@example.com <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --tags <span class="nv">department</span><span class="o">=</span>engineering</span></span></code></pre></div><p>With the command above, two tags were applied to a stack named <code>Stack</code>.</p>
<h3 id="tag-stacks-using-aws-cdk-cdkjson-file">Tag stacks using AWS CDK cdk.json file</h3>
<p>An alternative to the command line flag is using the <code>cdk.json</code> file to specify deploy time tags.</p>
<p>Simply add the <code>tags</code> key to your <code>cdk.json</code> file with your tags defined in an array:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;app&#34;</span><span class="p">:</span> <span class="s2">&#34;python3 app.py&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  <span class="nt">&#34;tags&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">      <span class="nt">&#34;Key&#34;</span><span class="p">:</span> <span class="s2">&#34;owner&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">      <span class="nt">&#34;Value&#34;</span><span class="p">:</span> <span class="s2">&#34;team@example.com&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">      <span class="nt">&#34;Key&#34;</span><span class="p">:</span> <span class="s2">&#34;department&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">      <span class="nt">&#34;Value&#34;</span><span class="p">:</span> <span class="s2">&#34;engineering&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="duplicate-tags-in-aws-cdk">Duplicate tags in AWS CDK</h2>
<p>Occasionally, there may be duplicate tags applied to the same resource.</p>
<p>To control which tags overwrite others, a <code>priority</code> parameter can be supplied to the <code>add</code> method. By default, all tags applied have a 100 priority.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_cdk</span> <span class="kn">import</span> <span class="n">App</span><span class="p">,</span> <span class="n">Tags</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">stack</span> <span class="kn">import</span> <span class="n">MyStack</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">app</span> <span class="o">=</span> <span class="n">App</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">my_stack</span> <span class="o">=</span> <span class="n">MyStack</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="s2">&#34;Stack&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">Tags</span><span class="o">.</span><span class="n">of</span><span class="p">(</span><span class="n">my_stack</span><span class="p">)</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&#34;owner&#34;</span><span class="p">,</span> <span class="s2">&#34;team2@example.com&#34;</span><span class="p">,</span> <span class="n">priority</span><span class="o">=</span><span class="mi">101</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="n">Tags</span><span class="o">.</span><span class="n">of</span><span class="p">(</span><span class="n">my_stack</span><span class="p">)</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&#34;owner&#34;</span><span class="p">,</span> <span class="s2">&#34;team@example.com&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">app</span><span class="o">.</span><span class="n">synth</span><span class="p">()</span></span></span></code></pre></div><p>If both stacks have a priority of <code>100</code> – <a href="https://docs.aws.amazon.com/cdk/v2/guide/tagging.html#w53aac21c26c25">the bottom-most tag</a> on the construct tree wins. In this case, the <code>101</code> priority superseded the bottom-most call.</p>
]]></content:encoded></item><item><title>A guide for deploying CloudFormation with CLI using Rain</title><link>https://how.wtf/a-guide-for-deploying-cloudformation-with-cli-using-rain.html</link><pubDate>Sun, 14 Jan 2024 15:35:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/a-guide-for-deploying-cloudformation-with-cli-using-rain.html</guid><description>Last year, I wrote a post describing the difference between aws cloudformation deploy and aws cloudformation create-stack. I concluded that the easiest method for deploying CloudFormation templates was cloudformation deploy since it handled change sets on your behalf.
My opinion has changed; I discovered a new tool named Rain that is maintained by AWS.
What is Rain For folks needing to deploy raw CloudFormation templates, rain is your hero. The tool brings you a lot of power:</description><content:encoded><![CDATA[<p>Last year, I <a href="https://how.wtf/cloudformation-create-stack-vs-deploy-in-aws-cli.html">wrote a post</a> describing the difference between <code>aws cloudformation deploy</code> and <code>aws cloudformation create-stack</code>. I concluded that the easiest method for deploying CloudFormation templates was <code>cloudformation deploy</code> since it handled change sets on your behalf.</p>
<p>My opinion has changed; I discovered a <a href="https://github.com/aws-cloudformation/rain">new tool named Rain</a> that is maintained by AWS.</p>
<h2 id="what-is-rain">What is Rain</h2>
<p>For folks needing to deploy raw CloudFormation templates, rain is your hero. The tool brings you a lot of power:</p>
<ol>
<li>Allows input parameters</li>
<li>Showcases real-time updates for stack deployments</li>
<li>Filters deployment logs sensibly</li>
<li>Provides the ability to generate CloudFormation templates via AI</li>
<li>Manipulates stack sets</li>
<li>Formats template files</li>
</ol>
<p>And <a href="https://github.com/aws-cloudformation/rain?tab=readme-ov-file#key-features">many more features</a>! As a previous user of CloudFormation, this tool appears amazing.</p>
<h2 id="installing-rain">Installing Rain</h2>
<p>There are a few options for installing Rain, but I&rsquo;ll use the <code>golang</code> install for this tutorial.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">go install github.com/aws-cloudformation/rain/cmd/rain@latest</span></span></code></pre></div><p>For MacOS users, <code>brew</code> is easy:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">brew install rain</span></span></code></pre></div><p>The remaining releases are <a href="https://github.com/aws-cloudformation/rain/releases">featured in their GitHub repository</a>.</p>
<h2 id="build-cloudformation-stacks-using-rain">Build CloudFormation stacks using Rain</h2>
<p>The <a href="https://aws-cloudformation.github.io/rain/rain_build.html">build command</a> accepts a prompt parameter to generate CloudFormation templates using AI. Let&rsquo;s use it for generating a CloudFormation template with a S3 bucket.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">rain build -p <span class="s2">&#34;A s3 bucket that is secure&#34;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nt">AWSTemplateFormatVersion</span><span class="p">:</span><span class="w"> </span><span class="ld">2010-09-09</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="nt">Description</span><span class="p">:</span><span class="w"> </span><span class="l">Create an S3 bucket</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="nt">Resources</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">  </span><span class="nt">MyS3Bucket</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="l">AWS::S3::Bucket</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">      </span><span class="nt">BucketName</span><span class="p">:</span><span class="w"> </span><span class="l">my-secure-bucket</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">      </span><span class="nt">AccessControl</span><span class="p">:</span><span class="w"> </span><span class="l">Private</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">      </span><span class="nt">VersioningConfiguration</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">        </span><span class="nt">Status</span><span class="p">:</span><span class="w"> </span><span class="l">Enabled</span></span></span></code></pre></div><p>Although the <code>AccessControl</code> <a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-s3-bucket.html#cfn-s3-bucket-accesscontrol">property is a considered legacy</a>, it&rsquo;s great that the template was generated on my behalf!</p>
<p>In addition, the <code>build</code> property will generate a skeleton for resources as well:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">rain build AWS::Route53::CidrCollection</span></span></code></pre></div><p>or</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">rain build CidrCollection</span></span></code></pre></div><p>This outputs a template with all the parameters and dummy <code>CHANGEME</code> values for a Route53 CIDR collection:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nt">AWSTemplateFormatVersion</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;2010-09-09&#34;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="nt">Description</span><span class="p">:</span><span class="w"> </span><span class="l">Template generated by rain</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w"></span><span class="nt">Resources</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">  </span><span class="nt">MyCidrCollection</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="l">AWS::Route53::CidrCollection</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">      </span><span class="nt">Locations</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">        </span>- <span class="nt">CidrList</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">            </span>- <span class="l">CHANGEME</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">          </span><span class="nt">LocationName</span><span class="p">:</span><span class="w"> </span><span class="l">CHANGEME</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">      </span><span class="nt">Name</span><span class="p">:</span><span class="w"> </span><span class="l">CHANGEME</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w"></span><span class="nt">Outputs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">  </span><span class="nt">MyCidrCollectionArn</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">    </span><span class="nt">Value</span><span class="p">:</span><span class="w"> </span>!<span class="l">GetAtt MyCidrCollection.Arn</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">  </span><span class="nt">MyCidrCollectionId</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">    </span><span class="nt">Value</span><span class="p">:</span><span class="w"> </span>!<span class="l">GetAtt MyCidrCollection.Id</span></span></span></code></pre></div><p>If you prefer <code>json</code>, there&rsquo;s a flag for that:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">rain build CidrCollection --json</span></span></code></pre></div><p>If you supply the command an ambigious term like &ldquo;collection&rdquo;, it provides you a warning:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">rain build collection</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Ambiguous resource type &#39;collection&#39;; could be any of:
</span></span><span class="line"><span class="ln">2</span><span class="cl">  AWS::DevOpsGuru::ResourceCollection
</span></span><span class="line"><span class="ln">3</span><span class="cl">  AWS::Location::GeofenceCollection
</span></span><span class="line"><span class="ln">4</span><span class="cl">  AWS::OpenSearchServerless::Collection
</span></span><span class="line"><span class="ln">5</span><span class="cl">  AWS::Rekognition::Collection
</span></span><span class="line"><span class="ln">6</span><span class="cl">  AWS::Route53::CidrCollection</span></span></code></pre></div><h2 id="bootstrap-using-rain">Bootstrap using Rain</h2>
<p>Before deploying stacks into an environment, let&rsquo;s run the bootstrap command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">rain bootstrap</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Rain needs to create an S3 bucket called &#39;rain-artifacts-012345678901-us-east-1&#39;. Continue? (Y/n)</span></span></code></pre></div><p>This command creates an artifacts bucket that <code>rain</code> references when deploying stacks.</p>
<p>It has the following naming convention:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">rain-artifacts-{accountId}-{regionName}</span></span></code></pre></div><h2 id="deploying-stacks-using-rain">Deploying stacks using Rain</h2>
<p>In this section, we&rsquo;ll explore deploying templates with <code>rain</code>.</p>
<h3 id="deploying-an-s3-bucket">Deploying an S3 bucket</h3>
<p>Using the S3 template <code>rain build</code> generated, let&rsquo;s deploy it!</p>
<p>This is my current directory structure:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">project
</span></span><span class="line"><span class="ln">2</span><span class="cl">└── s3.yml</span></span></code></pre></div><p>This is the command I&rsquo;ll use to deploy the <code>s3.yml</code> with a stack name of <code>s3-bucket-stack</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">rain deploy s3.yml s3-bucket-stack</span></span></code></pre></div><p>If <code>rain bootstrap</code> was not executed before deploying, it&rsquo;ll prompt you to do so.</p>
<p>My deployment failed with the following message:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">CloudFormation will make the following changes:
</span></span><span class="line"><span class="ln">2</span><span class="cl">Stack s3-bucket-stack:
</span></span><span class="line"><span class="ln">3</span><span class="cl">  + AWS::S3::Bucket MyS3Bucket
</span></span><span class="line"><span class="ln">4</span><span class="cl">Do you wish to continue? (Y/n)
</span></span><span class="line"><span class="ln">5</span><span class="cl">Deploying template &#39;s3.yml&#39; as stack &#39;s3-bucket-stack&#39; in us-east-1.
</span></span><span class="line"><span class="ln">6</span><span class="cl">Stack s3-bucket-stack: ROLLBACK_COMPLETE
</span></span><span class="line"><span class="ln">7</span><span class="cl">Messages:
</span></span><span class="line"><span class="ln">8</span><span class="cl">  - MyS3Bucket: Resource handler returned message: &#34;my-secure-bucket already exists (Service: S3, Status Code: 0, Request ID: null)&#34; (RequestToken: c4a528c1-2fa0-e75e-efb1-5cfacc2aebd6, HandlerErrorCode: AlreadyExists)
</span></span><span class="line"><span class="ln">9</span><span class="cl">failed deploying stack &#39;s3-bucket-stack&#39;</span></span></code></pre></div><p>Since S3 is a global service, the bucket name <code>my-secure-bucket</code> exists in another account or region. I modified the <code>BucketName</code> to be <code>how-wtf-rain-bucket</code> and issued the same command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Deleted existing, empty stack.
</span></span><span class="line"><span class="ln">2</span><span class="cl">CloudFormation will make the following changes:
</span></span><span class="line"><span class="ln">3</span><span class="cl">Stack s3-bucket-stack:
</span></span><span class="line"><span class="ln">4</span><span class="cl">  + AWS::S3::Bucket MyS3Bucket
</span></span><span class="line"><span class="ln">5</span><span class="cl">Do you wish to continue? (Y/n)
</span></span><span class="line"><span class="ln">6</span><span class="cl">Deploying template &#39;s3.yml&#39; as stack &#39;s3-bucket-stack&#39; in us-east-1.
</span></span><span class="line"><span class="ln">7</span><span class="cl">Stack s3-bucket-stack: CREATE_COMPLETE
</span></span><span class="line"><span class="ln">8</span><span class="cl">Successfully deployed s3-bucket-stack</span></span></code></pre></div><p>A couple of awesome things to note:</p>
<ol>
<li>It handled the failure of the stack gracefully <em>and</em> gave me the exact issue</li>
<li>I deployed again and it took care of <em>everything</em></li>
<li>I did this all without touching the AWS console.</li>
</ol>
<p>I am impressed by this tool already!</p>
<h3 id="deploying-a-lambda-function">Deploying a Lambda function</h3>
<p>I want to test the <code>rain pkg</code> command with lambda artifacts. Like the <code>cloudformation package</code> command, we specify a lambda directory <em>or</em> handler and it&rsquo;ll handle zipping and uploading it!</p>
<p>I created a file named <code>lambda.yml</code> with the following contents:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nt">AWSTemplateFormatVersion</span><span class="p">:</span><span class="w"> </span><span class="ld">2010-09-09</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="nt">Description</span><span class="p">:</span><span class="w"> </span><span class="l">Create an lambda function</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="nt">Resources</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">  </span><span class="nt">LambdaExecutionRole</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="l">AWS::IAM::Role</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">      </span><span class="nt">AssumeRolePolicyDocument</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">        </span><span class="nt">Version</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;2012-10-17&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">        </span><span class="nt">Statement</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">          </span>- <span class="nt">Effect</span><span class="p">:</span><span class="w"> </span><span class="l">Allow</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">            </span><span class="nt">Principal</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">              </span><span class="nt">Service</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">                </span>- <span class="l">lambda.amazonaws.com</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">            </span><span class="nt">Action</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">              </span>- <span class="l">sts:AssumeRole</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">      </span><span class="nt">ManagedPolicyArns</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">        </span>- <span class="l">arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">  </span><span class="nt">MyLambdaFunction</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">    </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="l">AWS::Lambda::Function</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">    </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">      </span><span class="nt">Code</span><span class="p">:</span><span class="w"> </span><span class="l">lambdafunction/</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">      </span><span class="nt">FunctionName</span><span class="p">:</span><span class="w"> </span><span class="l">MyLovelyFunction</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">      </span><span class="nt">Handler</span><span class="p">:</span><span class="w"> </span><span class="l">index.handler</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">      </span><span class="nt">Role</span><span class="p">:</span><span class="w"> </span>!<span class="l">GetAtt LambdaExecutionRole.Arn </span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">      </span><span class="nt">Runtime</span><span class="p">:</span><span class="w"> </span><span class="l">python3.12</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w"></span><span class="nt">Outputs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">  </span><span class="nt">LambdaFunctionArn</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">    </span><span class="nt">Description</span><span class="p">:</span><span class="w"> </span><span class="l">The ARN of the Lambda function</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">    </span><span class="nt">Value</span><span class="p">:</span><span class="w"> </span>!<span class="l">GetAtt MyLambdaFunction.Arn</span></span></span></code></pre></div><p>This stack creates two resources:</p>
<ol>
<li>A lambda execution role with basic permissions granted by the <code>AWSLambdaBasicExecutionRole</code> policy</li>
<li>A lambda function with the <code>lambdafunction/</code> contents</li>
</ol>
<p>And outputs the lambda function arn.</p>
<p>I ran the <code>fmt</code> command with the <code>--verify</code> flag:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">rain fmt lambda.yml --verify</span></span></code></pre></div><p>The <code>--verify</code> command is best saved for CI environments since it outputs a 0 or 1 depending if the formatting is correct.</p>
<p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">lambda.yml: would reformat</span></span></code></pre></div><p>I ran it with the <code>--write</code> command so that it fixed them:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">rain fmt lambda.yml --write</span></span></code></pre></div><p>Let&rsquo;s run the <code>pkg</code> command with an output file named <code>out.yml</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">rain pkg lambda.yml --output out.yml</span></span></code></pre></div><p>Here is a snapshot of my directory structure after doing the <code>pkg</code> command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">project
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── lambda.yml
</span></span><span class="line"><span class="ln">3</span><span class="cl">├── lambdafunction
</span></span><span class="line"><span class="ln">4</span><span class="cl">│   └── index.py
</span></span><span class="line"><span class="ln">5</span><span class="cl">└── out.yml</span></span></code></pre></div><p>Now let&rsquo;s deploy the <code>out.yml</code> template:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">rain deploy out.yml lambda-function-stack</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">CloudFormation will make the following changes:
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">Stack lambda-function-stack:
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  + AWS::IAM::Role LambdaExecutionRole
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  + AWS::Lambda::Function MyLambdaFunction
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">Do you wish to continue? (Y/n)
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">Deploying template &#39;out.yml&#39; as stack &#39;lambda-function-stack&#39; in us-east-1.
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">Stack lambda-function-stack: CREATE_COMPLETE
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">  Outputs:
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    LambdaFunctionArn: arn:aws:lambda:us-east-1:012345678901:function:MyLovelyFunction # The ARN of the Lambda function
</span></span><span class="line"><span class="ln">10</span><span class="cl">Successfully deployed lambda-function-stack</span></span></code></pre></div><p>Using the <code>LambdaFunctionArn</code> output, let&rsquo;s invoke the function to ensure everything worked correctly:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws lambda invoke --function-name MyLovelyFunction response.txt</span></span></code></pre></div><p>Here is the resulting <code>response.txt</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">&#34;Hello world!&#34;</span></span></code></pre></div><h2 id="view-logs-of-deployments">View logs of deployments</h2>
<p>Another powerful feature of <code>rain</code> is that it can display <em>sensible</em> logs for stack deployments.</p>
<h3 id="using-log-command">Using log command</h3>
<p>Using the lambda function stack from the prior section, we can inspect the logs using the <code>log</code> command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">rain log lambda-function-stack</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">No interesting log messages to display. To see everything, use the --all flag</span></span></code></pre></div><p>Since there were no &ldquo;interesting&rdquo; log messages to display, let&rsquo;s see them all!</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">rain log lambda-function-stack --all</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Jan 14 20:08:52 lambda-function-stack/lambda-function-stack (AWS::CloudFormation::Stack) CREATE_COMPLETE
</span></span><span class="line"><span class="ln">2</span><span class="cl">Jan 14 20:08:50 lambda-function-stack/MyLambdaFunction (AWS::Lambda::Function) CREATE_COMPLETE
</span></span><span class="line"><span class="ln">3</span><span class="cl">Jan 14 20:08:43 lambda-function-stack/MyLambdaFunction (AWS::Lambda::Function) CREATE_IN_PROGRESS &#34;Resource creation Initiated&#34;
</span></span><span class="line"><span class="ln">4</span><span class="cl">Jan 14 20:08:42 lambda-function-stack/MyLambdaFunction (AWS::Lambda::Function) CREATE_IN_PROGRESS
</span></span><span class="line"><span class="ln">5</span><span class="cl">Jan 14 20:08:40 lambda-function-stack/LambdaExecutionRole (AWS::IAM::Role) CREATE_COMPLETE
</span></span><span class="line"><span class="ln">6</span><span class="cl">Jan 14 20:08:24 lambda-function-stack/LambdaExecutionRole (AWS::IAM::Role) CREATE_IN_PROGRESS &#34;Resource creation Initiated&#34;
</span></span><span class="line"><span class="ln">7</span><span class="cl">Jan 14 20:08:22 lambda-function-stack/LambdaExecutionRole (AWS::IAM::Role) CREATE_IN_PROGRESS
</span></span><span class="line"><span class="ln">8</span><span class="cl">Jan 14 20:08:19 lambda-function-stack/lambda-function-stack (AWS::CloudFormation::Stack) CREATE_IN_PROGRESS &#34;User Initiated&#34;
</span></span><span class="line"><span class="ln">9</span><span class="cl">Jan 14 20:08:12 lambda-function-stack/lambda-function-stack (AWS::CloudFormation::Stack) REVIEW_IN_PROGRESS &#34;User Initiated&#34;</span></span></code></pre></div><h3 id="generating-gantt-chart-for-deployment-times">Generating Gantt chart for deployment times</h3>
<p>Another cool feature is viewing the Gantt chart for the deployment times of different resources:</p>





<pre tabindex="0"><code>rain log lambda-function-stack --chart &gt; chart.html</code></pre><p>Here is the resulting html page:</p>
<p><img src="images/ubJUKT.webp" alt="Gantt chart displaying deployment times for various resources using Rain"></p>
<h2 id="destroying-stacks-using-rain">Destroying stacks using Rain</h2>
<p>Using the prior sections&rsquo; stacks, let&rsquo;s use the <code>rm</code> command to showcase the stack deletion process:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">rain rm lambda-function-stack</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Stack lambda-function-stack: CREATE_COMPLETE
</span></span><span class="line"><span class="ln">2</span><span class="cl">Are you sure you want to delete this stack? (y/N) y
</span></span><span class="line"><span class="ln">3</span><span class="cl">Successfully deleted stack &#39;lambda-function-stack&#39;</span></span></code></pre></div><p>and the S3 bucket stack with the <code>-y</code> so that we don&rsquo;t have to confirm again:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">rain rm s3-bucket-stack -y</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Successfully deleted stack &#39;s3-bucket-stack&#39;</span></span></code></pre></div><h2 id="other-features">Other features</h2>
<p>There are other features not covered in this guide:</p>
<ol>
<li>Stack sets</li>
<li>Forecasting errors using <code>rain forecast</code> (experimental)</li>
<li>Using rain&rsquo;s instrinsic functions &amp; modules (experimental)</li>
</ol>
<p>As previously stated, if you need to work with raw CloudFormation - give this tool a try!</p>
]]></content:encoded></item><item><title>Implement version control in DynamoDB</title><link>https://how.wtf/implement-version-control-in-dynamodb.html</link><pubDate>Sat, 13 Jan 2024 12:30:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/implement-version-control-in-dynamodb.html</guid><description>Amazon DynamoDB is a fully managed service provided by AWS that enables developers to quickly store data for their applications. In this article, I will showcase how to implement version control in DynamoDB for recording changes to data over time.
What is version control in DynamoDB DynamoDB does not support native version control on a per-item basis. If you need to record changes to your data over time, it must be handled via the application.</description><content:encoded><![CDATA[<p>Amazon DynamoDB is a fully managed service provided by AWS that enables developers to quickly store data for their applications. In this article, I will showcase how to implement version control in DynamoDB for recording changes to data over time.</p>
<h2 id="what-is-version-control-in-dynamodb">What is version control in DynamoDB</h2>
<p>DynamoDB does not support native version control on a per-item basis. If you need to record changes to your data over time, it must be handled via the application. Luckily, there is a paradigm that supports storing multiple versions of the same data: duplication.</p>
<h2 id="how-to-implement-versioning-in-dynamodb">How to implement versioning in DynamoDB</h2>
<p>We have a few options for storing versioned data in DynamoDB. For the purposes of this tutorial, we will use a <strong>single table</strong> design: i.e., using a primary key and a sort key to manage multiple data types.</p>
<h2 id="creating-a-table-with-versioning-in-dynamodb">Creating a table with versioning in DynamoDB</h2>
<p>For the remaining sections of this tutorial, we&rsquo;ll leverage the same single table.</p>
<h3 id="create-a-table">Create a table</h3>
<p>To begin, let&rsquo;s define a table using the AWS CLI:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln"> 1</span><span class="cl">aws dynamodb create-table <span class="se">\
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="se"></span>    --table-name table <span class="se">\
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="se"></span>    --attribute-definitions <span class="se">\
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="se"></span>        <span class="nv">AttributeName</span><span class="o">=</span>PK,AttributeType<span class="o">=</span>S <span class="se">\
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="se"></span>        <span class="nv">AttributeName</span><span class="o">=</span>SK,AttributeType<span class="o">=</span>S <span class="se">\
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="se"></span>    --key-schema <span class="se">\
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="se"></span>        <span class="nv">AttributeName</span><span class="o">=</span>PK,KeyType<span class="o">=</span>HASH <span class="se">\
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="se"></span>        <span class="nv">AttributeName</span><span class="o">=</span>SK,KeyType<span class="o">=</span>RANGE <span class="se">\
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="se"></span>    --provisioned-throughput <span class="se">\
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="se"></span>        <span class="nv">ReadCapacityUnits</span><span class="o">=</span>5,WriteCapacityUnits<span class="o">=</span><span class="m">5</span></span></span></code></pre></div><p>I specified a primary key named <code>PK</code> and a sort key of <code>SK</code>.</p>
<h3 id="time-versioning">Time versioning</h3>
<p>Time-based versioning may be useful for applications that need to store the status of data at certain timed intervals.</p>
<p><img src="images/HSkq9c.webp" alt="DynamoDB key structure for time-based versioning"></p>
<h4 id="inserting-example-data">Inserting example data</h4>
<p>To showcase the power of DynamoDB, let&rsquo;s insert some values for a file object with an identifier of 1.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb put-item <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name table <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --item <span class="s1">&#39;{&#34;PK&#34;:{&#34;S&#34;:&#34;file#1&#34;},&#34;SK&#34;:{&#34;S&#34;:&#34;2024-01-13T11:25:27-05:00&#34;}}&#39;</span></span></span></code></pre></div><p>and another:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb put-item <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name table <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --item <span class="s1">&#39;{&#34;PK&#34;:{&#34;S&#34;:&#34;file#1&#34;},&#34;SK&#34;:{&#34;S&#34;:&#34;2024-01-13T11:32:13-05:00&#34;}}&#39;</span></span></span></code></pre></div><p>and one more:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb put-item <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name table <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --item <span class="s1">&#39;{&#34;PK&#34;:{&#34;S&#34;:&#34;file#1&#34;},&#34;SK&#34;:{&#34;S&#34;:&#34;2024-01-13T11:37:58-05:00&#34;}}&#39;</span></span></span></code></pre></div><h4 id="query-for-latest-versions">Query for latest versions</h4>
<p>Because the timestamps are sortable, we can leverage DynamoDB to perform the following requests:</p>
<ol>
<li>Grab the last 100 versions</li>
<li>Grab all the versions by a specific interval (year, month, day, etc.)</li>
</ol>
<p><strong>Grab the latest 100 versions (or up to the DynamoDB limits):</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb query <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name table <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --key-condition-expression <span class="s2">&#34;PK=:pk&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>    --expression-attribute-values <span class="s1">&#39;{&#34;:pk&#34;:{&#34;S&#34;:&#34;file#1&#34;}}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>    --no-scan-index-forward</span></span></code></pre></div><p>The <code>--no-scan-index-forward</code> flag is important to sort the records in descending order rather than the default of ascending.</p>
<p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="nt">&#34;Items&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">            <span class="nt">&#34;PK&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;file#1&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">            <span class="nt">&#34;SK&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;2024-01-13T11:37:58-05:00&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">            <span class="nt">&#34;PK&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;file#1&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="nt">&#34;SK&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;2024-01-13T11:32:13-05:00&#34;</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">            <span class="nt">&#34;PK&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;file#1&#34;</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">            <span class="nt">&#34;SK&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;2024-01-13T11:25:27-05:00&#34;</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">    <span class="nt">&#34;Count&#34;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">    <span class="nt">&#34;ScannedCount&#34;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">    <span class="nt">&#34;ConsumedCapacity&#34;</span><span class="p">:</span> <span class="kc">null</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p><strong>Grab all versions by a specific interval</strong>:</p>
<p>Using the <code>begins_with</code> or <code>between</code> operators, we can query for specific dates.</p>
<p>In the case below, I want to query everything that starts with <code>2024-01-13T11:3</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb query <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name table <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --key-condition-expression <span class="s2">&#34;PK=:pk and begins_with(SK, :sk)&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>    --expression-attribute-values <span class="s1">&#39;{&#34;:pk&#34;:{&#34;S&#34;:&#34;file#1&#34;},&#34;:sk&#34;:{&#34;S&#34;:&#34;2024-01-13T11:3&#34;}}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>    --no-scan-index-forward</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="nt">&#34;Items&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">            <span class="nt">&#34;PK&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;file#1&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">            <span class="nt">&#34;SK&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;2024-01-13T11:37:58-05:00&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">            <span class="nt">&#34;PK&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;file#1&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="nt">&#34;SK&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;2024-01-13T11:32:13-05:00&#34;</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="nt">&#34;Count&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">    <span class="nt">&#34;ScannedCount&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">    <span class="nt">&#34;ConsumedCapacity&#34;</span><span class="p">:</span> <span class="kc">null</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h3 id="number-versioning">Number versioning</h3>
<p>For applications that want to maintain a &ldquo;latest&rdquo; version with the ability to rollback to a prior version, a number-based versioning paradigm will be optimal.</p>
<p><img src="images/Vdqrh1.webp" alt="DynamoDB key structure for number-based versioning"></p>
<h4 id="inserting-example-data-1">Inserting example data</h4>
<p>To showcase the power of DynamoDB, let&rsquo;s insert some values for a file object with an identifier of 2 and 2 different versions.</p>
<p>The first item will be the <code>metadata</code> for <code>file#2</code>. This contains the attributes for the <code>file#2</code> when the application needs to fetch the latest version with the appropriate values.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb put-item <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name table <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --item <span class="s1">&#39;{&#34;PK&#34;:{&#34;S&#34;:&#34;file#2&#34;},&#34;SK&#34;:{&#34;S&#34;:&#34;metadata&#34;},&#34;version&#34;:{&#34;S&#34;:&#34;2&#34;},&#34;foo&#34;:{&#34;S&#34;:&#34;baz&#34;}}&#39;</span></span></span></code></pre></div><p>The second item will contain version 1&rsquo;s information.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb put-item <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name table <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --item <span class="s1">&#39;{&#34;PK&#34;:{&#34;S&#34;:&#34;file#2&#34;},&#34;SK&#34;:{&#34;S&#34;:&#34;version#1&#34;},&#34;version&#34;:{&#34;S&#34;:&#34;1&#34;},&#34;foo&#34;:{&#34;S&#34;:&#34;bar&#34;}}&#39;</span></span></span></code></pre></div><p>The third item will contain version 2&rsquo;s information.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb put-item <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name table <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --item <span class="s1">&#39;{&#34;PK&#34;:{&#34;S&#34;:&#34;file#2&#34;},&#34;SK&#34;:{&#34;S&#34;:&#34;version#2&#34;},&#34;version&#34;:{&#34;S&#34;:&#34;2&#34;},&#34;foo&#34;:{&#34;S&#34;:&#34;baz&#34;}}&#39;</span></span></span></code></pre></div><p>For this method, we duplicate the attributes and values of <code>version#2</code> onto the main <code>metadata</code> object.</p>
<h4 id="query-for-latest-versions-1">Query for latest versions</h4>
<p>Let&rsquo;s query for all versions:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb query <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name table <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --key-condition-expression <span class="s2">&#34;PK=:pk and begins_with(SK, :sk)&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>    --expression-attribute-values <span class="s1">&#39;{&#34;:pk&#34;:{&#34;S&#34;:&#34;file#2&#34;},&#34;:sk&#34;:{&#34;S&#34;:&#34;version#&#34;}}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>    --no-scan-index-forward</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="nt">&#34;Items&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">            <span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;2&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">            <span class="nt">&#34;SK&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;version#2&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">            <span class="nt">&#34;PK&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;file#2&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">            <span class="nt">&#34;foo&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;baz&#34;</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">            <span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">            <span class="nt">&#34;SK&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;version#1&#34;</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">            <span class="nt">&#34;PK&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;file#2&#34;</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">            <span class="nt">&#34;foo&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">                <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;bar&#34;</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">    <span class="nt">&#34;Count&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">    <span class="nt">&#34;ScannedCount&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">    <span class="nt">&#34;ConsumedCapacity&#34;</span><span class="p">:</span> <span class="kc">null</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>The user decides they want <code>version#1</code> to be the selected version for <code>file#2</code>. To satisfy the request perform the following steps:</p>
<ol>
<li>Modify the <code>metadata</code> item&rsquo;s <code>version</code> attribute to <code>1</code></li>
<li>Duplicate the version&rsquo;s attributes onto the <code>metadata</code> item</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb put-item <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name table <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --item <span class="s1">&#39;{&#34;PK&#34;:{&#34;S&#34;:&#34;file#2&#34;},&#34;SK&#34;:{&#34;S&#34;:&#34;metadata&#34;},&#34;version&#34;:{&#34;S&#34;:&#34;1&#34;},&#34;foo&#34;:{&#34;S&#34;:&#34;bar&#34;}}&#39;</span></span></span></code></pre></div><p>Next time we fetch the latest version it&rsquo;ll point to version 1:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb get-item <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name table <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --key <span class="s1">&#39;{&#34;PK&#34;:{&#34;S&#34;:&#34;file#2&#34;},&#34;SK&#34;:{&#34;S&#34;:&#34;metadata&#34;}}&#39;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="nt">&#34;Item&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">            <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="nt">&#34;SK&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">            <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;metadata&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="nt">&#34;PK&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">            <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;file#2&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="nt">&#34;foo&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">            <span class="nt">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;bar&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Create IAM role with multiple principals in AWS CDK</title><link>https://how.wtf/create-iam-role-with-multiple-principals-in-aws-cdk.html</link><pubDate>Wed, 10 Jan 2024 01:40:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/create-iam-role-with-multiple-principals-in-aws-cdk.html</guid><description>I need to create an IAM role that is assumable by multiple principals, but the AWS CDK role creation documentation only lists the following example:
1lambda_role = iam.Role(self, &amp;#34;Role&amp;#34;, 2 assumed_by=iam.ServicePrincipal(&amp;#34;lambda.amazonaws.com&amp;#34;), 3 description=&amp;#34;Example role...&amp;#34; 4) 5 6stream = kinesis.Stream(self, &amp;#34;MyEncryptedStream&amp;#34;, 7 encryption=kinesis.StreamEncryption.KMS 8) 9 10stream.grant_read(lambda_role)That works great, but how do I list multiple principals?
Specifying multiple principals for IAM role Luckily, there is a solution: the CompositePrincipal.
How to use the composite principal with AWS CDK The CompositePrincipal class enables developers to pass in variadic arguments of type IPrincipal.</description><content:encoded><![CDATA[<p>I need to create an IAM role that is assumable by multiple principals, but the AWS CDK <a href="https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_iam/Role.html">role creation documentation</a> only lists the following example:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="n">lambda_role</span> <span class="o">=</span> <span class="n">iam</span><span class="o">.</span><span class="n">Role</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;Role&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="n">assumed_by</span><span class="o">=</span><span class="n">iam</span><span class="o">.</span><span class="n">ServicePrincipal</span><span class="p">(</span><span class="s2">&#34;lambda.amazonaws.com&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="n">description</span><span class="o">=</span><span class="s2">&#34;Example role...&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">stream</span> <span class="o">=</span> <span class="n">kinesis</span><span class="o">.</span><span class="n">Stream</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;MyEncryptedStream&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">encryption</span><span class="o">=</span><span class="n">kinesis</span><span class="o">.</span><span class="n">StreamEncryption</span><span class="o">.</span><span class="n">KMS</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">stream</span><span class="o">.</span><span class="n">grant_read</span><span class="p">(</span><span class="n">lambda_role</span><span class="p">)</span></span></span></code></pre></div><p>That works great, but how do I list multiple principals?</p>
<h2 id="specifying-multiple-principals-for-iam-role">Specifying multiple principals for IAM role</h2>
<p>Luckily, there is a solution: the <code>CompositePrincipal</code>.</p>
<h3 id="how-to-use-the-composite-principal-with-aws-cdk">How to use the composite principal with AWS CDK</h3>
<p>The <a href="https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_iam/CompositePrincipal.html"><code>CompositePrincipal</code> class</a> enables developers to pass in variadic arguments of type <code>IPrincipal</code>.</p>
<p>In the snippet of code below, I</p>
<ol>
<li>Create two roles that are assumable by the <code>{&quot;AWS&quot;: &quot;*&quot;}</code> principal.</li>
<li>Create a third role that contains a <code>CompositePrincipal</code> for both of the previous roles using <code>iam.ArnPrincipal</code></li>
<li>Showcase the role arns in a CloudFormation output</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">os</span> <span class="kn">import</span> <span class="n">path</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk</span> <span class="k">as</span> <span class="nn">cdk</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk.aws_iam</span> <span class="k">as</span> <span class="nn">iam</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="k">class</span> <span class="nc">MultiplePrincipalsStack</span><span class="p">(</span><span class="n">cdk</span><span class="o">.</span><span class="n">Stack</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scope</span><span class="p">:</span> <span class="n">cdk</span><span class="o">.</span><span class="n">App</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">scope</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="n">one</span> <span class="o">=</span> <span class="n">iam</span><span class="o">.</span><span class="n">Role</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;Role1&#34;</span><span class="p">,</span> <span class="n">assumed_by</span><span class="o">=</span><span class="n">iam</span><span class="o">.</span><span class="n">AnyPrincipal</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="n">two</span> <span class="o">=</span> <span class="n">iam</span><span class="o">.</span><span class="n">Role</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;Role2&#34;</span><span class="p">,</span> <span class="n">assumed_by</span><span class="o">=</span><span class="n">iam</span><span class="o">.</span><span class="n">AnyPrincipal</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="n">three</span> <span class="o">=</span> <span class="n">iam</span><span class="o">.</span><span class="n">Role</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="s2">&#34;RoleWithMultiplePrincipals&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">            <span class="n">assumed_by</span><span class="o">=</span><span class="n">iam</span><span class="o">.</span><span class="n">CompositePrincipal</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">                <span class="n">iam</span><span class="o">.</span><span class="n">ArnPrincipal</span><span class="p">(</span><span class="n">one</span><span class="o">.</span><span class="n">role_arn</span><span class="p">),</span> <span class="n">iam</span><span class="o">.</span><span class="n">ArnPrincipal</span><span class="p">(</span><span class="n">two</span><span class="o">.</span><span class="n">role_arn</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">            <span class="p">),</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl">        <span class="n">cdk</span><span class="o">.</span><span class="n">CfnOutput</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;RoleArn1&#34;</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="n">one</span><span class="o">.</span><span class="n">role_arn</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">        <span class="n">cdk</span><span class="o">.</span><span class="n">CfnOutput</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;RoleArn2&#34;</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="n">two</span><span class="o">.</span><span class="n">role_arn</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">        <span class="n">cdk</span><span class="o">.</span><span class="n">CfnOutput</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;RoleArn3&#34;</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="n">three</span><span class="o">.</span><span class="n">role_arn</span><span class="p">)</span></span></span></code></pre></div><p>After running <code>cdk deploy</code>, here are the stack outputs:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Outputs:
</span></span><span class="line"><span class="ln">2</span><span class="cl">stack.RoleArn1 = arn:aws:iam::123456789012:role/stack-Role13A5C70C1-2RU2vpUAiHMy
</span></span><span class="line"><span class="ln">3</span><span class="cl">stack.RoleArn2 = arn:aws:iam::123456789012:role/stack-Role291939BC6-4geKeo5cAu3w
</span></span><span class="line"><span class="ln">4</span><span class="cl">stack.RoleArn3 = arn:aws:iam::123456789012:role/stack-RoleWithMultiplePrincipals7CD0E21E-Rd9Rxpc2Ioqe</span></span></code></pre></div><h3 id="testing-the-role-assumption">Testing the role assumption</h3>
<p>Using the outputs from before, we can verify that everything worked correctly using the AWS CLI.</p>
<p>I assumed <code>Role1</code> by using the <code>aws sts assume-role</code> command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws sts assume-role <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --role-arn arn:aws:iam::123456789012:role/stack-Role13A5C70C1-2RU2vpUAiHMy <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --role-session-name test</span></span></code></pre></div><p>I exported the credentials from the output then assumed <code>RoleWithMultiplePrincipals</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws sts assume-role <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --role-arn arn:aws:iam::123456789012:role/stack-RoleWithMultiplePrincipals7CD0E21E-Rd9Rxpc2Ioqe <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --role-session-name test2</span></span></code></pre></div><p>Everything worked!</p>
]]></content:encoded></item><item><title>Serverless FastAPI with AWS Lambda, API Gateway, and AWS CDK</title><link>https://how.wtf/serverless-fastapi-with-aws-lambda-api-gateway-and-aws-cdk.html</link><pubDate>Sun, 07 Jan 2024 16:40:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/serverless-fastapi-with-aws-lambda-api-gateway-and-aws-cdk.html</guid><description>By the end of this article, you&amp;rsquo;ll have a Python app deployed with FastAPI using AWS Lambda and API Gateway that is serving requests. In addition, you will have the infrastructure defined in code.
What is AWS Lambda and API Gateway AWS Lambda and Amazon API Gateway are two services offered by AWS that enable developers to quickly spin up infrastructure without the hassle of provisioning or maintaining servers. In our case, we&amp;rsquo;ll host the FastAPI app in a Lambda function and the API Gateway will route requests to it.</description><content:encoded><![CDATA[<p><img src="images/XGSAmg.webp" alt="API Gateway, Lambda, and FastAPI logos in a simple architecture image"></p>
<p>By the end of this article, you&rsquo;ll have a Python app deployed with FastAPI using AWS Lambda and API Gateway that is serving requests. In addition, you will have the infrastructure defined in code.</p>
<h2 id="what-is-aws-lambda-and-api-gateway">What is AWS Lambda and API Gateway</h2>
<p><a href="https://aws.amazon.com/lambda/">AWS Lambda</a> and <a href="https://aws.amazon.com/api-gateway/">Amazon API Gateway</a> are two services offered by AWS that enable developers to quickly spin up infrastructure without the hassle of provisioning or maintaining servers. In our case, we&rsquo;ll host the FastAPI app in a Lambda function and the API Gateway will route requests to it.</p>
<p>This approach is immediately scalable upon deployment and includes a generous free tier by AWS.</p>
<h2 id="how-to-deploy-fastapi-with-aws-lambda--api-gateway--aws-cdk">How to deploy FastAPI with AWS Lambda + API Gateway + AWS CDK</h2>
<p>Follow the instructions below to successfully deploy an AWS CDK app that includes a lambda function and API Gateway.</p>
<h3 id="create-a-requirementstxt">Create a requirements.txt</h3>
<p>Create a <code>requirements.txt</code> file with the following information:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">aws-cdk-lib==2.118.0
</span></span><span class="line"><span class="ln">2</span><span class="cl">aws-cdk.aws-lambda-python-alpha==2.118.0a0
</span></span><span class="line"><span class="ln">3</span><span class="cl">constructs&gt;=10.0.0,&lt;11.0.0
</span></span><span class="line"><span class="ln">4</span><span class="cl">fastapi==0.108.0
</span></span><span class="line"><span class="ln">5</span><span class="cl">uvicorn==0.25.0
</span></span><span class="line"><span class="ln">6</span><span class="cl">mangum==0.17.0</span></span></code></pre></div><p>To serve FastAPI locally, <a href="https://www.uvicorn.org/">I chose <code>uvicorn</code></a>. This is not mandatory if you do not care about testing locally. To adapt the FastAPI router for API Gateway, we <a href="https://mangum.io/">will use <code>mangum</code></a>.</p>
<h3 id="install-the-dependencies">Install the dependencies</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip3 install -r requirements.txt</span></span></code></pre></div><h3 id="create-app-folder-with-a-mainpy-file">Create /app folder with a main.py file</h3>
<p>You can use your preferred file structure. Whether you use this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">project/
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">├── app
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">│   ├── __init__.py
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">│   ├── main.py
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">│   ├── dependencies.py
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">│   └── routers
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">│   │   ├── __init__.py
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">│   │   ├── items.py
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">│   │   └── users.py
</span></span><span class="line"><span class="ln">10</span><span class="cl">│   └── internal
</span></span><span class="line"><span class="ln">11</span><span class="cl">│       ├── __init__.py
</span></span><span class="line"><span class="ln">12</span><span class="cl">│       └── admin.py</span></span></code></pre></div><p>or this</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">project/
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── app
</span></span><span class="line"><span class="ln">3</span><span class="cl">│   ├── __init__.py
</span></span><span class="line"><span class="ln">4</span><span class="cl">│   └── main.py</span></span></code></pre></div><p>ensure that there&rsquo;s a <code>main.py</code> at the root of the <code>app</code> folder.</p>
<p>For the purposes of this tutorial, we&rsquo;ll use a <code>app/main.py</code> file to keep it simple for a small todo app:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">fastapi</span> <span class="kn">import</span> <span class="n">FastAPI</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">mangum</span> <span class="kn">import</span> <span class="n">Mangum</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">app</span> <span class="o">=</span> <span class="n">FastAPI</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nd">@app.get</span><span class="p">(</span><span class="s2">&#34;/tasks&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">get_tasks</span><span class="p">():</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="c1"># database lookup goes here</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="k">return</span> <span class="p">[{</span><span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;ptvWZ3&#34;</span><span class="p">,</span> <span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;hello!&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;cqDUr3&#34;</span><span class="p">,</span> <span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;another!&#34;</span><span class="p">}]</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nd">@app.get</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">root</span><span class="p">():</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="k">return</span> <span class="p">{</span><span class="s2">&#34;message&#34;</span><span class="p">:</span> <span class="s2">&#34;Hello World!&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="n">handler</span> <span class="o">=</span> <span class="n">Mangum</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="n">lifespan</span><span class="o">=</span><span class="s2">&#34;off&#34;</span><span class="p">)</span></span></span></code></pre></div><h3 id="create-a-stackpy-with-an-api-gateway-and-a-lambda-router">Create a stack.py with an API Gateway and a lambda router</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">os</span> <span class="kn">import</span> <span class="n">path</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk</span> <span class="k">as</span> <span class="nn">cdk</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk.aws_lambda</span> <span class="k">as</span> <span class="nn">lambda_</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk.aws_apigateway</span> <span class="k">as</span> <span class="nn">apigateway</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk.aws_lambda_python_alpha</span> <span class="k">as</span> <span class="nn">python</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="k">class</span> <span class="nc">ApiStack</span><span class="p">(</span><span class="n">cdk</span><span class="o">.</span><span class="n">Stack</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scope</span><span class="p">:</span> <span class="n">cdk</span><span class="o">.</span><span class="n">App</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">scope</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="n">lambda_function</span> <span class="o">=</span> <span class="n">python</span><span class="o">.</span><span class="n">PythonFunction</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="s2">&#34;Function&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">            <span class="n">entry</span><span class="o">=</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="vm">__file__</span><span class="p">),</span> <span class="s2">&#34;app&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">            <span class="n">runtime</span><span class="o">=</span><span class="n">lambda_</span><span class="o">.</span><span class="n">Runtime</span><span class="o">.</span><span class="n">PYTHON_3_11</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">            <span class="n">index</span><span class="o">=</span><span class="s2">&#34;main.py&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl">        <span class="n">api</span> <span class="o">=</span> <span class="n">apigateway</span><span class="o">.</span><span class="n">LambdaRestApi</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;API&#34;</span><span class="p">,</span> <span class="n">handler</span><span class="o">=</span><span class="n">lambda_function</span><span class="p">)</span></span></span></code></pre></div><p><strong>NOTE</strong>: We are using a construct that is in alpha. This enables the AWS CDK to use Docker to bundle our Python requirements together.</p>
<p>This seems small, but we are leveraging the power of the AWS CDK and <a href="https://docs.aws.amazon.com/cdk/v2/guide/constructs.html#constructs_lib">their L3 constructs</a>. This CDK app will:</p>
<ol>
<li>Bundle python requirements and create a .zip file</li>
<li>Create a lambda function with the handler as <code>main.handler</code></li>
<li>Create an API Gateway</li>
<li>Add a resource path of <code>{proxy+}</code> to the API</li>
<li>Add an <code>ANY</code> method to the resource path that points to the lambda function</li>
<li>Enable a &ldquo;proxy integration&rdquo; for the lambda function</li>
</ol>
<h4 id="what-is-an-api-gateway-proxy-integration">What is an API Gateway proxy integration?</h4>
<p>For the FastAPI logic to work appropriately, we need to configure the API Gateway to forward <strong>full</strong> API requests to the lambda function. With this setting, the lambda function&rsquo;s responsibility increases as it must fulfill the requirements of the API Gateway service.</p>
<p>Fortunately, <code>mangum</code> takes care of this.</p>
<h3 id="create-a-requirementstxt-file-for-the-app-folder">Create a requirements.txt file for the /app folder</h3>
<p>As of time of writing (Jan. 7th, 2024), the python alpha function <code>entry</code> folder <em>must</em> have the <code>requirements.txt</code> file in it. Create <code>app/requirements.txt</code> file with the following:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">fastapi==0.108.0
</span></span><span class="line"><span class="ln">2</span><span class="cl">mangum==0.17.0</span></span></code></pre></div><h3 id="create-infrapy">Create infra.py</h3>
<p>Create a file that provisions the CDK app. I named mine <code>infra.py</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk</span> <span class="k">as</span> <span class="nn">cdk</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="kn">from</span> <span class="nn">stack</span> <span class="kn">import</span> <span class="n">ApiStack</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">app</span> <span class="o">=</span> <span class="n">cdk</span><span class="o">.</span><span class="n">App</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="n">ApiStack</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="s2">&#34;ApiStack&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="n">app</span><span class="o">.</span><span class="n">synth</span><span class="p">()</span></span></span></code></pre></div><h3 id="create-cdkjson">Create cdk.json</h3>
<p>Ensure that the entry file matches the one you created before.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;app&#34;</span><span class="p">:</span> <span class="s2">&#34;python3 infra.py&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>The directory structure should look like this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">project/
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── app
</span></span><span class="line"><span class="ln">3</span><span class="cl">│   ├── main.py
</span></span><span class="line"><span class="ln">4</span><span class="cl">│   └── requirements.txt
</span></span><span class="line"><span class="ln">5</span><span class="cl">├── cdk.json
</span></span><span class="line"><span class="ln">6</span><span class="cl">├── infra.py
</span></span><span class="line"><span class="ln">7</span><span class="cl">├── requirements.txt
</span></span><span class="line"><span class="ln">8</span><span class="cl">└── stack.py</span></span></code></pre></div><h3 id="deploy-the-stack">Deploy the stack</h3>
<p>Before deploying, ensure that <em>Docker is running</em>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">cdk deploy</span></span></code></pre></div><p>After the stack is deployed, we&rsquo;re given the API endpoint in a stack output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Outputs:
</span></span><span class="line"><span class="ln">2</span><span class="cl">ApiStack.APIEndpoint1793E782 = https://{api_id}.execute-api.us-east-1.amazonaws.com/prod/</span></span></code></pre></div><h3 id="testing-the-proxy-integration">Testing the proxy integration</h3>
<p>We&rsquo;ll use <code>curl</code> to test our API:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl https://<span class="o">{</span>api_id<span class="o">}</span>.execute-api.us-east-1.amazonaws.com/prod/</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span><span class="nt">&#34;message&#34;</span><span class="p">:</span> <span class="s2">&#34;Hello world!&#34;</span><span class="p">}</span></span></span></code></pre></div><p>The <code>/tasks</code> endpoint:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl https://<span class="o">{</span>api_id<span class="o">}</span>.execute-api.us-east-1.amazonaws.com/prod/tasks</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">[{</span><span class="nt">&#34;id&#34;</span><span class="p">:</span><span class="s2">&#34;ptvWZ3&#34;</span><span class="p">,</span><span class="nt">&#34;text&#34;</span><span class="p">:</span><span class="s2">&#34;hello!&#34;</span><span class="p">},{</span><span class="nt">&#34;id&#34;</span><span class="p">:</span><span class="s2">&#34;cqDUr3&#34;</span><span class="p">,</span><span class="nt">&#34;text&#34;</span><span class="p">:</span><span class="s2">&#34;another!&#34;</span><span class="p">}]</span></span></span></code></pre></div><h3 id="testing-locally">Testing locally</h3>
<p>The top-level <code>requirements.txt</code> enables us to test locally with uvicorn:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">uvicorn app.main:app --reload</span></span></code></pre></div><p>Using <code>curl</code>,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl http://127.0.0.1:8000/</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span><span class="nt">&#34;message&#34;</span><span class="p">:</span><span class="s2">&#34;Hello World!&#34;</span><span class="p">}</span></span></span></code></pre></div><h3 id="cleaning-up">Cleaning up</h3>
<p>If you wish to destroy your CDK app, run the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">cdk destroy</span></span></code></pre></div><h2 id="conclusion">Conclusion</h2>
<p>After following the prior steps, you will have an understanding of how to deploy a functioning API Gateway and Lambda function powered by FastAPI.</p>
<p>Enjoy building on this example!</p>
]]></content:encoded></item><item><title>Creating a serverless API using AWS Lambda Powertools and CDK</title><link>https://how.wtf/creating-a-serverless-api-using-aws-lambda-powertools-and-cdk.html</link><pubDate>Fri, 05 Jan 2024 03:05:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/creating-a-serverless-api-using-aws-lambda-powertools-and-cdk.html</guid><description>Amazon API Gateway + AWS Lambda is a powerful duo for creating easy-to-deploy scalable infrastructure that is immediately accessible by thousands of users. For this post, we will create an API Gateway with an lambda proxy integration using the AWS Lambda Powertools library and the AWS CDK.
In just a few lines of code, we&amp;rsquo;ll have our API deployed and ready to go! This tutorial assumes you know what the Amazon API Gateway and AWS Lambda services are.</description><content:encoded><![CDATA[<p><img src="images/hwruz7.webp" alt="API Gateway and Lambda Logo architecture image"></p>
<p>Amazon API Gateway + AWS Lambda is a powerful duo for creating easy-to-deploy scalable infrastructure that is immediately accessible by thousands of users. For this post, we will create an API Gateway with an lambda proxy integration using the AWS Lambda Powertools library and the AWS CDK.</p>
<p>In just a few lines of code, we&rsquo;ll have our API deployed and ready to go! This tutorial assumes you know what the Amazon API Gateway and AWS Lambda services are.</p>
<h2 id="what-is-aws-lambda-powertools">What is AWS Lambda Powertools</h2>
<p><a href="https://docs.powertools.aws.dev/lambda/python/latest/">AWS Lambda Powertools</a> is an SDK released by Amazon that aims to increase developer productiviy by bundling similar functionality together:</p>
<ol>
<li>Tracing</li>
<li>Logging</li>
<li>Event handling</li>
<li>Typing / Validation</li>
<li>Middleware</li>
</ol>
<p>and more!</p>
<p>With this SDK, we&rsquo;ll build a single lambda integration that will handle all the routes of our API Gateway.</p>
<p>If you&rsquo;ve used Flask, Spring Boot, express, etc., this following code snippet should look familiar:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_lambda_powertools</span> <span class="kn">import</span> <span class="n">Logger</span><span class="p">,</span> <span class="n">Tracer</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_lambda_powertools.event_handler</span> <span class="kn">import</span> <span class="n">APIGatewayRestResolver</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_lambda_powertools.logging</span> <span class="kn">import</span> <span class="n">correlation_paths</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_lambda_powertools.utilities.typing</span> <span class="kn">import</span> <span class="n">LambdaContext</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_lambda_powertools.utilities.data_classes</span> <span class="kn">import</span> <span class="n">event_source</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_lambda_powertools.utilities.data_classes.api_gateway_authorizer_event</span> <span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">APIGatewayAuthorizerRequestEvent</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">tracer</span> <span class="o">=</span> <span class="n">Tracer</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">app</span> <span class="o">=</span> <span class="n">APIGatewayRestResolver</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="nd">@app.get</span><span class="p">(</span><span class="s2">&#34;/pets&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="nd">@tracer.capture_method</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="k">def</span> <span class="nf">get_pets</span><span class="p">():</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="k">return</span> <span class="p">{</span><span class="s2">&#34;pets&#34;</span><span class="p">:</span> <span class="p">[]}</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="nd">@logger.inject_lambda_context</span><span class="p">(</span><span class="n">correlation_id_path</span><span class="o">=</span><span class="n">correlation_paths</span><span class="o">.</span><span class="n">API_GATEWAY_REST</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="nd">@tracer.capture_lambda_handler</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="nd">@event_source</span><span class="p">(</span><span class="n">data_class</span><span class="o">=</span><span class="n">APIGatewayAuthorizerRequestEvent</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="k">def</span> <span class="nf">lambda_handler</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="n">event</span><span class="p">:</span> <span class="n">APIGatewayAuthorizerRequestEvent</span><span class="p">,</span> <span class="n">context</span><span class="p">:</span> <span class="n">LambdaContext</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">    <span class="k">return</span> <span class="n">app</span><span class="o">.</span><span class="n">resolve</span><span class="p">(</span><span class="n">event</span><span class="o">.</span><span class="n">raw_event</span><span class="p">,</span> <span class="n">context</span><span class="p">)</span></span></span></code></pre></div><p>The <code>APIGatewayRestResolver</code> behaves like a router. The <code>lambda_handler</code> processes the API Gateway event then <code>resolve</code>s the route using the information that was passed from the lambda context. We&rsquo;ll reference this example when creating our own.</p>
<h2 id="how-to-deploy-an-api-gateway-with-proxy-lambda-with-powertools">How to deploy an API Gateway with Proxy Lambda with Powertools</h2>
<p>Follow the instructions below to deploy a Lambda Function with Powertools bundled for an API Gateway proxy integration.</p>
<h3 id="create-a-requirementstxt">Create a requirements.txt</h3>
<p>For this tutorial, version 2.118.0 of the AWS CDK was used.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">aws-cdk-lib==2.118.0
</span></span><span class="line"><span class="ln">2</span><span class="cl">constructs&gt;=10.0.0,&lt;11.0.0</span></span></code></pre></div><h3 id="install-the-dependencies">Install the dependencies</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip3 install -r requirements.txt</span></span></code></pre></div><h3 id="create-handler-folder-with-an-indexpy-file">Create /handler folder with an index.py file</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">def</span> <span class="nf">handler</span><span class="p">(</span><span class="n">event</span><span class="p">,</span> <span class="n">context</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="k">return</span> <span class="p">{</span><span class="s2">&#34;statusCode&#34;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span> <span class="s2">&#34;body&#34;</span><span class="p">:</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">({</span><span class="s2">&#34;message&#34;</span><span class="p">:</span> <span class="s2">&#34;Hello world!&#34;</span><span class="p">})}</span></span></span></code></pre></div><h3 id="create-stackpy-with-an-api-gateway-and-a-lambda-router">Create stack.py with an API Gateway and a lambda router</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">os</span> <span class="kn">import</span> <span class="n">path</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk</span> <span class="k">as</span> <span class="nn">cdk</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk.aws_lambda</span> <span class="k">as</span> <span class="nn">lambda_</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk.aws_apigateway</span> <span class="k">as</span> <span class="nn">apigateway</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="k">class</span> <span class="nc">ApiStack</span><span class="p">(</span><span class="n">cdk</span><span class="o">.</span><span class="n">Stack</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scope</span><span class="p">:</span> <span class="n">cdk</span><span class="o">.</span><span class="n">App</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">scope</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="n">lambda_function</span> <span class="o">=</span> <span class="n">lambda_</span><span class="o">.</span><span class="n">Function</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">            <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="s2">&#34;Function&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="n">runtime</span><span class="o">=</span><span class="n">lambda_</span><span class="o">.</span><span class="n">Runtime</span><span class="o">.</span><span class="n">PYTHON_3_11</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">            <span class="n">handler</span><span class="o">=</span><span class="s2">&#34;index.handler&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">            <span class="n">code</span><span class="o">=</span><span class="n">lambda_</span><span class="o">.</span><span class="n">Code</span><span class="o">.</span><span class="n">from_asset</span><span class="p">(</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="vm">__file__</span><span class="p">),</span> <span class="s2">&#34;handler&#34;</span><span class="p">)),</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl">        <span class="n">api</span> <span class="o">=</span> <span class="n">apigateway</span><span class="o">.</span><span class="n">LambdaRestApi</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;API&#34;</span><span class="p">,</span> <span class="n">handler</span><span class="o">=</span><span class="n">lambda_function</span><span class="p">)</span></span></span></code></pre></div><p>The AWS CDK <a href="https://docs.aws.amazon.com/cdk/v2/guide/constructs.html#constructs_lib">provides &ldquo;L3&rdquo; constructs</a>; constructs that abstract away configuration we otherwise explicitly need define. In the case above, the <a href="https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_apigateway/LambdaRestApi.html">L3 construct named <code>LambdaRestApi</code></a> handles a few things:</p>
<ol>
<li>API Gateway creation</li>
<li>Lambda handler configuration</li>
<li>Resource path <code>{proxy+}</code> creation</li>
<li><code>ANY</code> method creation</li>
</ol>
<h3 id="create-apppy">Create app.py</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk</span> <span class="k">as</span> <span class="nn">cdk</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="kn">from</span> <span class="nn">stack</span> <span class="kn">import</span> <span class="n">ApiStack</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">app</span> <span class="o">=</span> <span class="n">cdk</span><span class="o">.</span><span class="n">App</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="n">ApiStack</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="s2">&#34;ApiStack&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="n">app</span><span class="o">.</span><span class="n">synth</span><span class="p">()</span></span></span></code></pre></div><h3 id="create-cdkjson">Create cdk.json</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;app&#34;</span><span class="p">:</span> <span class="s2">&#34;python3 app.py&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>The directory structure should look like this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">project/
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── app.py
</span></span><span class="line"><span class="ln">3</span><span class="cl">├── cdk.json
</span></span><span class="line"><span class="ln">4</span><span class="cl">├── handler
</span></span><span class="line"><span class="ln">5</span><span class="cl">│   └── index.py
</span></span><span class="line"><span class="ln">6</span><span class="cl">├── requirements.txt
</span></span><span class="line"><span class="ln">7</span><span class="cl">└── stack.py</span></span></code></pre></div><h3 id="deploy-the-stack">Deploy the stack</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">cdk deploy</span></span></code></pre></div><p>After the stack is deployed, we&rsquo;re given the API endpoint in a stack output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Outputs:
</span></span><span class="line"><span class="ln">2</span><span class="cl">ApiStack.APIEndpoint1793E782 = https://{api_id}.execute-api.us-east-1.amazonaws.com/prod/</span></span></code></pre></div><h3 id="testing-the-proxy-integration">Testing the proxy integration</h3>
<p>At this point, we can send any HTTP request and always get back the same response:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl https://<span class="o">{</span>api_id<span class="o">}</span>.execute-api.us-east-1.amazonaws.com/prod/</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span><span class="nt">&#34;message&#34;</span><span class="p">:</span> <span class="s2">&#34;Hello world!&#34;</span><span class="p">}</span></span></span></code></pre></div><h3 id="add-lambda-powertools-lambda-layer-using-aws-cdk--sar">Add Lambda Powertools lambda layer using AWS CDK + SAR</h3>
<p>Rather than write our own routing function based on the API Gateway event, let&rsquo;s use AWS Lambda Powertools.</p>
<p>I have two preferred options for adding the Lambda Powertools layer:</p>
<ol>
<li>Using the <a href="https://github.com/aws-powertools/powertools-lambda-layer-cdk">AWS lambda layer construct provided by AWS</a> (requires Docker)</li>
<li>Explicitly using the AWS managed layer</li>
</ol>
<p>For the purposes of this tutorial, I&rsquo;ll <a href="https://docs.powertools.aws.dev/lambda/python/latest/#sar">reference the lambda layer using the serverless application respository</a>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">os</span> <span class="kn">import</span> <span class="n">path</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk</span> <span class="k">as</span> <span class="nn">cdk</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk.aws_lambda</span> <span class="k">as</span> <span class="nn">lambda_</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk.aws_apigateway</span> <span class="k">as</span> <span class="nn">apigateway</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk.aws_sam</span> <span class="k">as</span> <span class="nn">sam</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">POWERTOOLS_BASE_NAME</span> <span class="o">=</span> <span class="s2">&#34;AWSLambdaPowertools&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="n">POWERTOOLS_VERSION</span> <span class="o">=</span> <span class="s2">&#34;2.30.2&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">POWERTOOLS_ARN</span> <span class="o">=</span> <span class="s2">&#34;arn:aws:serverlessrepo:eu-west-1:057560766410:applications/aws-lambda-powertools-python-layer&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="k">class</span> <span class="nc">ApiStack</span><span class="p">(</span><span class="n">cdk</span><span class="o">.</span><span class="n">Stack</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scope</span><span class="p">:</span> <span class="n">cdk</span><span class="o">.</span><span class="n">App</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">scope</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="n">powertools_app</span> <span class="o">=</span> <span class="n">sam</span><span class="o">.</span><span class="n">CfnApplication</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">            <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">            <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">POWERTOOLS_BASE_NAME</span><span class="si">}</span><span class="s2">Application&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">            <span class="n">location</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">                <span class="s2">&#34;applicationId&#34;</span><span class="p">:</span> <span class="n">POWERTOOLS_ARN</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">                <span class="s2">&#34;semanticVersion&#34;</span><span class="p">:</span> <span class="n">POWERTOOLS_VERSION</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">
</span></span><span class="line"><span class="ln">26</span><span class="cl">        <span class="n">powertools_layer_arn</span> <span class="o">=</span> <span class="n">powertools_app</span><span class="o">.</span><span class="n">get_att</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">            <span class="s2">&#34;Outputs.LayerVersionArn&#34;</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">        <span class="p">)</span><span class="o">.</span><span class="n">to_string</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">
</span></span><span class="line"><span class="ln">30</span><span class="cl">        <span class="n">powertools_layer_version</span> <span class="o">=</span> <span class="n">lambda_</span><span class="o">.</span><span class="n">LayerVersion</span><span class="o">.</span><span class="n">from_layer_version_arn</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">            <span class="bp">self</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">POWERTOOLS_BASE_NAME</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">,</span> <span class="n">powertools_layer_arn</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">
</span></span><span class="line"><span class="ln">34</span><span class="cl">        <span class="n">lambda_function</span> <span class="o">=</span> <span class="n">lambda_</span><span class="o">.</span><span class="n">Function</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">            <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">            <span class="s2">&#34;Function&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">            <span class="n">runtime</span><span class="o">=</span><span class="n">lambda_</span><span class="o">.</span><span class="n">Runtime</span><span class="o">.</span><span class="n">PYTHON_3_11</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">            <span class="n">handler</span><span class="o">=</span><span class="s2">&#34;index.handler&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl">            <span class="n">code</span><span class="o">=</span><span class="n">lambda_</span><span class="o">.</span><span class="n">Code</span><span class="o">.</span><span class="n">from_asset</span><span class="p">(</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="vm">__file__</span><span class="p">),</span> <span class="s2">&#34;handler&#34;</span><span class="p">)),</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl">            <span class="n">layers</span><span class="o">=</span><span class="p">[</span><span class="n">powertools_layer_version</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl">
</span></span><span class="line"><span class="ln">43</span><span class="cl">        <span class="n">api</span> <span class="o">=</span> <span class="n">apigateway</span><span class="o">.</span><span class="n">LambdaRestApi</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;API&#34;</span><span class="p">,</span> <span class="n">handler</span><span class="o">=</span><span class="n">lambda_function</span><span class="p">)</span></span></span></code></pre></div><h3 id="using-aws-lambda-powertools">Using AWS Lambda Powertools</h3>
<p>Now that the lambda is successfully configured for AWS Lambda Powertools, let&rsquo;s experiment using a small todo app:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_lambda_powertools</span> <span class="kn">import</span> <span class="n">Logger</span><span class="p">,</span> <span class="n">Tracer</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_lambda_powertools.event_handler</span> <span class="kn">import</span> <span class="n">APIGatewayRestResolver</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_lambda_powertools.logging</span> <span class="kn">import</span> <span class="n">correlation_paths</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_lambda_powertools.utilities.typing</span> <span class="kn">import</span> <span class="n">LambdaContext</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">tracer</span> <span class="o">=</span> <span class="n">Tracer</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">app</span> <span class="o">=</span> <span class="n">APIGatewayRestResolver</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nd">@app.get</span><span class="p">(</span><span class="s2">&#34;/tasks&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nd">@tracer.capture_method</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="k">def</span> <span class="nf">get_tasks</span><span class="p">():</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="c1"># database lookup goes here</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="k">return</span> <span class="p">[{</span><span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;ptvWZ3&#34;</span><span class="p">,</span> <span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;hello!&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;cqDUr3&#34;</span><span class="p">,</span> <span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;another!&#34;</span><span class="p">}]</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="nd">@logger.inject_lambda_context</span><span class="p">(</span><span class="n">correlation_id_path</span><span class="o">=</span><span class="n">correlation_paths</span><span class="o">.</span><span class="n">API_GATEWAY_REST</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="nd">@tracer.capture_lambda_handler</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="k">def</span> <span class="nf">handler</span><span class="p">(</span><span class="n">event</span><span class="p">:</span> <span class="nb">dict</span><span class="p">,</span> <span class="n">context</span><span class="p">:</span> <span class="n">LambdaContext</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">    <span class="k">return</span> <span class="n">app</span><span class="o">.</span><span class="n">resolve</span><span class="p">(</span><span class="n">event</span><span class="p">,</span> <span class="n">context</span><span class="p">)</span></span></span></code></pre></div><p>Now we can test the different routes:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl https://<span class="o">{</span>api_id<span class="o">}</span>.execute-api.us-east-1.amazonaws.com/prod/</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span><span class="nt">&#34;statusCode&#34;</span><span class="p">:</span><span class="mi">404</span><span class="p">,</span><span class="nt">&#34;message&#34;</span><span class="p">:</span><span class="s2">&#34;Not found&#34;</span><span class="p">}</span></span></span></code></pre></div><p>and the real <code>/tasks</code> endpoint:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl https://<span class="o">{</span>api_id<span class="o">}</span>.execute-api.us-east-1.amazonaws.com/prod/tasks</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">[{</span><span class="nt">&#34;id&#34;</span><span class="p">:</span><span class="s2">&#34;ptvWZ3&#34;</span><span class="p">,</span><span class="nt">&#34;text&#34;</span><span class="p">:</span><span class="s2">&#34;hello!&#34;</span><span class="p">},{</span><span class="nt">&#34;id&#34;</span><span class="p">:</span><span class="s2">&#34;cqDUr3&#34;</span><span class="p">,</span><span class="nt">&#34;text&#34;</span><span class="p">:</span><span class="s2">&#34;another!&#34;</span><span class="p">}]</span></span></span></code></pre></div><h2 id="conclusion">Conclusion</h2>
<p>At this point, you will have a functioning AWS CDK application with an API Gateway Lambda Proxy integration setup! While the <code>/tasks</code> code is rudimentary, it provides the foundation for expansion for your own API!</p>
<p>Happy building!</p>
]]></content:encoded></item><item><title>Lambda Bash custom runtime with AWS CDK</title><link>https://how.wtf/lambda-bash-custom-runtime-with-aws-cdk.html</link><pubDate>Tue, 02 Jan 2024 11:25:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/lambda-bash-custom-runtime-with-aws-cdk.html</guid><description>For this post, I will extend the AWS documentation for &amp;lsquo;Building a custom runtime&amp;rsquo; by additionally using the AWS CDK in Python to deploy the Bash custom runtime for AWS Lambda.
How to deploy a Lambda custom runtime using AWS CDK Follow the instructions below to deploy an AWS Lambda Function with a Bash custom runtime!
Create a /handler folder with a bootstrap file AWS provides a bootstrap file that creates the custom runtime.</description><content:encoded><![CDATA[<p><img src="images/4PS3Zk.webp" alt="A bald character looking at the Bash logo for deploying custom runtimes with AWS CDK"></p>
<p>For this post, I will extend the <a href="https://docs.aws.amazon.com/lambda/latest/dg/runtimes-walkthrough.html">AWS documentation for &lsquo;Building a custom runtime&rsquo;</a> by additionally using the AWS CDK in Python to deploy the Bash custom runtime for AWS Lambda.</p>
<h2 id="how-to-deploy-a-lambda-custom-runtime-using-aws-cdk">How to deploy a Lambda custom runtime using AWS CDK</h2>
<p>Follow the instructions below to deploy an AWS Lambda Function with a Bash custom runtime!</p>
<h3 id="create-a-handler-folder-with-a-bootstrap-file">Create a /handler folder with a bootstrap file</h3>
<p>AWS provides a <code>bootstrap</code> file that creates the custom runtime. Here is that script:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="cp">#!/bin/sh
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nb">set</span> -euo pipefail
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"># Initialization - load function handler</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nb">source</span> <span class="nv">$LAMBDA_TASK_ROOT</span>/<span class="s2">&#34;</span><span class="k">$(</span><span class="nb">echo</span> <span class="nv">$_HANDLER</span> <span class="p">|</span> cut -d. -f1<span class="k">)</span><span class="s2">.sh&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"># Processing</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="k">while</span> <span class="nb">true</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="k">do</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="nv">HEADERS</span><span class="o">=</span><span class="s2">&#34;</span><span class="k">$(</span>mktemp<span class="k">)</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">  <span class="c1"># Get an event. The HTTP request will block until one is received</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">  <span class="nv">EVENT_DATA</span><span class="o">=</span><span class="k">$(</span>curl -sS -LD <span class="s2">&#34;</span><span class="nv">$HEADERS</span><span class="s2">&#34;</span> <span class="s2">&#34;http://</span><span class="si">${</span><span class="nv">AWS_LAMBDA_RUNTIME_API</span><span class="si">}</span><span class="s2">/2018-06-01/runtime/invocation/next&#34;</span><span class="k">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl">  <span class="c1"># Extract request ID by scraping response headers received above</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">  <span class="nv">REQUEST_ID</span><span class="o">=</span><span class="k">$(</span>grep -Fi Lambda-Runtime-Aws-Request-Id <span class="s2">&#34;</span><span class="nv">$HEADERS</span><span class="s2">&#34;</span> <span class="p">|</span> tr -d <span class="s1">&#39;[:space:]&#39;</span> <span class="p">|</span> cut -d: -f2<span class="k">)</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl">  <span class="c1"># Run the handler function from the script</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">  <span class="nv">RESPONSE</span><span class="o">=</span><span class="k">$($(</span><span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$_HANDLER</span><span class="s2">&#34;</span> <span class="p">|</span> cut -d. -f2<span class="k">)</span> <span class="s2">&#34;</span><span class="nv">$EVENT_DATA</span><span class="s2">&#34;</span><span class="k">)</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl">  <span class="c1"># Send the response</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">  curl <span class="s2">&#34;http://</span><span class="si">${</span><span class="nv">AWS_LAMBDA_RUNTIME_API</span><span class="si">}</span><span class="s2">/2018-06-01/runtime/invocation/</span><span class="nv">$REQUEST_ID</span><span class="s2">/response&#34;</span>  -d <span class="s2">&#34;</span><span class="nv">$RESPONSE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="k">done</span></span></span></code></pre></div><p>The tutorial explains what this script does in-depth, but here&rsquo;s the summary:</p>
<ol>
<li>Initializes by loading the handler file provided by the lambda</li>
<li>Grabs the event data from the invocation event</li>
<li>Grabs the request id from the invocation header</li>
<li>Runs the handler, then passes the response to the lambda runtime API</li>
</ol>
<p>For more information about the runtime process, check out the AWS documentation <a href="https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html">here</a> that describes the process and the API.</p>
<p>I created a folder named <code>/handler</code> and added the <code>bootstrap</code> file into it.</p>
<h3 id="create-a-requirementstxt">Create a requirements.txt</h3>
<p>For this tutorial, version 2.117.0 of the AWS CDK was used.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">aws-cdk-lib==2.117.0
</span></span><span class="line"><span class="ln">2</span><span class="cl">constructs&gt;=10.0.0,&lt;11.0.0</span></span></code></pre></div><h3 id="install-the-dependencies">Install the dependencies</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip3 install -r requirements.txt</span></span></code></pre></div><h3 id="add-indexsh-file-to-handler-directory">Add index.sh file to /handler directory</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">handler<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nv">EVENT_DATA</span><span class="o">=</span><span class="nv">$1</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$EVENT_DATA</span><span class="s2">&#34;</span> 1&gt;<span class="p">&amp;</span>2<span class="p">;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="nv">RESPONSE</span><span class="o">=</span><span class="s2">&#34;Echoing request: &#39;</span><span class="nv">$EVENT_DATA</span><span class="s2">&#39;&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">  <span class="nb">echo</span> <span class="nv">$RESPONSE</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="o">}</span></span></span></code></pre></div><h3 id="create-stackpy-with-the-lambda-function">Create stack.py with the lambda function</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">os</span> <span class="kn">import</span> <span class="n">path</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk</span> <span class="k">as</span> <span class="nn">cdk</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk.aws_lambda</span> <span class="k">as</span> <span class="nn">lambda_</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="k">class</span> <span class="nc">BashFunctionStack</span><span class="p">(</span><span class="n">cdk</span><span class="o">.</span><span class="n">Stack</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scope</span><span class="p">:</span> <span class="n">cdk</span><span class="o">.</span><span class="n">App</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">scope</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="n">lambda_function</span> <span class="o">=</span> <span class="n">lambda_</span><span class="o">.</span><span class="n">Function</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">            <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">            <span class="s2">&#34;Function&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="n">runtime</span><span class="o">=</span><span class="n">lambda_</span><span class="o">.</span><span class="n">Runtime</span><span class="o">.</span><span class="n">PROVIDED_AL2023</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="n">handler</span><span class="o">=</span><span class="s2">&#34;index.handler&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">            <span class="n">code</span><span class="o">=</span><span class="n">lambda_</span><span class="o">.</span><span class="n">Code</span><span class="o">.</span><span class="n">from_asset</span><span class="p">(</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="vm">__file__</span><span class="p">),</span> <span class="s2">&#34;handler&#34;</span><span class="p">)),</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl">        <span class="n">cdk</span><span class="o">.</span><span class="n">CfnOutput</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;FunctionName&#34;</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="n">lambda_function</span><span class="o">.</span><span class="n">function_name</span><span class="p">)</span></span></span></code></pre></div><h3 id="create-apppy">Create app.py</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk</span> <span class="k">as</span> <span class="nn">cdk</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="kn">from</span> <span class="nn">stack</span> <span class="kn">import</span> <span class="n">BashFunctionStack</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">app</span> <span class="o">=</span> <span class="n">cdk</span><span class="o">.</span><span class="n">App</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="n">BashFunctionStack</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="s2">&#34;BashFunctionStack&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="n">app</span><span class="o">.</span><span class="n">synth</span><span class="p">()</span></span></span></code></pre></div><h3 id="create-cdkjson">Create cdk.json</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;app&#34;</span><span class="p">:</span> <span class="s2">&#34;python3 app.py&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>The directory structure should look like this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">project/
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── app.py
</span></span><span class="line"><span class="ln">3</span><span class="cl">├── cdk.json
</span></span><span class="line"><span class="ln">4</span><span class="cl">├── handler
</span></span><span class="line"><span class="ln">5</span><span class="cl">│   ├── bootstrap
</span></span><span class="line"><span class="ln">6</span><span class="cl">│   └── index.sh
</span></span><span class="line"><span class="ln">7</span><span class="cl">├── requirements.txt
</span></span><span class="line"><span class="ln">8</span><span class="cl">└── stack.py</span></span></code></pre></div><h3 id="deploy-the-stack">Deploy the stack</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">cdk deploy</span></span></code></pre></div><p>Because of the <code>CfnOutput</code>, the function name is an output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Outputs:
</span></span><span class="line"><span class="ln">2</span><span class="cl">BashFunctionStack.FunctionName = BashFunctionStack-Function76856677-TiMb7dPSe1lE</span></span></code></pre></div><h3 id="invoke-the-function">Invoke the function</h3>
<p>If everything worked correctly, we can invoke the function using the AWS CLI:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws lambda invoke response.txt <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --function-name FUNCTION_NAME <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --payload <span class="s1">&#39;{&#34;text&#34;:&#34;Hello&#34;}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>    --cli-binary-format raw-in-base64-out</span></span></code></pre></div><p>and receive the following output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;StatusCode&#34;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nt">&#34;ExecutedVersion&#34;</span><span class="p">:</span> <span class="s2">&#34;$LATEST&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>with a <code>response.txt</code> of:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Echoing request: &#39;{&#34;text&#34;:&#34;Hello&#34;}&#39;</span></span></code></pre></div>]]></content:encoded></item><item><title>Goatcounter for blog analytics</title><link>https://how.wtf/goatcounter-for-blog-analytics.html</link><pubDate>Sun, 31 Dec 2023 22:55:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/goatcounter-for-blog-analytics.html</guid><description>Going into 2024, I wanted to minimize the footprint of how.wtf.
This included:
Removing ads Removing giscus, the commenting system Removing Google Analytics Reducing the website&amp;rsquo;s size to less than 20kb Changing the theme to be super minimal with a focus on content I have nothing against Google Analytics; I simply wanted something with less impact on my website&amp;rsquo;s loading speeds. Additionally, GDPR compliance requires companies using Google Analytics to gain explicit user consent for data collection.</description><content:encoded><![CDATA[<p>Going into 2024, I wanted to minimize the footprint of <a href="https://how.wtf">how.wtf</a>.</p>
<p>This included:</p>
<ol>
<li>Removing ads</li>
<li>Removing giscus, the commenting system</li>
<li>Removing <strong>Google Analytics</strong></li>
<li>Reducing the website&rsquo;s size to <a href="https://512kb.club/">less than 20kb</a></li>
<li>Changing the theme to be super minimal with a focus on content</li>
</ol>
<p>I have nothing against Google Analytics; I simply wanted something with less impact on my website&rsquo;s loading speeds. Additionally, GDPR compliance requires companies using Google Analytics to gain explicit user consent for data collection. Personally, I just want a simple analytics - not a full-blown suite of tools.</p>
<h2 id="what-is-goatcounter">What is Goatcounter</h2>
<p>After careful consideration, I chose <a href="https://www.goatcounter.com/">Goatcounter</a>. It&rsquo;s a minimal, opensource analytics tool that is easy to configure, privacy-aware, and lightweight. Like Google Analytics, I easily integrated it using a single script:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">data-goatcounter</span><span class="o">=</span><span class="s">&#34;https://yoursite.goatcounter.com/count&#34;</span> <span class="na">async</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;//gc.zgo.at/count.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span></span></span></code></pre></div><p>It provides a streamlined interface that gives exactly what I&rsquo;m looking for:</p>
<p><img src="images/HJEk0H.webp" alt="image of goatcounter analytics for how.wtf"></p>
<h2 id="why-i-chose-goatcounter">Why I chose Goatcounter</h2>
<p>Philosophically, I prefer minimalism. Goatcounter met my preferences and provided a <em>streamlined</em> integration and set up process. After a few clicks to setup my account, I immediately had analytics flowing. There&rsquo;s always the option to self-host in the future, which is awesome!</p>
<p>To summarize here are my top reasons:</p>
<ol>
<li>Open-source</li>
<li>Dead simple UI</li>
<li>Small (~3.5kb script)</li>
<li>Privacy-first</li>
<li><a href="https://www.goatcounter.com/help/gdpr#conclusion-306">Seemingly GDPR compliant</a></li>
<li>Self-hosted option</li>
<li>API is <em>easy</em> to use if I ever need to</li>
<li>JavaScript-free options such as <a href="https://www.goatcounter.com/help/pixel">pixel tracking</a> or <a href="https://www.goatcounter.com/help/logfile">logfile parsing</a></li>
</ol>
]]></content:encoded></item><item><title>How to get top used Linux commands</title><link>https://how.wtf/how-to-get-top-used-linux-commands.html</link><pubDate>Wed, 27 Dec 2023 18:30:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-get-top-used-linux-commands.html</guid><description>Retrieving the top 10 used commands in Linux is simple using the history command.
What is the history command The history command, as its name implies, is used to view previously executed commands. It&amp;rsquo;s API is minimal and easy to use.
How to view top used commands in Linux Using a combination of history and awk, we can pull the top 10 commands like this:
1history | 2 awk &amp;#39;{CMD[$1]++;count++;}END { for (a in CMD)print CMD[a] &amp;#34; &amp;#34; CMD[a]/count*100 &amp;#34;% &amp;#34; a;}&amp;#39; | 3 grep -v &amp;#34;.</description><content:encoded><![CDATA[<p><img src="images/ZMV2NF.webp" alt="how to use the history command to fetch the top used linux commands"></p>
<p>Retrieving the top 10 used commands in Linux is simple using the <code>history</code> command.</p>
<h2 id="what-is-the-history-command">What is the history command</h2>
<p>The <code>history</code> command, as its name implies, is used to view previously executed commands. It&rsquo;s API is minimal and easy to use.</p>
<h2 id="how-to-view-top-used-commands-in-linux">How to view top used commands in Linux</h2>
<p>Using a combination of <code>history</code> and <code>awk</code>, we can pull the top 10 commands like this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">history</span> <span class="p">|</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    awk <span class="s1">&#39;{CMD[$1]++;count++;}END { for (a in CMD)print CMD[a] &#34; &#34; CMD[a]/count*100 &#34;% &#34; a;}&#39;</span> <span class="p">|</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    grep -v <span class="s2">&#34;./&#34;</span> <span class="p">|</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    sort -n -r <span class="p">|</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    head -n <span class="m">10</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">1842 26.4617% git
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">520 7.47019% export
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">389 5.58828% cd
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">262 3.76383% sfdx
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">257 3.692% npx
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">254 3.6489% npm
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">237 3.40468% nvim
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">234 3.36159% aws
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">227 3.26103% rm
</span></span><span class="line"><span class="ln">10</span><span class="cl">195 2.80132% poetry</span></span></code></pre></div><p>The <code>awk</code> command is the magic sauce. The <code>sort</code> command is used to reverse sort the list then the <code>head</code> command prints the last 10 lines.</p>
<p>If you prefer aligned columns with a counter to the left, we can use <code>nl</code> and the <code>column</code> command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">history</span> <span class="p">|</span> 
</span></span><span class="line"><span class="ln">2</span><span class="cl">    awk <span class="s1">&#39;{CMD[$1]++;count++;}END { for (a in CMD)print CMD[a] &#34; &#34; CMD[a]/count*100 &#34;% &#34; a;}&#39;</span> <span class="p">|</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    grep -v <span class="s2">&#34;./&#34;</span> <span class="p">|</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    column -c <span class="m">3</span> -s <span class="s2">&#34; &#34;</span> -t <span class="p">|</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    sort -n -r <span class="p">|</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    nl <span class="p">|</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    head -n <span class="m">10</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">    1	1842  26.4351%    git
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    2	520   7.46269%    export
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    3	389   5.58266%    cd
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    4	262   3.76005%    sfdx
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    5	257   3.68829%    npx
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    6	254   3.64524%    npm
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    7	237   3.40126%    nvim
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    8	234   3.35821%    aws
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    9	227   3.25775%    rm
</span></span><span class="line"><span class="ln">10</span><span class="cl">    10	195   2.79851%    poetry</span></span></code></pre></div><p>In my case, <code>git</code>, <code>export</code>, and <code>cd</code> are my most used commands from the terminal.</p>
]]></content:encoded></item><item><title>How to wait for all threads to finish in Python</title><link>https://how.wtf/how-to-wait-for-all-threads-to-finish-in-python.html</link><pubDate>Sun, 24 Dec 2023 23:00:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-wait-for-all-threads-to-finish-in-python.html</guid><description>For a side project, I needed to wait for multiple threads to complete before proceeding with the next step. In other words, I needed threads to behave like the Promise.all() functionality of JavaScript.
Wait for threads in Python In the sections below, we&amp;rsquo;ll discuss different methods for waitin on threads to complete in Python.
Wait for all threads to complete using start / join In simple terms, we can create the threads, append them to a list, then start and join them.</description><content:encoded><![CDATA[<p><img src="images/X9qZVG.webp" alt="waiting for threads to finish using concurrent futures in Python"></p>
<p>For a side project, I needed to wait for multiple threads to complete before proceeding with the next step. In other words, I needed threads to behave like the <code>Promise.all()</code> functionality of JavaScript.</p>
<h2 id="wait-for-threads-in-python">Wait for threads in Python</h2>
<p>In the sections below, we&rsquo;ll discuss different methods for waitin on threads to complete in Python.</p>
<h3 id="wait-for-all-threads-to-complete-using-start--join">Wait for all threads to complete using start / join</h3>
<p>In simple terms, we can create the threads, append them to a list, then <code>start</code> and <code>join</code> them.</p>
<p>For example:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">threading</span> <span class="kn">import</span> <span class="n">Thread</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">def</span> <span class="nf">work</span><span class="p">(</span><span class="n">interval_seconds</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;sleeping for </span><span class="si">{</span><span class="n">interval_seconds</span><span class="si">}</span><span class="s2"> seconds&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">interval_seconds</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;slept for </span><span class="si">{</span><span class="n">interval_seconds</span><span class="si">}</span><span class="s2"> seconds&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">threads</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">work</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,)),</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">work</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,)),</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">work</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,)),</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">threads</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="n">t</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">threads</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">    <span class="n">t</span><span class="o">.</span><span class="n">join</span><span class="p">()</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">sleeping for 1 seconds
</span></span><span class="line"><span class="ln">2</span><span class="cl">sleeping for 2 seconds
</span></span><span class="line"><span class="ln">3</span><span class="cl">sleeping for 1 seconds
</span></span><span class="line"><span class="ln">4</span><span class="cl">slept for 1 seconds
</span></span><span class="line"><span class="ln">5</span><span class="cl">slept for 1 seconds
</span></span><span class="line"><span class="ln">6</span><span class="cl">slept for 2 seconds</span></span></code></pre></div><p>This works well and may be all you need; however, there are alternatives.</p>
<h3 id="wait-for-all-threads-to-complete-using-a-threadpoolexecutor">Wait for all threads to complete using a ThreadPoolExecutor</h3>
<p>In Python 3.2, concurrent.futures <a href="https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Executor">was released</a>. The purpose was to provide a simple high-level API for asynchronously executing callables.</p>
<p>There were two classes released:</p>
<ul>
<li><a href="https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor"><code>ThreadPoolExecutor</code></a> for performing asynchronous executions using threads</li>
<li><a href="https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor"><code>ProcessPoolExecutor</code></a> for performing asynchronous executions using processes</li>
</ul>
<p>Both implement the same interface, the <code>Executor</code> class, so the examples provided below will work for either. For the purposes of this tutorial, I&rsquo;ll use the <code>ThreadPoolExecutor</code>.</p>
<p>Here is the same example from above, but using the <code>ThreadPoolExecutor</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">concurrent.futures</span> <span class="kn">import</span> <span class="n">ThreadPoolExecutor</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">def</span> <span class="nf">work</span><span class="p">(</span><span class="n">interval_seconds</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;sleeping for </span><span class="si">{</span><span class="n">interval_seconds</span><span class="si">}</span><span class="s2"> seconds&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">interval_seconds</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;slept for </span><span class="si">{</span><span class="n">interval_seconds</span><span class="si">}</span><span class="s2"> seconds&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="k">with</span> <span class="n">ThreadPoolExecutor</span><span class="p">(</span><span class="n">max_workers</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="n">e</span><span class="o">.</span><span class="n">submit</span><span class="p">(</span><span class="n">work</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">e</span><span class="o">.</span><span class="n">submit</span><span class="p">(</span><span class="n">work</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="n">e</span><span class="o">.</span><span class="n">submit</span><span class="p">(</span><span class="n">work</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">sleeping for 1 seconds
</span></span><span class="line"><span class="ln">2</span><span class="cl">sleeping for 2 seconds
</span></span><span class="line"><span class="ln">3</span><span class="cl">slept for 1 seconds
</span></span><span class="line"><span class="ln">4</span><span class="cl">sleeping for 1 seconds
</span></span><span class="line"><span class="ln">5</span><span class="cl">slept for 1 seconds
</span></span><span class="line"><span class="ln">6</span><span class="cl">slept for 2 seconds</span></span></code></pre></div><p>The <code>executor</code> provides a <code>.map</code> function for convenience as well:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">concurrent.futures</span> <span class="kn">import</span> <span class="n">ThreadPoolExecutor</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">def</span> <span class="nf">work</span><span class="p">(</span><span class="n">interval_seconds</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;sleeping for </span><span class="si">{</span><span class="n">interval_seconds</span><span class="si">}</span><span class="s2"> seconds&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">interval_seconds</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;slept for </span><span class="si">{</span><span class="n">interval_seconds</span><span class="si">}</span><span class="s2"> seconds&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="k">with</span> <span class="n">ThreadPoolExecutor</span><span class="p">(</span><span class="n">max_workers</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="n">e</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="n">work</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span></span></span></code></pre></div><h3 id="wait-for-all-threads-to-complete-and-return-their-results">Wait for all threads to complete and return their results</h3>
<p>Firing an forgetting is useful, but returning results was my use-case. Using <code>ThreadPoolExecutor</code> or <code>ProcessPoolExecutor</code> makes this <em>real</em> easy.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">concurrent.futures</span> <span class="kn">import</span> <span class="n">ThreadPoolExecutor</span><span class="p">,</span> <span class="n">as_completed</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">def</span> <span class="nf">work</span><span class="p">(</span><span class="n">interval_seconds</span><span class="p">,</span> <span class="n">order</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;sleeping for </span><span class="si">{</span><span class="n">interval_seconds</span><span class="si">}</span><span class="s2"> seconds&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">interval_seconds</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;slept for </span><span class="si">{</span><span class="n">interval_seconds</span><span class="si">}</span><span class="s2"> seconds&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="k">return</span> <span class="sa">f</span><span class="s2">&#34;task </span><span class="si">{</span><span class="n">order</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="k">with</span> <span class="n">ThreadPoolExecutor</span><span class="p">(</span><span class="n">max_workers</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">futures</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="p">[(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">)]:</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="n">futures</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">submit</span><span class="p">(</span><span class="n">work</span><span class="p">,</span> <span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="k">for</span> <span class="n">future</span> <span class="ow">in</span> <span class="n">as_completed</span><span class="p">(</span><span class="n">futures</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">future</span><span class="o">.</span><span class="n">result</span><span class="p">())</span></span></span></code></pre></div><p>In the example, I added a new parameter named <code>order</code> that represents when the item was queued.</p>
<ul>
<li>The first job takes 1 second and returns 1</li>
<li>The second job takes 2 seconds and returns 2</li>
<li>The third job takes 1 seconds and returns 3</li>
</ul>
<p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">sleeping for 1 seconds
</span></span><span class="line"><span class="ln">2</span><span class="cl">sleeping for 2 seconds
</span></span><span class="line"><span class="ln">3</span><span class="cl">slept for 1 seconds
</span></span><span class="line"><span class="ln">4</span><span class="cl">sleeping for 1 seconds
</span></span><span class="line"><span class="ln">5</span><span class="cl">slept for 2 seconds
</span></span><span class="line"><span class="ln">6</span><span class="cl">slept for 1 seconds
</span></span><span class="line"><span class="ln">7</span><span class="cl">task 2
</span></span><span class="line"><span class="ln">8</span><span class="cl">task 1
</span></span><span class="line"><span class="ln">9</span><span class="cl">task 3</span></span></code></pre></div><h3 id="wait-for-all-threads-to-complete-and-return-their-results-in-order">Wait for all threads to complete and return their results in order</h3>
<p>In the last example, the results where returned out of order. Just a small tweak enables the futures to be in order:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">concurrent.futures</span> <span class="kn">import</span> <span class="n">ThreadPoolExecutor</span><span class="p">,</span> <span class="n">as_completed</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">def</span> <span class="nf">work</span><span class="p">(</span><span class="n">interval_seconds</span><span class="p">,</span> <span class="n">order</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;sleeping for </span><span class="si">{</span><span class="n">interval_seconds</span><span class="si">}</span><span class="s2"> seconds&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">interval_seconds</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;slept for </span><span class="si">{</span><span class="n">interval_seconds</span><span class="si">}</span><span class="s2"> seconds&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="k">return</span> <span class="sa">f</span><span class="s2">&#34;task </span><span class="si">{</span><span class="n">order</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="k">with</span> <span class="n">ThreadPoolExecutor</span><span class="p">(</span><span class="n">max_workers</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">futures</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="p">[(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">)]:</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="n">futures</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">submit</span><span class="p">(</span><span class="n">work</span><span class="p">,</span> <span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="k">for</span> <span class="n">future</span> <span class="ow">in</span> <span class="n">futures</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">future</span><span class="o">.</span><span class="n">result</span><span class="p">())</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">sleeping for 1 seconds
</span></span><span class="line"><span class="ln">2</span><span class="cl">sleeping for 2 seconds
</span></span><span class="line"><span class="ln">3</span><span class="cl">slept for 1 seconds
</span></span><span class="line"><span class="ln">4</span><span class="cl">sleeping for 1 seconds
</span></span><span class="line"><span class="ln">5</span><span class="cl">slept for 2 seconds
</span></span><span class="line"><span class="ln">6</span><span class="cl">slept for 1 seconds
</span></span><span class="line"><span class="ln">7</span><span class="cl">task 1
</span></span><span class="line"><span class="ln">8</span><span class="cl">task 2
</span></span><span class="line"><span class="ln">9</span><span class="cl">task 3</span></span></code></pre></div><h3 id="promiseall-and-promiseallsettled-using-threads">Promise.all and Promise.allSettled using threads</h3>
<p>For the last topic, I want to replicate the interface that NodeJS provides: <code>Promise.all()</code> and <code>Promise.allSettled()</code>.</p>
<p>If you&rsquo;re unfamiliar, <code>await Promise.all()</code> waits for all the fulfilled promises to complete. If a rejection occurs, it throws an exception. <code>Promise.allSettled()</code> waits for all promises to be rejected or fulfilled without throwing an exception.</p>
<p>To replicate the functionality using <code>concurrent.futures</code>, I created a <code>Job</code> <code>dataclass</code> that has three properties:</p>
<ol>
<li>The <code>Callable</code> (ie. function) that will be called for the job</li>
<li>The <code>Tuple</code> of positional arguments that will be passed to the job</li>
<li>The <code>dict[str, Any]</code> of keyword arguments that will be passed to the job</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">concurrent.futures</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Callable</span><span class="p">,</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Tuple</span><span class="p">,</span> <span class="n">Optional</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="k">def</span> <span class="nf">work</span><span class="p">(</span><span class="n">interval_seconds</span><span class="p">,</span> <span class="n">order</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;sleeping for </span><span class="si">{</span><span class="n">interval_seconds</span><span class="si">}</span><span class="s2"> seconds&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">interval_seconds</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;slept for </span><span class="si">{</span><span class="n">interval_seconds</span><span class="si">}</span><span class="s2"> seconds&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="k">return</span> <span class="sa">f</span><span class="s2">&#34;task </span><span class="si">{</span><span class="n">order</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="nd">@dataclass</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="k">class</span> <span class="nc">Job</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="n">func</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[</span><span class="o">...</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="n">args</span><span class="p">:</span> <span class="n">Tuple</span><span class="p">[</span><span class="n">Any</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span> <span class="o">=</span> <span class="p">()</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="n">kwargs</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl">    <span class="k">def</span> <span class="nf">execute</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span> <span class="ow">or</span> <span class="p">{}))</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">
</span></span><span class="line"><span class="ln">24</span><span class="cl">
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="k">def</span> <span class="nf">all</span><span class="p">(</span><span class="n">jobs</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">    <span class="k">with</span> <span class="n">concurrent</span><span class="o">.</span><span class="n">futures</span><span class="o">.</span><span class="n">ThreadPoolExecutor</span><span class="p">()</span> <span class="k">as</span> <span class="n">executor</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">        <span class="n">futures</span> <span class="o">=</span> <span class="p">[</span><span class="n">executor</span><span class="o">.</span><span class="n">submit</span><span class="p">(</span><span class="n">job</span><span class="o">.</span><span class="n">execute</span><span class="p">)</span> <span class="k">for</span> <span class="n">job</span> <span class="ow">in</span> <span class="n">jobs</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">        <span class="k">return</span> <span class="p">[</span><span class="n">f</span><span class="o">.</span><span class="n">result</span><span class="p">()</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">futures</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">
</span></span><span class="line"><span class="ln">30</span><span class="cl">
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="n">jobs</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">    <span class="n">Job</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">work</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)),</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">    <span class="n">Job</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">work</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">)),</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">    <span class="n">Job</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">work</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">)),</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">
</span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="n">results</span> <span class="o">=</span> <span class="nb">all</span><span class="p">(</span><span class="n">jobs</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">results</span><span class="p">)</span></span></span></code></pre></div><p>The <code>all(jobs)</code> function accepts a list of jobs to complete.</p>
<p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">sleeping for 1 seconds
</span></span><span class="line"><span class="ln">2</span><span class="cl">sleeping for 2 seconds
</span></span><span class="line"><span class="ln">3</span><span class="cl">sleeping for 1 seconds
</span></span><span class="line"><span class="ln">4</span><span class="cl">slept for 1 seconds
</span></span><span class="line"><span class="ln">5</span><span class="cl">slept for 1 seconds
</span></span><span class="line"><span class="ln">6</span><span class="cl">slept for 2 seconds
</span></span><span class="line"><span class="ln">7</span><span class="cl">[&#39;task 1&#39;, &#39;task 2&#39;, &#39;task 3&#39;]</span></span></code></pre></div><p>We can extend the prior example by adding a <code>all_settled</code> function and a <code>JobResult</code> <code>dataclass</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">concurrent.futures</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Callable</span><span class="p">,</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Tuple</span><span class="p">,</span> <span class="n">Optional</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="k">def</span> <span class="nf">work</span><span class="p">(</span><span class="n">interval_seconds</span><span class="p">,</span> <span class="n">order</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;sleeping for </span><span class="si">{</span><span class="n">interval_seconds</span><span class="si">}</span><span class="s2"> seconds&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">interval_seconds</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;slept for </span><span class="si">{</span><span class="n">interval_seconds</span><span class="si">}</span><span class="s2"> seconds&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="k">return</span> <span class="sa">f</span><span class="s2">&#34;task </span><span class="si">{</span><span class="n">order</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="nd">@dataclass</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="k">class</span> <span class="nc">JobResult</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="n">status</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="n">value</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="n">reason</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="ne">Exception</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="nd">@dataclass</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="k">class</span> <span class="nc">Job</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">    <span class="n">func</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[</span><span class="o">...</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="n">args</span><span class="p">:</span> <span class="n">Tuple</span><span class="p">[</span><span class="n">Any</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span> <span class="o">=</span> <span class="p">()</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">    <span class="n">kwargs</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">
</span></span><span class="line"><span class="ln">28</span><span class="cl">    <span class="k">def</span> <span class="nf">execute</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span> <span class="ow">or</span> <span class="p">{}))</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">
</span></span><span class="line"><span class="ln">31</span><span class="cl">
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="k">def</span> <span class="nf">all</span><span class="p">(</span><span class="n">jobs</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">    <span class="k">with</span> <span class="n">concurrent</span><span class="o">.</span><span class="n">futures</span><span class="o">.</span><span class="n">ThreadPoolExecutor</span><span class="p">()</span> <span class="k">as</span> <span class="n">executor</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">        <span class="n">futures</span> <span class="o">=</span> <span class="p">[</span><span class="n">executor</span><span class="o">.</span><span class="n">submit</span><span class="p">(</span><span class="n">job</span><span class="o">.</span><span class="n">execute</span><span class="p">)</span> <span class="k">for</span> <span class="n">job</span> <span class="ow">in</span> <span class="n">jobs</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">        <span class="k">return</span> <span class="p">[</span><span class="n">f</span><span class="o">.</span><span class="n">result</span><span class="p">()</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">futures</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">
</span></span><span class="line"><span class="ln">37</span><span class="cl">
</span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="k">def</span> <span class="nf">all_settled</span><span class="p">(</span><span class="n">jobs</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl">    <span class="k">with</span> <span class="n">concurrent</span><span class="o">.</span><span class="n">futures</span><span class="o">.</span><span class="n">ThreadPoolExecutor</span><span class="p">()</span> <span class="k">as</span> <span class="n">executor</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl">        <span class="n">futures</span> <span class="o">=</span> <span class="p">[</span><span class="n">executor</span><span class="o">.</span><span class="n">submit</span><span class="p">(</span><span class="n">job</span><span class="o">.</span><span class="n">execute</span><span class="p">)</span> <span class="k">for</span> <span class="n">job</span> <span class="ow">in</span> <span class="n">jobs</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">        <span class="n">concurrent</span><span class="o">.</span><span class="n">futures</span><span class="o">.</span><span class="n">wait</span><span class="p">(</span><span class="n">futures</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl">
</span></span><span class="line"><span class="ln">43</span><span class="cl">        <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">44</span><span class="cl">        <span class="k">for</span> <span class="n">future</span> <span class="ow">in</span> <span class="n">futures</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">45</span><span class="cl">            <span class="k">if</span> <span class="n">future</span><span class="o">.</span><span class="n">exception</span><span class="p">():</span>
</span></span><span class="line"><span class="ln">46</span><span class="cl">                <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">JobResult</span><span class="p">(</span><span class="n">status</span><span class="o">=</span><span class="s2">&#34;rejected&#34;</span><span class="p">,</span> <span class="n">reason</span><span class="o">=</span><span class="n">future</span><span class="o">.</span><span class="n">exception</span><span class="p">()))</span>
</span></span><span class="line"><span class="ln">47</span><span class="cl">            <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">48</span><span class="cl">                <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">JobResult</span><span class="p">(</span><span class="n">status</span><span class="o">=</span><span class="s2">&#34;fulfilled&#34;</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="n">future</span><span class="o">.</span><span class="n">result</span><span class="p">()))</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl">        <span class="k">return</span> <span class="n">results</span>
</span></span><span class="line"><span class="ln">50</span><span class="cl">
</span></span><span class="line"><span class="ln">51</span><span class="cl">
</span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="n">jobs</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">53</span><span class="cl">    <span class="n">Job</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">work</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)),</span>
</span></span><span class="line"><span class="ln">54</span><span class="cl">    <span class="n">Job</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">work</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">)),</span>
</span></span><span class="line"><span class="ln">55</span><span class="cl">    <span class="n">Job</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">work</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">)),</span>
</span></span><span class="line"><span class="ln">56</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">57</span><span class="cl">
</span></span><span class="line"><span class="ln">58</span><span class="cl"><span class="n">results</span> <span class="o">=</span> <span class="n">all_settled</span><span class="p">(</span><span class="n">jobs</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">59</span><span class="cl"><span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">60</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">r</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">sleeping for 1 seconds
</span></span><span class="line"><span class="ln">2</span><span class="cl">sleeping for 2 seconds
</span></span><span class="line"><span class="ln">3</span><span class="cl">sleeping for 1 seconds
</span></span><span class="line"><span class="ln">4</span><span class="cl">slept for 1 seconds
</span></span><span class="line"><span class="ln">5</span><span class="cl">slept for 1 seconds
</span></span><span class="line"><span class="ln">6</span><span class="cl">slept for 2 seconds
</span></span><span class="line"><span class="ln">7</span><span class="cl">JobResult(status=&#39;fulfilled&#39;, value=&#39;task 1&#39;, reason=None)
</span></span><span class="line"><span class="ln">8</span><span class="cl">JobResult(status=&#39;fulfilled&#39;, value=&#39;task 2&#39;, reason=None)
</span></span><span class="line"><span class="ln">9</span><span class="cl">JobResult(status=&#39;fulfilled&#39;, value=&#39;task 3&#39;, reason=None)</span></span></code></pre></div>]]></content:encoded></item><item><title>Stable Diffusion with Amazon Bedrock Python boto3</title><link>https://how.wtf/stable-diffusion-with-amazon-bedrock-python-boto3.html</link><pubDate>Fri, 22 Dec 2023 02:00:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/stable-diffusion-with-amazon-bedrock-python-boto3.html</guid><description>Amazon Bedrock is a managed service provided by AWS that allows users to invoke models. For more information about the service, please refer to their user guide here.
For this article, we&amp;rsquo;re going to focus on how to invoke the Stable Diffusion model using the Python SDK: boto3. If you want to learn about the Amazon Bedrock SDK in general or how to invoke Claude with it, I have an article here that goes into detail.</description><content:encoded><![CDATA[<p><img src="images/MGTrlU.webp" alt="invoking amazon bedrock runtime stable diffusion model"></p>
<p>Amazon Bedrock is a managed service provided by AWS that allows users to invoke models. For more information about the service, please refer to their <a href="https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html">user guide here</a>.</p>
<p>For this article, we&rsquo;re going to focus on how to invoke the Stable Diffusion model using the Python SDK: <code>boto3</code>. If you want to learn about the Amazon Bedrock SDK in general or how to invoke Claude with it, I have an <a href="https://how.wtf/amazon-bedrock-runtime-examples-using-boto3.html">article here</a> that goes into detail.</p>
<h2 id="what-is-stable-diffusion">What is Stable Diffusion</h2>
<p>Stable diffusion is a text-to-image model first released in 2022. The term &ldquo;diffusion&rdquo; originates from <a href="https://en.wikipedia.org/wiki/Diffusion_model">diffusion models</a> in machine learning. OpenAI&rsquo;s DALL-E 2 is another example of a model that leverages diffusion. It&rsquo;s open source, free, and easy to run! In addition, it has an active community and a plethora of how-to tutorials.</p>
<p>For more information about Stable Diffusion, check out the <a href="https://aws.amazon.com/what-is/stable-diffusion/">AWS write up</a> about it.</p>
<h2 id="how-use-stable-diffusion-with-amazon-bedrock">How use Stable Diffusion with Amazon Bedrock</h2>
<p>For this article, we&rsquo;ll be leveraging the Python AWS SDK: <code>boto3</code> to call the Stable Diffusion model.</p>
<h3 id="install-boto3">Install boto3</h3>
<p>Let&rsquo;s begin by installing the latest version of <code>boto3</code> and the Python image library <code>PIL</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip3 install boto3 Pillow</span></span></code></pre></div><h3 id="lookup-the-model-inference-parameters">Lookup the model inference parameters</h3>
<p>Each model has specific inference parameters that must be supplied to Bedrock.</p>
<p>As of time of writing, Dec. 22nd 2023, the supported <a href="https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-diffusion-1-0-text-image.html">inference parameters for Stable Diffusion 1.0 text-to-image are</a>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">{
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    &#34;text_prompts&#34;: [
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        {
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">            &#34;text&#34;: string,
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">            &#34;weight&#34;: float
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        }
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    ],
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    &#34;height&#34;: int,
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    &#34;width&#34;: int,
</span></span><span class="line"><span class="ln">10</span><span class="cl">    &#34;cfg_scale&#34;: float,
</span></span><span class="line"><span class="ln">11</span><span class="cl">    &#34;clip_guidance_preset&#34;: string,
</span></span><span class="line"><span class="ln">12</span><span class="cl">    &#34;sampler&#34;: string,
</span></span><span class="line"><span class="ln">13</span><span class="cl">    &#34;samples&#34;,
</span></span><span class="line"><span class="ln">14</span><span class="cl">    &#34;seed&#34;: int,
</span></span><span class="line"><span class="ln">15</span><span class="cl">    &#34;steps&#34;: int,
</span></span><span class="line"><span class="ln">16</span><span class="cl">    &#34;style_preset&#34;: string,
</span></span><span class="line"><span class="ln">17</span><span class="cl">    &#34;extras&#34;: JSON object     
</span></span><span class="line"><span class="ln">18</span><span class="cl">}</span></span></code></pre></div><p>The smallest payload we can send is this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{
</span></span><span class="line"><span class="ln">2</span><span class="cl">    &#34;text_prompts&#34;: [{&#34;text&#34;: string}]
</span></span><span class="line"><span class="ln">3</span><span class="cl">}</span></span></code></pre></div><h3 id="use-the-invoke_model-api">Use the invoke_model API</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">base64</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="nn">io</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kn">from</span> <span class="nn">PIL</span> <span class="kn">import</span> <span class="n">Image</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">,</span> <span class="n">region_name</span><span class="o">=</span><span class="s2">&#34;us-east-1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">body</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;text_prompts&#34;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;A blue bird&#34;</span><span class="p">}]}</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">invoke_model</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">body</span><span class="o">=</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">body</span><span class="p">),</span> <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;stability.stable-diffusion-xl&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="n">response_body</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="p">[</span><span class="s2">&#34;body&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="n">finish_reason</span> <span class="o">=</span> <span class="n">response_body</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;artifacts&#34;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;finishReason&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="k">if</span> <span class="n">finish_reason</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&#34;ERROR&#34;</span><span class="p">,</span> <span class="s2">&#34;CONTENT_FILTERED&#34;</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Image error: </span><span class="si">{</span><span class="n">finish_reason</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="n">base64_image</span> <span class="o">=</span> <span class="n">response_body</span><span class="p">[</span><span class="s2">&#34;artifacts&#34;</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s2">&#34;base64&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="n">base64_bytes</span> <span class="o">=</span> <span class="n">base64_image</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&#34;ascii&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="n">image_bytes</span> <span class="o">=</span> <span class="n">base64</span><span class="o">.</span><span class="n">b64decode</span><span class="p">(</span><span class="n">base64_bytes</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="n">image</span> <span class="o">=</span> <span class="n">Image</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">(</span><span class="n">image_bytes</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="n">image</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></span></span></code></pre></div><p>Here is the line-by-line breakdown of the code above:</p>
<ul>
<li>Instantiate the <code>boto3.client(&quot;bedrock-runtime&quot;)</code> client with a <code>region_name</code> of <code>us-east-1</code>.</li>
<li><code>json.dumps</code> a dictionary of Stable Diffusion&rsquo;s required inference parameters</li>
<li>Invoke the model by specifying the <code>body</code> (string) and <code>modelId</code></li>
<li>If the <code>finishReason</code> is <code>ERROR</code> or <code>CONTENT_FILTERED</code>, raise an error</li>
<li>Convert the <code>response_body</code> to the necessary types for <code>PIL.Image</code></li>
<li>Use <code>image.show()</code> to display a simple gui with the image</li>
</ul>
<p>Output:</p>
<p><img src="images/t1MP6o.webp" alt="stable diffusion output using Amazon Bedrock"></p>
]]></content:encoded></item><item><title>Invoke Amazon Bedrock models from Step Functions with AWS CDK</title><link>https://how.wtf/invoke-amazon-bedrock-models-from-step-functions-with-aws-cdk.html</link><pubDate>Wed, 20 Dec 2023 02:30:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/invoke-amazon-bedrock-models-from-step-functions-with-aws-cdk.html</guid><description>AWS released an optimized integration for Amazon Bedrock. It allows StepFunction statemachines to directly call the Amazon Bedrock API without needing to write a Lambda function.
How to deploy a StepFunction with Amazon Bedrock integration using AWS CDK Follow the instructions below to deploy a StepFunction with Amazon Bedrock integration using the AWS CDK. The following tutorial uses Python, but the same principles can be used with any language.</description><content:encoded><![CDATA[<p><img src="images/nauk58.webp" alt="invoke Amazon bedrock models directly from Step Function statemachines"></p>
<p>AWS released an <a href="https://aws.amazon.com/about-aws/whats-new/2023/11/aws-step-functions-optimized-integration-bedrock/">optimized integration</a> for Amazon Bedrock. It allows StepFunction statemachines to directly call the Amazon Bedrock API without needing to write a Lambda function.</p>
<h2 id="how-to-deploy-a-stepfunction-with-amazon-bedrock-integration-using-aws-cdk">How to deploy a StepFunction with Amazon Bedrock integration using AWS CDK</h2>
<p>Follow the instructions below to deploy a StepFunction with Amazon Bedrock integration using the AWS CDK. The following tutorial uses Python, but the same principles can be used with any language.</p>
<h3 id="create-a-requirementstxt">Create a requirements.txt</h3>
<p>For this tutorial, version 2.115.0 of the AWS CDK was used.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">aws-cdk-lib==2.115.0
</span></span><span class="line"><span class="ln">2</span><span class="cl">constructs&gt;=10.0.0,&lt;11.0.0</span></span></code></pre></div><h3 id="install-the-dependencies">Install the dependencies</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip3 install -r requirements.txt</span></span></code></pre></div><h3 id="create-stackpy-with-the-step-function-and-bedrock-task">Create stack.py with the step function and bedrock task</h3>
<p>For this tutorial, I opted to use the Claude V1 instant model. If you&rsquo;re unsure where the <code>sfn.TaskInput.from_object()</code> parameters originate from, please review my <a href="https://how.wtf/amazon-bedrock-runtime-examples-using-boto3.html">article describing how to invoke Bedrock models directly</a>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_cdk</span> <span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="n">App</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="n">CfnOutput</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="n">Stack</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="n">aws_stepfunctions</span> <span class="k">as</span> <span class="n">sfn</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">aws_stepfunctions_tasks</span> <span class="k">as</span> <span class="n">tasks</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">aws_bedrock</span> <span class="k">as</span> <span class="n">bedrock</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="k">class</span> <span class="nc">StepFunctionBedrockStack</span><span class="p">(</span><span class="n">Stack</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scope</span><span class="p">:</span> <span class="n">App</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">scope</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="n">model</span> <span class="o">=</span> <span class="n">bedrock</span><span class="o">.</span><span class="n">FoundationModel</span><span class="o">.</span><span class="n">from_foundation_model_id</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">            <span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;Model&#34;</span><span class="p">,</span> <span class="n">bedrock</span><span class="o">.</span><span class="n">FoundationModelIdentifier</span><span class="o">.</span><span class="n">ANTHROPIC_CLAUDE_INSTANT_V1</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">        <span class="n">invoke_model_task</span> <span class="o">=</span> <span class="n">tasks</span><span class="o">.</span><span class="n">BedrockInvokeModel</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">            <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">            <span class="s2">&#34;InvokeModel&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">            <span class="n">model</span><span class="o">=</span><span class="n">model</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">            <span class="n">body</span><span class="o">=</span><span class="n">sfn</span><span class="o">.</span><span class="n">TaskInput</span><span class="o">.</span><span class="n">from_object</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">                    <span class="s2">&#34;prompt&#34;</span><span class="p">:</span> <span class="s2">&#34;</span><span class="se">\n\n</span><span class="s2">Human:Give me a cowboy joke</span><span class="se">\n\n</span><span class="s2">Assistant:&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">                    <span class="s2">&#34;max_tokens_to_sample&#34;</span><span class="p">:</span> <span class="mi">256</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">            <span class="p">),</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">            <span class="n">result_selector</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;joke&#34;</span><span class="p">:</span> <span class="n">sfn</span><span class="o">.</span><span class="n">JsonPath</span><span class="o">.</span><span class="n">string_at</span><span class="p">(</span><span class="s2">&#34;$.Body.completion&#34;</span><span class="p">)},</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">        <span class="n">state_machine</span> <span class="o">=</span> <span class="n">sfn</span><span class="o">.</span><span class="n">StateMachine</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">            <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">            <span class="s2">&#34;StateMachine&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">            <span class="n">definition_body</span><span class="o">=</span><span class="n">sfn</span><span class="o">.</span><span class="n">DefinitionBody</span><span class="o">.</span><span class="n">from_chainable</span><span class="p">(</span><span class="n">invoke_model_task</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">
</span></span><span class="line"><span class="ln">36</span><span class="cl">        <span class="n">CfnOutput</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;StateMachineArn&#34;</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="n">state_machine</span><span class="o">.</span><span class="n">state_machine_arn</span><span class="p">)</span></span></span></code></pre></div><p>The code above creates a <code>BedrockInvokeModel</code> task with a <code>body</code> that&rsquo;s specific for Anthropic Claude&rsquo;s input and a <code>result_selector</code> that extracts the <code>completion</code>.</p>
<h3 id="create-apppy">Create app.py</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk</span> <span class="k">as</span> <span class="nn">cdk</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="kn">from</span> <span class="nn">stack</span> <span class="kn">import</span> <span class="n">StepFunctionBedrockStack</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">app</span> <span class="o">=</span> <span class="n">cdk</span><span class="o">.</span><span class="n">App</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="n">StepFunctionBedrockStack</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="s2">&#34;StepFunctionBedrockStack&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="n">app</span><span class="o">.</span><span class="n">synth</span><span class="p">()</span></span></span></code></pre></div><h3 id="create-cdkjson">Create cdk.json</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;app&#34;</span><span class="p">:</span> <span class="s2">&#34;python3 app.py&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>The directory structure should look like this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">project/
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── app.py
</span></span><span class="line"><span class="ln">3</span><span class="cl">├── cdk.json
</span></span><span class="line"><span class="ln">4</span><span class="cl">├── requirements.txt
</span></span><span class="line"><span class="ln">5</span><span class="cl">└── stack.py</span></span></code></pre></div><h3 id="deploy-the-stack">Deploy the stack</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">cdk deploy</span></span></code></pre></div><p>Because of the <code>CfnOutput</code>, the statemachine&rsquo;s arn is in an output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Outputs:
</span></span><span class="line"><span class="ln">2</span><span class="cl">StepFunctionBedrockStack.StateMachineArn = arn:aws:states:us-east-1:0123456789101:stateMachine:StateMachine2E01A3A5-GeJycj800pUN</span></span></code></pre></div><h3 id="start-a-statemachine-execution">Start a statemachine execution</h3>
<p>With the statemachine name, we can start an execution using the AWS CLI:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws stepfunctions start-execution  <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --state-machine-arn &lt;statemachine arn here&gt;</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;executionArn&#34;</span><span class="p">:</span> <span class="s2">&#34;arn:aws:states:us-east-1:0123456789101:execution:StateMachine2E01A3A5-GeJycj800pUN:387b0976-feb6-4c8c-9abe-af427546df3c&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nt">&#34;startDate&#34;</span><span class="p">:</span> <span class="s2">&#34;2023-12-20T01:48:56.396000-05:00&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>then, we can describe the execution using the execution arn:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws stepfunctions describe-execution <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --execution-arn &lt;execution arn here&gt;</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="nt">&#34;executionArn&#34;</span><span class="p">:</span> <span class="s2">&#34;arn:aws:states:us-east-1:0123456789101:execution:StateMachine2E01A3A5-GeJycj800pUN:387b0976-feb6-4c8c-9abe-af427546df3c&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="nt">&#34;stateMachineArn&#34;</span><span class="p">:</span> <span class="s2">&#34;arn:aws:states:us-east-1:0123456789101:stateMachine:StateMachine2E01A3A5-GeJycj800pUN&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;387b0976-feb6-4c8c-9abe-af427546df3c&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="nt">&#34;status&#34;</span><span class="p">:</span> <span class="s2">&#34;SUCCEEDED&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="nt">&#34;startDate&#34;</span><span class="p">:</span> <span class="s2">&#34;2023-12-20T01:48:56.396000-05:00&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="nt">&#34;stopDate&#34;</span><span class="p">:</span> <span class="s2">&#34;2023-12-20T01:48:57.814000-05:00&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="nt">&#34;input&#34;</span><span class="p">:</span> <span class="s2">&#34;{}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="nt">&#34;inputDetails&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="nt">&#34;included&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="nt">&#34;output&#34;</span><span class="p">:</span> <span class="s2">&#34;{\&#34;joke\&#34;:\&#34; Here&#39;s one: Why don&#39;t seagulls fly over the bay? Because then they&#39;d be bagels!\&#34;}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="nt">&#34;outputDetails&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">        <span class="nt">&#34;included&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="nt">&#34;redriveCount&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="nt">&#34;redriveStatus&#34;</span><span class="p">:</span> <span class="s2">&#34;NOT_REDRIVABLE&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="nt">&#34;redriveStatusReason&#34;</span><span class="p">:</span> <span class="s2">&#34;Execution is SUCCEEDED and cannot be redriven&#34;</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h3 id="pass-information-from-the-statemachine-input-to-bedrock">Pass information from the statemachine input to Bedrock</h3>
<p>If you want to pass the input to the foundational model, you can do this using a combination of:</p>
<p><code>sfn.JsonPatch.string_at()</code> and <code>States.Format</code> intrinsic function</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_cdk</span> <span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="n">App</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="n">CfnOutput</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="n">Stack</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="n">aws_stepfunctions</span> <span class="k">as</span> <span class="n">sfn</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">aws_stepfunctions_tasks</span> <span class="k">as</span> <span class="n">tasks</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">aws_bedrock</span> <span class="k">as</span> <span class="n">bedrock</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="k">class</span> <span class="nc">StepFunctionBedrockStack</span><span class="p">(</span><span class="n">Stack</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scope</span><span class="p">:</span> <span class="n">App</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">scope</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="n">model</span> <span class="o">=</span> <span class="n">bedrock</span><span class="o">.</span><span class="n">FoundationModel</span><span class="o">.</span><span class="n">from_foundation_model_id</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">            <span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;Model&#34;</span><span class="p">,</span> <span class="n">bedrock</span><span class="o">.</span><span class="n">FoundationModelIdentifier</span><span class="o">.</span><span class="n">ANTHROPIC_CLAUDE_INSTANT_V1</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">        <span class="n">invoke_model_task</span> <span class="o">=</span> <span class="n">tasks</span><span class="o">.</span><span class="n">BedrockInvokeModel</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">            <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">            <span class="s2">&#34;InvokeModel&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">            <span class="n">model</span><span class="o">=</span><span class="n">model</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">            <span class="n">body</span><span class="o">=</span><span class="n">sfn</span><span class="o">.</span><span class="n">TaskInput</span><span class="o">.</span><span class="n">from_object</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">                    <span class="s2">&#34;prompt&#34;</span><span class="p">:</span> <span class="n">sfn</span><span class="o">.</span><span class="n">JsonPath</span><span class="o">.</span><span class="n">string_at</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">                        <span class="s2">&#34;States.Format(&#39;</span><span class="se">\n\n</span><span class="s2">Human:</span><span class="si">{}</span><span class="se">\n\n</span><span class="s2">Assistant:&#39;, $$.Execution.Input.prompt)&#34;</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">                    <span class="p">),</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">                    <span class="s2">&#34;max_tokens_to_sample&#34;</span><span class="p">:</span> <span class="mi">256</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">            <span class="p">),</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">            <span class="n">result_selector</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;joke&#34;</span><span class="p">:</span> <span class="n">sfn</span><span class="o">.</span><span class="n">JsonPath</span><span class="o">.</span><span class="n">string_at</span><span class="p">(</span><span class="s2">&#34;$.Body.completion&#34;</span><span class="p">)},</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">        <span class="n">state_machine</span> <span class="o">=</span> <span class="n">sfn</span><span class="o">.</span><span class="n">StateMachine</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">            <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">            <span class="s2">&#34;StateMachine&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">            <span class="n">definition_body</span><span class="o">=</span><span class="n">sfn</span><span class="o">.</span><span class="n">DefinitionBody</span><span class="o">.</span><span class="n">from_chainable</span><span class="p">(</span><span class="n">invoke_model_task</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">
</span></span><span class="line"><span class="ln">38</span><span class="cl">        <span class="n">CfnOutput</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;StateMachineArn&#34;</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="n">state_machine</span><span class="o">.</span><span class="n">state_machine_arn</span><span class="p">)</span></span></span></code></pre></div><p>Now we can start the statemachine execution with a prompt:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws stepfunctions start-execution  <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --state-machine-arn &lt;statemachine arn here&gt; <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --input <span class="s1">&#39;{&#34;prompt&#34;: &#34;Write me a joke&#34;}&#39;</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Amazon Bedrock Runtime examples using boto3</title><link>https://how.wtf/amazon-bedrock-runtime-examples-using-boto3.html</link><pubDate>Sun, 17 Dec 2023 00:55:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/amazon-bedrock-runtime-examples-using-boto3.html</guid><description>Amazon Bedrock is a managed service provided by AWS that provides foundational models at your fingertips through a unified API. The service offers a range of features including foundational model invocations, fine-tuning, agents, guardrails, knowledge base searching, and more!
To read more about the service offerings, refer to its documentation.
What is Amazon Bedrock Runtime? For this article, we&amp;rsquo;ll dive into using the Python AWS SDK, boto3, to call foundational models.</description><content:encoded><![CDATA[<p><img src="images/xmzH72.webp" alt="how to invoke amazon bedrock runtime using boto3"></p>
<p>Amazon Bedrock is a managed service provided by AWS that provides foundational models at your fingertips through a unified API. The service offers a range of features including foundational model invocations, fine-tuning, agents, guardrails, knowledge base searching, and more!</p>
<p>To read more about the service offerings, refer to its <a href="https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html">documentation</a>.</p>
<h2 id="what-is-amazon-bedrock-runtime">What is Amazon Bedrock Runtime?</h2>
<p>For this article, we&rsquo;ll dive into using the Python AWS SDK, <code>boto3</code>, to call foundational models. <a href="https://docs.aws.amazon.com/bedrock/latest/APIReference/API_Operations_Amazon_Bedrock_Runtime.html">Amazon Bedrock Runtime</a> is the API entry point for invoking foundational models.</p>
<p>As of time of writing, Dec. 16th 2023, the supported <a href="https://docs.aws.amazon.com/bedrock/latest/APIReference/API_Operations_Amazon_Bedrock_Runtime.html">API actions are</a>:</p>
<ol>
<li><code>InvokeModel</code></li>
<li><code>InvokeModelWithResponseStream</code></li>
</ol>
<h2 id="how-to-call-models-using-python-boto3">How to call models using Python boto3</h2>
<h3 id="installing-boto3">Installing boto3</h3>
<p>Invoking a foundational model using the <code>InvokeModel</code> API call is easy in Python! To begin, ensure that you have <code>boto3</code> installed:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip3 install boto3</span></span></code></pre></div><h3 id="how-to-use-the-invoke_model-method">How to use the invoke_model method</h3>
<p>Let&rsquo;s instantiate the Amazon Bedrock Runtime client using boto3:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span></span></span></code></pre></div><p>then lookup the inference parameters needed for the <code>body</code> <a href="https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters.html">here</a>. For the sake of this example, I&rsquo;m invoking the Anthropic Claude model. Its inference parameters are:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;prompt&#34;</span><span class="p">:</span> <span class="s2">&#34;\n\nHuman:&lt;prompt&gt;\n\nAssistant:&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nt">&#34;temperature&#34;</span><span class="p">:</span> <span class="mf">0.5</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nt">&#34;top_p&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="nt">&#34;top_k&#34;</span><span class="p">:</span> <span class="mi">250</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="nt">&#34;max_tokens_to_sample&#34;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="nt">&#34;stop_sequences&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;\n\nHuman:&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>The bare minimum request for Claude is:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;prompt&#34;</span><span class="p">:</span> <span class="s2">&#34;\n\nHuman:&lt;prompt&gt;\n\nAssistant:&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nt">&#34;max_tokens_to_sample&#34;</span><span class="p">:</span> <span class="mi">200</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>The body passed into the client must be a file or bytes. For Claude, the <code>contentType</code> as <code>application/json</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">,</span> <span class="n">region_name</span><span class="o">=</span><span class="s2">&#34;us-east-1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">body</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="s2">&#34;prompt&#34;</span><span class="p">:</span> <span class="s2">&#34;</span><span class="se">\n\n</span><span class="s2">Human:What is your name?</span><span class="se">\n\n</span><span class="s2">Assistant:&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="s2">&#34;max_tokens_to_sample&#34;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">invoke_model</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="n">body</span><span class="o">=</span><span class="n">body</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-v2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="n">accept</span><span class="o">=</span><span class="s2">&#34;application/json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="n">contentType</span><span class="o">=</span><span class="s2">&#34;application/json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="n">response_body</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="p">[</span><span class="s2">&#34;body&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response_body</span><span class="p">)</span></span></span></code></pre></div><p>Here is the line-by-line breakdown of the code above:</p>
<ul>
<li>Instantiate the <code>boto3.client(&quot;bedrock-runtime&quot;)</code> client with a <code>region_name</code> of <code>us-east-1</code>.</li>
<li><code>json.dumps</code> a dictionary of Claude&rsquo;s required inference parameters</li>
<li>Transform the JSON string into bytes using the <code>.encode()</code> method</li>
<li>Invoke the model by specifying the body (bytes), model id, accept, and contentType parameters.</li>
<li>Convert the <code>StreamingBody</code> to a JSON encoded string using <code>.read()</code> then turn the JSON string into a dictionary using <code>json.loads</code></li>
</ul>
<p>For more information about <code>StreamingBody</code>, refer to its documentation <a href="https://botocore.amazonaws.com/v1/documentation/api/latest/reference/response.html#botocore.response.StreamingBody.read">here</a>. To keep it simple, we simply need to use the <code>read</code> method on the response body to get its contents.</p>
<p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{&#39;completion&#39;: &#39; My name is Claude.&#39;, &#39;stop_reason&#39;: &#39;stop_sequence&#39;, &#39;stop&#39;: &#39;\n\nHuman:&#39;}</span></span></code></pre></div><p>The Claude JSON output includes a <code>completion</code> attribute with the text.</p>
<p>Here&rsquo;s how to grab that information:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">,</span> <span class="n">region_name</span><span class="o">=</span><span class="s2">&#34;us-east-1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">body</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="s2">&#34;prompt&#34;</span><span class="p">:</span> <span class="s2">&#34;</span><span class="se">\n\n</span><span class="s2">Human:What is your name?</span><span class="se">\n\n</span><span class="s2">Assistant:&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="s2">&#34;max_tokens_to_sample&#34;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">invoke_model</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="n">body</span><span class="o">=</span><span class="n">body</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-v2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="n">accept</span><span class="o">=</span><span class="s2">&#34;application/json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="n">contentType</span><span class="o">=</span><span class="s2">&#34;application/json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="n">response_body</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="p">[</span><span class="s2">&#34;body&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="n">completion</span> <span class="o">=</span> <span class="n">response_body</span><span class="p">[</span><span class="s2">&#34;completion&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">completion</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">My name is Claude.</span></span></code></pre></div><h2 id="how-to-stream-models-responses-using-python-boto3">How to stream models responses using Python boto3</h2>
<p>Amazon Bedrock allows streaming LLM responses as well!</p>
<h3 id="how-to-use-the-invoke_model-with-response-stream-method">How to use the invoke_model with response stream method</h3>
<p>Using the same example from above, let&rsquo;s use the <code>invoke_model_with_response_stream</code> method:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">,</span> <span class="n">region_name</span><span class="o">=</span><span class="s2">&#34;us-east-1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">body</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="s2">&#34;prompt&#34;</span><span class="p">:</span> <span class="s2">&#34;</span><span class="se">\n\n</span><span class="s2">Human:Write me a 100 word essay about snickers candy bars</span><span class="se">\n\n</span><span class="s2">Assistant:&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="s2">&#34;max_tokens_to_sample&#34;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">invoke_model_with_response_stream</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="n">body</span><span class="o">=</span><span class="n">body</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="n">modelId</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-v2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="n">accept</span><span class="o">=</span><span class="s2">&#34;application/json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="n">contentType</span><span class="o">=</span><span class="s2">&#34;application/json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="n">stream</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;body&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="k">if</span> <span class="n">stream</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">    <span class="k">for</span> <span class="n">event</span> <span class="ow">in</span> <span class="n">stream</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">        <span class="n">chunk</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;chunk&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">        <span class="k">if</span> <span class="n">chunk</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">            <span class="nb">print</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">chunk</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;bytes&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">()))</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">{&#39;completion&#39;: &#39; Here&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">{&#39;completion&#39;: &#39; is a 100 word essay&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">{&#39;completion&#39;: &#39; about Snickers candy&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">{&#39;completion&#39;: &#39; bars:\n\nS&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">{&#39;completion&#39;: &#39;nickers is one of&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">{&#39;completion&#39;: &#39; the most popular candy bars around. Introdu&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">{&#39;completion&#39;: &#39;ced in 1930, it consists of nougat topped with&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">{&#39;completion&#39;: &#39; caramel and peanuts that is encased in milk chocolate&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">{&#39;completion&#39;: &#39;. With its sweet and salty taste profile,&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln">10</span><span class="cl">{&#39;completion&#39;: &#39; Snickers provides the perfect balance of flavors. The candy&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln">11</span><span class="cl">{&#39;completion&#39;: &#34; bar got its name from the Mars family&#39;s&#34;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln">12</span><span class="cl">{&#39;completion&#39;: &#39; favorite horse. Bite&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln">13</span><span class="cl">{&#39;completion&#39;: &#39; into a Snickers and the rich&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln">14</span><span class="cl">{&#39;completion&#39;: &#39; chocolate and caramel intermingle in your mouth while the&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln">15</span><span class="cl">{&#39;completion&#39;: &#39; crunch of peanuts adds text&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln">16</span><span class="cl">{&#39;completion&#39;: &#39;ural contrast. Loaded with sugar, Snick&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln">17</span><span class="cl">{&#39;completion&#39;: &#39;ers gives you a quick burst of energy. It&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln">18</span><span class="cl">{&#39;completion&#39;: &#34;&#39;s a classic candy bar that has endured for&#34;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln">19</span><span class="cl">{&#39;completion&#39;: &#39; decades thanks to its irresistible combination&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln">20</span><span class="cl">{&#39;completion&#39;: &#39; of chocolate,&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln">21</span><span class="cl">{&#39;completion&#39;: &#39; caramel, noug&#39;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln">22</span><span class="cl">{&#39;completion&#39;: &#34;at and peanuts. Snickers&#39; popularity shows&#34;, &#39;stop_reason&#39;: None, &#39;stop&#39;: None}
</span></span><span class="line"><span class="ln">23</span><span class="cl">{&#39;completion&#39;: &#39; no signs of waning anytime soon.&#39;, &#39;stop_reason&#39;: &#39;stop_sequence&#39;, &#39;stop&#39;: &#39;\n\nHuman:&#39;, &#39;amazon-bedrock-invocationMetrics&#39;: {&#39;inputTokenCount&#39;: 21, &#39;outputTokenCount&#39;: 184, &#39;invocationLatency&#39;: 8756, &#39;firstByteLatency&#39;: 383}}</span></span></code></pre></div><p>Instead of returning a <code>StreamingBody</code> like before, the <code>response[&quot;body&quot;]</code> is an <a href="https://botocore.amazonaws.com/v1/documentation/api/latest/reference/eventstream.html"><code>EventStream</code></a> that can be iterated over in chunks.</p>
]]></content:encoded></item><item><title>ABC vs Protocol in Python</title><link>https://how.wtf/abc-vs-protocol-in-python.html</link><pubDate>Sat, 16 Dec 2023 12:00:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/abc-vs-protocol-in-python.html</guid><description>Before typing was released for Python, the ABC class reigned as champion for describing shape and behaviors of classes. After type annotations, ABC and @abstractmethod were still used to describe the behaviors: they felt &amp;lsquo;interface-like&amp;rsquo;.
Then, Protocol was released and introduced a new way for declaring class behaviors.
Should you use ABC or Protocol? Before describing why or why not you should choose one over the other, let&amp;rsquo;s delve into what each of them are.</description><content:encoded><![CDATA[<p><img src="images/UlTKgH.webp" alt="differences between ABC and Protocol"></p>
<p>Before <code>typing</code> was <a href="https://docs.python.org/3/library/typing.html">released</a> for Python, the <code>ABC</code> class reigned as champion for describing shape and behaviors of classes. After type annotations, <code>ABC</code> and <code>@abstractmethod</code> were still used to describe the behaviors: they felt &lsquo;interface-like&rsquo;.</p>
<p>Then, <code>Protocol</code> was <a href="https://peps.python.org/pep-0544/">released</a> and introduced a new way for declaring class behaviors.</p>
<h2 id="should-you-use-abc-or-protocol">Should you use ABC or Protocol?</h2>
<p>Before describing why or why not you should choose one over the other, let&rsquo;s delve into what each of them are.</p>
<h3 id="what-is-abc-or-abstract-base-classes">What is ABC or Abstract Base Classes?</h3>
<p><a href="https://docs.python.org/3/library/abc.html">Abstract Base Classes</a>, or ABC, is a a module that provides infrastructure to define abstract classes in Python.</p>
<p>As previously stated, they predated type hinting and were the go-to for enforcing class behaviors. Their goal was to provide a standardized means to test if an object adhered to a given specification.</p>
<p>For example,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">abc</span> <span class="kn">import</span> <span class="n">ABC</span><span class="p">,</span> <span class="n">abstractmethod</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="k">class</span> <span class="nc">Readable</span><span class="p">(</span><span class="n">ABC</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="nd">@abstractmethod</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="k">def</span> <span class="nf">read</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="k">pass</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="k">class</span> <span class="nc">Stream</span><span class="p">(</span><span class="n">Readable</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="k">def</span> <span class="nf">read</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="k">return</span> <span class="s2">&#34;read!&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="k">class</span> <span class="nc">FileReader</span><span class="p">(</span><span class="n">Readable</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="k">def</span> <span class="nf">read</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="k">return</span> <span class="s2">&#34;some lines from a file&#34;</span></span></span></code></pre></div><p>ABCs use nominative subtyping by default: ie. you must explicitly inherit from a superclass to be considered a subtype.</p>
<p>Although, they do have a <code>register</code> method that enables a structural-like typing:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">abc</span> <span class="kn">import</span> <span class="n">ABC</span><span class="p">,</span> <span class="n">abstractmethod</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="k">class</span> <span class="nc">Readable</span><span class="p">(</span><span class="n">ABC</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="nd">@abstractmethod</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="k">def</span> <span class="nf">read</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="k">pass</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="k">class</span> <span class="nc">Stream</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="k">def</span> <span class="nf">read</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="k">return</span> <span class="s2">&#34;read!&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="n">Readable</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">Stream</span><span class="p">)</span></span></span></code></pre></div><h3 id="what-is-protocol">What is Protocol</h3>
<p>Protocols are intended to make static checking easier - without needing to use an <code>isinstance</code> check at runtime.</p>
<p>They are treated as formalized duck typing - ie. the class only has to have the same attributes and methods&hellip; NOT be an <code>instanceof</code>.</p>
<p>Taking our class from earlier,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Protocol</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">class</span> <span class="nc">Readable</span><span class="p">(</span><span class="n">Protocol</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="k">def</span> <span class="nf">read</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span> <span class="o">...</span></span></span></code></pre></div><p>We can implement the <code>Protocol</code> in different ways:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">class</span> <span class="nc">Stream</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="k">def</span> <span class="nf">read</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="k">return</span> <span class="s2">&#34;read!&#34;</span></span></span></code></pre></div><p>OR explicitly</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">class</span> <span class="nc">Stream</span><span class="p">(</span><span class="n">Readable</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="k">def</span> <span class="nf">read</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="k">return</span> <span class="s2">&#34;read!&#34;</span></span></span></code></pre></div><p>Additionally, we can enforce runtime evaluation using the <code>runtime_checkable</code> decorator:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Protocol</span><span class="p">,</span> <span class="n">runtime_checkable</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nd">@runtime_checkable</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">class</span> <span class="nc">Readable</span><span class="p">(</span><span class="n">Protocol</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="k">def</span> <span class="nf">read</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span> <span class="o">...</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="k">class</span> <span class="nc">Stream</span><span class="p">(</span><span class="n">Readable</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="k">def</span> <span class="nf">read</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="k">return</span> <span class="s2">&#34;read!&#34;</span></span></span></code></pre></div><h3 id="which-is-preferred">Which is preferred?</h3>
<p>From my perspective, <code>Protocol</code> wins. Given Python&rsquo;s emphasis on duck typing (&ldquo;if it walks and quacks like a duck, then it must be a duck&rdquo;), it makes sense to opt for <code>Protocol</code>.</p>
<p>If there is a need to enforce runtime checks, it has that covered with the <code>@runtime_checkable</code>.</p>
<p>Protocol Pros:</p>
<ul>
<li>Short syntax</li>
<li>Aligns with the &ldquo;duck typing&rdquo; mentality</li>
<li>Supports implicit or explicit declaration</li>
<li>Supports runtime enforcement</li>
</ul>
<p>Protocol Cons:</p>
<ul>
<li>Only available in Python 3.8 or above</li>
</ul>
]]></content:encoded></item><item><title>How to use CSV files in vector stores with Langchain</title><link>https://how.wtf/how-to-use-csv-files-in-vector-stores-with-langchain.html</link><pubDate>Tue, 12 Dec 2023 01:55:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-use-csv-files-in-vector-stores-with-langchain.html</guid><description>Retrieval-Augmented Generation (RAG) is a technique for improving an LLM&amp;rsquo;s response by including contextual information from external sources. In other terms, it helps a large language model answer a question by providing facts and information for the prompt.
For the purposes of this tutorial, we will implement RAG by leveraging a Chroma DB as a vector store with the FDIC Failed Bank List dataset.
Langchain with CSV data in a vector store A vector store leverages a vector database, like Chroma DB, to fetch relevant documents using cosine similarity searches.</description><content:encoded><![CDATA[<p><img src="images/yjbsz4.webp" alt="how to use csv files in vector stores with langchain step by step"></p>
<p>Retrieval-Augmented Generation (RAG) is a technique for improving an LLM&rsquo;s response by including contextual information from external sources. In other terms, it helps a large language model answer a question by providing facts and information for the prompt.</p>
<p>For the purposes of this tutorial, we will implement RAG by leveraging a Chroma DB as a vector store with the <a href="https://catalog.data.gov/dataset/fdic-failed-bank-list/resource/a8cfc40d-bf6d-4716-bba6-04fdbdf5f9c1">FDIC Failed Bank List dataset</a>.</p>
<h2 id="langchain-with-csv-data-in-a-vector-store">Langchain with CSV data in a vector store</h2>
<p>A vector store leverages a vector database, like Chroma DB, to fetch relevant documents using cosine similarity searches.</p>
<p>Install the dependencies:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install langchain chromadb sentence-transformers</span></span></code></pre></div><p>Use the following code:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.document_loaders</span> <span class="kn">import</span> <span class="n">CSVLoader</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.embeddings.sentence_transformer</span> <span class="kn">import</span> <span class="n">SentenceTransformerEmbeddings</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.vectorstores</span> <span class="kn">import</span> <span class="n">Chroma</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">embedding_function</span> <span class="o">=</span> <span class="n">SentenceTransformerEmbeddings</span><span class="p">(</span><span class="n">model_name</span><span class="o">=</span><span class="s2">&#34;all-MiniLM-L6-v2&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">loader</span> <span class="o">=</span> <span class="n">CSVLoader</span><span class="p">(</span><span class="s2">&#34;./banklist.csv&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;windows-1252&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">documents</span> <span class="o">=</span> <span class="n">loader</span><span class="o">.</span><span class="n">load</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">db</span> <span class="o">=</span> <span class="n">Chroma</span><span class="o">.</span><span class="n">from_documents</span><span class="p">(</span><span class="n">documents</span><span class="p">,</span> <span class="n">embedding_function</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">query</span> <span class="o">=</span> <span class="s2">&#34;Did a bank fail in North Carolina?&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">docs</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">similarity_search</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">docs</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">page_content</span><span class="p">)</span></span></span></code></pre></div><p><strong>Steps</strong>:</p>
<ol>
<li>Use the <code>SentenceTransformerEmbeddings</code> to create an embedding function using the open source model of <code>all-MiniLM-L6-v2</code> from huggingface.</li>
<li>Instantiate the loader for the csv files from the <code>banklist.csv</code> file. I had to use <code>windows-1252</code> for the encoding of <code>banklist.csv</code>.</li>
<li>Load the files</li>
<li>Instantiate a Chroma DB instance from the documents &amp; the embedding model</li>
<li>Perform a cosine similarity search</li>
<li>Print out the contents of the first retrieved document</li>
</ol>
<h2 id="langchain-expression-with-chroma-db-csv-rag">Langchain Expression with Chroma DB CSV (RAG)</h2>
<p>After exploring how to use CSV files in a vector store, let&rsquo;s now explore a more advanced application: integrating Chroma DB using CSV data in a chain.</p>
<p>This section will demonstrate how to enhance the capabilities of our language model by incorporating RAG.</p>
<p>For the purposes of the following code, I opted for the OpenAI model and embeddings.</p>
<p>Install the dependencies:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install langchain chromadb openai tiktoken</span></span></code></pre></div><p>Use the following code:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.chat_models</span> <span class="kn">import</span> <span class="n">ChatOpenAI</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.document_loaders</span> <span class="kn">import</span> <span class="n">CSVLoader</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.embeddings</span> <span class="kn">import</span> <span class="n">OpenAIEmbeddings</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.prompts</span> <span class="kn">import</span> <span class="n">ChatPromptTemplate</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.vectorstores</span> <span class="kn">import</span> <span class="n">Chroma</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_core.output_parsers</span> <span class="kn">import</span> <span class="n">StrOutputParser</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain_core.runnables</span> <span class="kn">import</span> <span class="n">RunnableLambda</span><span class="p">,</span> <span class="n">RunnablePassthrough</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="n">embedding_function</span> <span class="o">=</span> <span class="n">OpenAIEmbeddings</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">loader</span> <span class="o">=</span> <span class="n">CSVLoader</span><span class="p">(</span><span class="s2">&#34;./banklist.csv&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;windows-1252&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">documents</span> <span class="o">=</span> <span class="n">loader</span><span class="o">.</span><span class="n">load</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">db</span> <span class="o">=</span> <span class="n">Chroma</span><span class="o">.</span><span class="n">from_documents</span><span class="p">(</span><span class="n">documents</span><span class="p">,</span> <span class="n">embedding_function</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="n">retriever</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">as_retriever</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="n">template</span> <span class="o">=</span> <span class="s2">&#34;&#34;&#34;Answer the question based only on the following context:
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="s2"></span><span class="si">{context}</span><span class="s2">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="s2">Question: </span><span class="si">{question}</span><span class="s2">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="s2">&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="n">prompt</span> <span class="o">=</span> <span class="n">ChatPromptTemplate</span><span class="o">.</span><span class="n">from_template</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="n">ChatOpenAI</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">
</span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="n">chain</span> <span class="o">=</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">    <span class="p">{</span><span class="s2">&#34;context&#34;</span><span class="p">:</span> <span class="n">retriever</span><span class="p">,</span> <span class="s2">&#34;question&#34;</span><span class="p">:</span> <span class="n">RunnablePassthrough</span><span class="p">()}</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">    <span class="o">|</span> <span class="n">prompt</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">    <span class="o">|</span> <span class="n">model</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">    <span class="o">|</span> <span class="n">StrOutputParser</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">chain</span><span class="o">.</span><span class="n">invoke</span><span class="p">(</span><span class="s2">&#34;What bank failed in North Carolina?&#34;</span><span class="p">))</span></span></span></code></pre></div><p><strong>Borrowing from the prior example, we:</strong></p>
<ol>
<li>Created a prompt template with <code>context</code> and <code>question</code> variables</li>
<li>Created a chain using the <code>ChatOpenAI</code> model with a retriever</li>
<li>Invoked the chain with the question <code>What bank failed in North Carolina?</code></li>
</ol>
<p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">The bank that failed in North Carolina is Blue Ridge Savings Bank, Inc.</span></span></code></pre></div><p>This tutorial only includes the basic functionality for Chroma DB. Please visit my <a href="https://how.wtf/how-to-use-chroma-db-step-by-step-guide.html">Chroma DB guide</a> where I walk step-by-step on how to use it for a more in-depth tutorial.</p>
]]></content:encoded></item><item><title>Open a GitHub pull request using the command line</title><link>https://how.wtf/open-a-github-pull-request-using-the-command-line.html</link><pubDate>Sat, 09 Dec 2023 13:45:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/open-a-github-pull-request-using-the-command-line.html</guid><description>After pushing changes to a remote repository, a common next step is creating a pull request for your team members to review. In this article, we&amp;rsquo;ll discuss how to open a pull request from the command line using the GitHub CLI.
What is the GitHub CLI The GitHub CLI is a tool that allows users to interact with GitHub directly from the terminal. It simplifies and streamlines GitHub workflows, enabling users to issue pull requests, check issues, clone repositories, etc.</description><content:encoded><![CDATA[<p><img src="images/usbOAk.webp" alt="How to create a github pull requesting from the command line"></p>
<p>After pushing changes to a remote repository, a common next step is creating a pull request for your team members to review. In this article, we&rsquo;ll discuss how to open a pull request from the command line using the GitHub CLI.</p>
<h2 id="what-is-the-github-cli">What is the GitHub CLI</h2>
<p>The GitHub CLI is a tool that allows users to interact with GitHub directly from the terminal. It simplifies and streamlines GitHub workflows, enabling users to issue pull requests, check issues, clone repositories, etc., without leaving the terminal.</p>
<h2 id="how-to-open-a-pr-from-the-terminal">How to open a PR from the terminal</h2>
<p>Opening a PR from the command line is straightforward using the <code>gh</code> CLI.</p>
<h3 id="install-the-github-cli">Install the GitHub CLI</h3>
<p>To begin, install the GitHub CLI using the <a href="https://github.com/cli/cli#installation">installation instructions</a>.</p>
<p>For MacOS, the <code>brew</code> package manager is an easy option:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">brew install gh</span></span></code></pre></div><h3 id="authenticate-the-github-cli">Authenticate the GitHub CLI</h3>
<p>After the GitHub CLI is installed, authenticate using the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">gh auth login</span></span></code></pre></div><p>If you&rsquo;re having trouble, follow the <a href="https://cli.github.com/manual/gh_auth_login">instructions provided by the GitHub team here</a> for more options.</p>
<h3 id="open-a-pull-request-from-the-terminal">Open a pull request from the terminal</h3>
<p>The following opens an interactive experience for your current branch:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">gh pr create</span></span></code></pre></div><h3 id="create-a-pull-request-in-the-browser-from-the-terminal">Create a pull request in the browser from the terminal</h3>
<p>If you prefer opening pull requests in the web version, the CLI can direct you to it:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">gh pr create --web</span></span></code></pre></div><h3 id="create-a-pull-request-using-a-template-from-the-terminal">Create a pull request using a template from the terminal</h3>
<p>If your organization requires using a PR template, this is supported as well:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">gh pr create --template &lt;file&gt;</span></span></code></pre></div><h3 id="create-a-draft-pull-request-from-the-terminal">Create a draft pull request from the terminal</h3>
<p>If you want to create a draft pull request, the GitHub CLI has you covered:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">gh pr create --draft</span></span></code></pre></div><h3 id="create-a-pull-request-using-a-title-and-body-from-the-terminal">Create a pull request using a title and body from the terminal</h3>
<p>The CLI supports explicitly defining the <code>--title</code> and <code>--body</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">gh pr create --title <span class="s2">&#34;Some title&#34;</span> --body <span class="s2">&#34;Some body&#34;</span></span></span></code></pre></div><h3 id="create-a-pull-request-for-a-different-branch-from-the-terminal">Create a pull request for a different branch from the terminal</h3>
<p>You may want to create a PR for a different branch using the CLI. This is covered as well:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">gh pr create --base main --head feature-branch</span></span></code></pre></div><h2 id="conclusion">Conclusion</h2>
<p>To wrap up, using the GitHub CLI can significantly boost your workflow. I encourage you to explore this tool – it&rsquo;s like having a superpower right in your terminal.</p>
]]></content:encoded></item><item><title>Set up time-to-live (TTL) attribute in DynamoDB</title><link>https://how.wtf/set-up-time-to-live-ttl-attribute-in-dynamodb.html</link><pubDate>Fri, 08 Dec 2023 01:50:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/set-up-time-to-live-ttl-attribute-in-dynamodb.html</guid><description>Amazon DynamoDB&amp;rsquo;s Time to Live (TTL) feature allows for automatic item deletion after a specified timestamp. It comes at no extra cost and is useful for removing outdated data.
TTL use-cases Remove stale data and save on DynamoDB memory usage Retain sensitive data only up to contractual or regulatory obligations Trigger processes using DynamoDB Streams based on TTL deletions since the deletion stream is marked as &amp;ldquo;system&amp;rdquo; rather than normal How to setup TTL in DynamoDB step-by-step This tutorial will use Python and the AWS CLI for demonstration purposes.</description><content:encoded><![CDATA[<p><img src="images/c6ETc4.webp" alt="How to set up time-to-live ttl attribute in Dynamodb"></p>
<p>Amazon DynamoDB&rsquo;s Time to Live (TTL) feature allows for automatic item deletion after a specified timestamp. It comes at no extra cost and is useful for removing outdated data.</p>
<h2 id="ttl-use-cases">TTL use-cases</h2>
<ol>
<li>Remove stale data and save on DynamoDB memory usage</li>
<li>Retain sensitive data only up to contractual or regulatory obligations</li>
<li>Trigger processes using DynamoDB Streams based on TTL deletions since the deletion stream is marked as <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/time-to-live-ttl-before-you-start.html#time-to-live-ttl-before-you-start-notes">&ldquo;system&rdquo; rather than normal</a></li>
</ol>
<h2 id="how-to-setup-ttl-in-dynamodb-step-by-step">How to setup TTL in DynamoDB step-by-step</h2>
<p>This tutorial will use Python and the AWS CLI for demonstration purposes. The same logic can be applied to the tooling of your choice.</p>
<h3 id="create-a-dynamodb-table-with-ttl">Create a DynamoDB table with TTL</h3>
<p>To keep things simple, we&rsquo;ll leverage the AWS CLI to quickly create a table.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln"> 1</span><span class="cl">aws dynamodb create-table <span class="se">\
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="se"></span>    --table-name your-table <span class="se">\
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="se"></span>    --attribute-definitions <span class="se">\
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="se"></span>        <span class="nv">AttributeName</span><span class="o">=</span>pk,AttributeType<span class="o">=</span>S <span class="se">\
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="se"></span>        <span class="nv">AttributeName</span><span class="o">=</span>sk,AttributeType<span class="o">=</span>S <span class="se">\
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="se"></span>    --key-schema <span class="se">\
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="se"></span>        <span class="nv">AttributeName</span><span class="o">=</span>pk,KeyType<span class="o">=</span>HASH <span class="se">\
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="se"></span>        <span class="nv">AttributeName</span><span class="o">=</span>sk,KeyType<span class="o">=</span>RANGE <span class="se">\
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="se"></span>    --provisioned-throughput <span class="se">\
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="se"></span>        <span class="nv">ReadCapacityUnits</span><span class="o">=</span>5,WriteCapacityUnits<span class="o">=</span><span class="m">5</span></span></span></code></pre></div><p>then enable TTL</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws dynamodb update-time-to-live <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --table-name your-table <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --time-to-live-specification <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>        <span class="nv">AttributeName</span><span class="o">=</span>expires_at,Enabled<span class="o">=</span>true</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;TimeToLiveSpecification&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="nt">&#34;Enabled&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">        <span class="nt">&#34;AttributeName&#34;</span><span class="p">:</span> <span class="s2">&#34;expires_at&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>If you desire to deploy a table via AWS CDK or CloudFormation, they allow you to specify a <code>TimeToLiveSpecification</code> upon table creation:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nt">AWSTemplateFormatVersion</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;2010-09-09&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="nt">Description</span><span class="p">:</span><span class="w"> </span><span class="l">CloudFormation template for creating a DynamoDB table with TTL.</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="nt">Resources</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">  </span><span class="nt">MyDynamoDBTable</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;AWS::DynamoDB::Table&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">      </span><span class="nt">TableName</span><span class="p">:</span><span class="w"> </span><span class="l">your-table</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">      </span><span class="nt">AttributeDefinitions</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">        </span>- <span class="nt">AttributeName</span><span class="p">:</span><span class="w"> </span><span class="l">pk</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">          </span><span class="nt">AttributeType</span><span class="p">:</span><span class="w"> </span><span class="l">S</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">        </span>- <span class="nt">AttributeName</span><span class="p">:</span><span class="w"> </span><span class="l">sk</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">          </span><span class="nt">AttributeType</span><span class="p">:</span><span class="w"> </span><span class="l">S</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">      </span><span class="nt">KeySchema</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">        </span>- <span class="nt">AttributeName</span><span class="p">:</span><span class="w"> </span><span class="l">pk</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">          </span><span class="nt">KeyType</span><span class="p">:</span><span class="w"> </span><span class="l">HASH</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">        </span>- <span class="nt">AttributeName</span><span class="p">:</span><span class="w"> </span><span class="l">sk</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">          </span><span class="nt">KeyType</span><span class="p">:</span><span class="w"> </span><span class="l">RANGE</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">      </span><span class="nt">ProvisionedThroughput</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">        </span><span class="nt">ReadCapacityUnits</span><span class="p">:</span><span class="w"> </span><span class="m">5</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">        </span><span class="nt">WriteCapacityUnits</span><span class="p">:</span><span class="w"> </span><span class="m">5</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">      </span><span class="nt">TimeToLiveSpecification</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">        </span><span class="nt">AttributeName</span><span class="p">:</span><span class="w"> </span><span class="l">expires_at </span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">        </span><span class="nt">Enabled</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span></span></span></code></pre></div><h3 id="add-ttl-attribute-with-proper-format-to-an-item">Add TTL attribute with proper format to an item</h3>
<p>The value for a TTL attribute is required to be in <a href="https://en.wikipedia.org/wiki/Unix_time">Unix Epoch time format</a>. Items with a timestamp older than the current time, except those older by 5 years or more, are marked as expired and will be deleted by the <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/howitworks-ttl.html">per-partition background scanner</a>.</p>
<p>Here is a Python example demonstrating how to insert an item with correctly formatted TTL:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">dynamodb</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s2">&#34;dynamodb&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">table</span> <span class="o">=</span> <span class="n">dynamodb</span><span class="o">.</span><span class="n">Table</span><span class="p">(</span><span class="s2">&#34;your-table&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">current_time</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">())</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"># TTL value (e.g., 24 hours from now)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="n">ttl_value</span> <span class="o">=</span> <span class="n">current_time</span> <span class="o">+</span> <span class="mi">24</span> <span class="o">*</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">60</span>  <span class="c1"># 24 hours from now in seconds</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">item</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;pk&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;sk&#34;</span><span class="p">:</span> <span class="s2">&#34;entity&#34;</span><span class="p">,</span> <span class="s2">&#34;expires_at&#34;</span><span class="p">:</span> <span class="n">ttl_value</span><span class="p">}</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">put_item</span><span class="p">(</span><span class="n">Item</span><span class="o">=</span><span class="n">item</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;ResponseMetadata&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="nt">&#34;RequestId&#34;</span><span class="p">:</span> <span class="s2">&#34;...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="nt">&#34;HTTPStatusCode&#34;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="nt">&#34;HTTPHeaders&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">      <span class="nt">&#34;server&#34;</span><span class="p">:</span> <span class="s2">&#34;Server&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">      <span class="nt">&#34;date&#34;</span><span class="p">:</span> <span class="s2">&#34;Fri, 08 Dec 2023 06:24:48 GMT&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">      <span class="nt">&#34;content-type&#34;</span><span class="p">:</span> <span class="s2">&#34;application/x-amz-json-1.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">      <span class="nt">&#34;content-length&#34;</span><span class="p">:</span> <span class="s2">&#34;2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">      <span class="nt">&#34;connection&#34;</span><span class="p">:</span> <span class="s2">&#34;keep-alive&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">      <span class="nt">&#34;x-amzn-requestid&#34;</span><span class="p">:</span> <span class="s2">&#34;...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">      <span class="nt">&#34;x-amz-crc32&#34;</span><span class="p">:</span> <span class="s2">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="nt">&#34;RetryAttempts&#34;</span><span class="p">:</span> <span class="mi">0</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h3 id="dynamodb-query-without-ttl-expired-items">DynamoDB Query without TTL expired items</h3>
<p>Directly from the <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/howitworks-ttl.html">AWS documentation</a>:</p>
<blockquote>
<p>TTL typically deletes expired items within a few days. Depending on the size and activity level of a table, the actual delete operation of an expired item can vary. Because TTL is meant to be a background process, the nature of the capacity used to expire and delete items via TTL is variable (but free of charge).</p>
</blockquote>
<p>DynamoDB queries and scans will return the items that are supposed to be expired if they have not been removed from the table. To remediate this, use a filter expression:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">dynamodb</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s2">&#34;dynamodb&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">table</span> <span class="o">=</span> <span class="n">dynamodb</span><span class="o">.</span><span class="n">Table</span><span class="p">(</span><span class="s2">&#34;your-table&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">current_time</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">())</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">current_time</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="n">query_params</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="s2">&#34;KeyConditionExpression&#34;</span><span class="p">:</span> <span class="s2">&#34;pk = :pk&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="s2">&#34;FilterExpression&#34;</span><span class="p">:</span> <span class="s2">&#34;attribute_not_exists(#ttl) OR #ttl &gt; :now&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="s2">&#34;ExpressionAttributeValues&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;:pk&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;:now&#34;</span><span class="p">:</span> <span class="n">current_time</span><span class="p">},</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="s2">&#34;ExpressionAttributeNames&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;#ttl&#34;</span><span class="p">:</span> <span class="s2">&#34;expires_at&#34;</span><span class="p">},</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="o">**</span><span class="n">query_params</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="p">)</span></span></span></code></pre></div>]]></content:encoded></item><item><title>How to use NordVPN on Linux step-by-step guide</title><link>https://how.wtf/how-to-use-nordvpn-on-linux-step-by-step-guide.html</link><pubDate>Wed, 06 Dec 2023 02:20:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-use-nordvpn-on-linux-step-by-step-guide.html</guid><description>In this article, we&amp;rsquo;ll discuss how to use NordVPN on Linux. This includes installation, authentication, and general usage of the CLI in Linux.
Please note, the links provided for NordVPN are affiliate links. This means if you click on them and make a purchase, I may receive a commission at no extra cost to you. This helps support the blog and allows me to continue creating content like this.</description><content:encoded><![CDATA[<p><img src="images/G6rw3h.webp" alt="how to use NordVPN on linux step-by-step"></p>
<p>In this article, we&rsquo;ll discuss how to use NordVPN on Linux. This includes installation, authentication, and general usage of the CLI in Linux.</p>
<p>Please note, the links provided for NordVPN are affiliate links. This means if you click on them and make a purchase, I may receive a commission at no extra cost to you. This helps support the blog and allows me to continue creating content like this.</p>
<h2 id="what-is-nordvpn">What is NordVPN?</h2>
<p><a href="https://go.nordvpn.net/aff_c?offer_id=15&amp;aff_id=97262&amp;source=how-to-use-nordvpn-on-ubuntu-step-by-step-guide">NordVPN</a> is a robust virtual private network (VPN) service that ensures secure and anonymized internet access. It&rsquo;s easy to use, fast, and provides <em>many</em> servers to connect from. Truth be told, it has been my go-to VPN solution for years.</p>
<h2 id="why-use-nordvpn">Why use NordVPN?</h2>
<ul>
<li>14 million users</li>
<li>5,400+ servers in 59 countries</li>
<li>Split tunneling support</li>
<li>24/7 customer support</li>
</ul>
<h2 id="installing-nordvpn-on-linux">Installing NordVPN on Linux</h2>
<p>Sign up for <a href="https://go.nordvpn.net/aff_c?offer_id=15&amp;aff_id=97262&amp;source=how-to-use-nordvpn-on-ubuntu-step-by-step-guide">NordVPN</a> then run the installer for Linux using the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sh &lt;<span class="o">(</span>curl -sSf https://downloads.nordcdn.com/apps/linux/install.sh<span class="o">)</span></span></span></code></pre></div><p>If <code>curl</code> is not available on your system, <code>wget</code> is an option:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sh &lt;<span class="o">(</span>wget -qO - https://downloads.nordcdn.com/apps/linux/install.sh<span class="o">)</span></span></span></code></pre></div><p>If you receive the following error:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Whoops! Permission denied accessing /run/nordvpn/nordvpnd.sock</span></span></code></pre></div><p>then modify your current user&rsquo;s permissions by running the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo usermod -aG nordvpn <span class="nv">$USER</span></span></span></code></pre></div><p>For permission refresh, either reboot your machine using</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo reboot now</span></span></code></pre></div><p>or re-login using your current user:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">su - <span class="nv">$USER</span></span></span></code></pre></div><p>You&rsquo;re all set!</p>
<h2 id="login-with-nordvpn-cli">Login with NordVPN CLI</h2>
<p>To begin, you must login to your NordVPN account using the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">nordvpn login</span></span></code></pre></div><p>This outputs a login url. <em>COPY</em> the url and paste it into a browser of your choosing.</p>
<p>After a successful attempt, the <code>Continue</code> button should authenticate your terminal session.</p>
<p>To verify, run the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">nordvpn account</span></span></code></pre></div><p>If you receive the &ldquo;You are not logged in&rdquo; message, then you may optionally provide the <code>callback</code> URI to the CLI.</p>
<p>To do this, issue the <code>nordvpn login</code> command again. Before clicking the <code>Continue</code> button this time, right click it and copy the link.</p>
<p>Paste the uri in quotes as the value for the <code>--callback</code> argument:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">nordvpn login --callback <span class="s2">&#34;nordvpn://login?action=login?exchange_token=&lt;tokenhere&gt;&amp;status=done&#34;</span></span></span></code></pre></div><h2 id="connect-with-nordvpn">Connect with NordVPN</h2>
<p>Like I mentioned earlier, this is my preferred VPN because of its ease-of-use. To connect, simply run the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">nordvpn connect</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Connecting to the United States #10028 (us10028.nordvpn.com)
</span></span><span class="line"><span class="ln">2</span><span class="cl">You are connected to United States #10028 (us10028.nordvpn.com)</span></span></code></pre></div><p>You will automatically be connected to the nearest location.</p>
<h3 id="connect-with-specific-country-using-nordvpn">Connect with specific country using NordVPN</h3>
<p>The NordVPN client allows connections to other locations seamlessly. To begin, run the following command to discover the countries available:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">nordvpn countries</span></span></code></pre></div><p>Connect to the country:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">nordvpn connect COUNTRY</span></span></code></pre></div><h3 id="connect-with-specific-city-using-nordvpn">Connect with specific city using NordVPN</h3>
<p>Similary, discover the cities available by country using the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">nordvpn cities COUNTRY</span></span></code></pre></div><p>For example,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">nordvpn cities United_States</span></span></code></pre></div><p>Connect to a city:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">nordvpn connect COUNTRY CITY</span></span></code></pre></div><p>For example,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">nordvpn connect United_States New_York</span></span></code></pre></div><h2 id="automatically-start-nordvpn-connection-on-linux-boot">Automatically start NordVPN connection on Linux boot</h2>
<p>To automatically connect NordVPN on boot, simply run the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">nordvpn <span class="nb">set</span> autoconnect enabled</span></span></code></pre></div><h2 id="set-up-nordvpn-kill-switch-on-linux">Set up NordVPN Kill Switch on Linux</h2>
<p>If NordVPN connection is lost, you may optionally enable the killswitch to ensure all internet traffic stops:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">nordvpn <span class="nb">set</span> killswitch enabled</span></span></code></pre></div><h2 id="view-nordvpn-settings">View NordVPN settings</h2>
<p>If you want to view all the settings that can be toggled simply run:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">nordvpn settings</span></span></code></pre></div><h2 id="conclusion">Conclusion</h2>
<p>This article provides a step-by-step guide on installing and using NordVPN on Linux. It covers installation, logging in, connecting to different servers, and setting up features like auto-connect and killswitch. I hope you enjoyed the content!</p>
<p><a href="https://go.nordvpn.net/aff_c?offer_id=15&amp;aff_id=97262&amp;source=how-to-use-nordvpn-on-ubuntu-step-by-step-guide"><img src="images/M5CQOY.webp" alt="get the nord vpn deal now"></a></p>
]]></content:encoded></item><item><title>How to use Docker without Docker Desktop on MacOS</title><link>https://how.wtf/how-to-use-docker-without-docker-desktop-on-macos.html</link><pubDate>Fri, 01 Dec 2023 01:25:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-use-docker-without-docker-desktop-on-macos.html</guid><description>Docker Desktop was my de facto choice on MacOS due to its ease of installation and container management. This changed after Docker updated their subscription service agreement.
Step-by-step guide to installing Docker without Docker Desktop The following tutorial assumes that you use brew as your package manager.
Install docker Firstly, install docker and docker-credential-helper.
1brew install docker-credential-helper dockerdocker-credential-helper provides a way for Docker to use the MacOS Keychain as a credential store.</description><content:encoded><![CDATA[<p><img src="images/lLFsL5.webp" alt="How to use Docker without Docker Desktop on MacOS"></p>
<p>Docker Desktop was my de facto choice on MacOS due to its ease of installation and container management. This changed after Docker updated their <a href="https://www.docker.com/blog/updating-product-subscriptions/">subscription service agreement</a>.</p>
<h2 id="step-by-step-guide-to-installing-docker-without-docker-desktop">Step-by-step guide to installing Docker without Docker Desktop</h2>
<p>The following tutorial assumes that you use <code>brew</code> as your package manager.</p>
<h3 id="install-docker">Install docker</h3>
<p>Firstly, install <code>docker</code> and <code>docker-credential-helper</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">brew install docker-credential-helper docker</span></span></code></pre></div><p><code>docker-credential-helper</code> provides a way for Docker to use the MacOS Keychain as a credential store.</p>
<h3 id="install-colima">Install colima</h3>
<p>The true power comes from <a href="https://github.com/abiosoft/colima">colima</a>: a container runtime for MacOS and Linux.</p>
<p>Install it using <code>brew</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">brew install colima</span></span></code></pre></div><h3 id="start-colima">Start colima</h3>
<p>Colima boasts its CLI ease of use! To get started, simply start the service:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">colima start</span></span></code></pre></div><h3 id="using-colima">Using colima</h3>
<p>After <code>colima</code> is installed, <code>docker</code> should hopefully work out-of-the-box:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">docker ps
</span></span><span class="line"><span class="ln">2</span><span class="cl">CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES</span></span></code></pre></div><p>Some applications do not respect <code>docker</code> contexts and will yield the following error:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?</span></span></code></pre></div><p>To remediate the issue, set the <code>DOCKER_HOST</code> variable.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">export</span> <span class="nv">DOCKER_HOST</span><span class="o">=</span>unix://<span class="si">${</span><span class="nv">HOME</span><span class="si">}</span>/.colima/default/docker.sock</span></span></code></pre></div>]]></content:encoded></item><item><title>Golang AWS Lambda project structure</title><link>https://how.wtf/golang-aws-lambda-project-structure.html</link><pubDate>Wed, 29 Nov 2023 01:45:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/golang-aws-lambda-project-structure.html</guid><description>AWS Lambda is an easy-to-use serverless offering that enables developers to quickly deploy code without worrying about maintenance, orchestration, scaling, etc. It&amp;rsquo;s simple to get started and its free tier is generous!
Golang project structure GO does not have a recommended project structure. In fact, keeping a project structure flat is preferrable for small apps:
1project/ 2├── go.mod 3├── go.sum 4├── user.go 5└── main.goMy personal preference is to use the flat structure for small apps or a combination of internal + cmd:</description><content:encoded><![CDATA[<p><img src="images/yI9Hqu.webp" alt="how to structure a Golang AWS Lambda project"></p>
<p>AWS Lambda is an easy-to-use serverless offering that enables developers to quickly deploy code without worrying about maintenance, orchestration, scaling, etc. It&rsquo;s simple to get started and its free tier is generous!</p>
<h2 id="golang-project-structure">Golang project structure</h2>
<p>GO does not have a recommended project structure. In fact, keeping a project structure flat is preferrable for small apps:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">project/
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── go.mod
</span></span><span class="line"><span class="ln">3</span><span class="cl">├── go.sum
</span></span><span class="line"><span class="ln">4</span><span class="cl">├── user.go
</span></span><span class="line"><span class="ln">5</span><span class="cl">└── main.go</span></span></code></pre></div><p>My personal preference is to use the flat structure for small apps or a combination of <code>internal</code> + <code>cmd</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">project/
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── cmd
</span></span><span class="line"><span class="ln">3</span><span class="cl">│   └── app1
</span></span><span class="line"><span class="ln">4</span><span class="cl">│       └── main.go
</span></span><span class="line"><span class="ln">5</span><span class="cl">├── go.mod
</span></span><span class="line"><span class="ln">6</span><span class="cl">├── go.sum
</span></span><span class="line"><span class="ln">7</span><span class="cl">└── internal
</span></span><span class="line"><span class="ln">8</span><span class="cl">    └── user.go</span></span></code></pre></div><h3 id="what-is-the-internal-module">What is the internal module</h3>
<p>The <code>internal</code> module can only be imported from packages rooted at the parent of the internal folder. In other words, the <code>internal</code> folder is &ldquo;private&rdquo; or non-existent outside the package. It reduces API surface area and establishes a clear domain boundary that <a href="https://go.dev/doc/go1.4#internalpackages">is enforced by GO</a>.</p>
<h3 id="what-is-the-cmd-module">What is the cmd module</h3>
<p>The <code>cmd</code> directory is <a href="https://github.com/golang-standards/project-layout#cmd">a common convention</a> I prefer for organizing sub-apps into runnable binaries. For example, a larger project may have multiple &ldquo;apps&rdquo; required to run it:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">store/
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">├── cmd
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">│   ├── api
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">│   │   └── main.go
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">│   ├── frontend
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">│   │   └── main.go
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">│   └── worker
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">│       └── main.go
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">├── go.mod
</span></span><span class="line"><span class="ln">10</span><span class="cl">├── go.sum
</span></span><span class="line"><span class="ln">11</span><span class="cl">└── internal
</span></span><span class="line"><span class="ln">12</span><span class="cl">    ├── cart.go
</span></span><span class="line"><span class="ln">13</span><span class="cl">    ├── product.go
</span></span><span class="line"><span class="ln">14</span><span class="cl">    └── user.go</span></span></code></pre></div><p>Each &ldquo;app&rdquo; within the <code>cmd</code> directory will have a distributable binary that can be invoked with required / optional flags. For example, the <code>frontend</code> binary may have a <code>-port</code> flag. The intention of the <code>main.go</code> files are to be <strong>THIN</strong> entry points that delegate the heavy processing to the <code>internal</code> layer.</p>
<p>It&rsquo;s common for a simple <code>main.go</code> to look like this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="s">&#34;github.com/user/repo/internal&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="nx">c</span> <span class="o">:=</span> <span class="nx">internal</span><span class="p">.</span><span class="nf">NewClient</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="nx">c</span><span class="p">.</span><span class="nf">DoSomething</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="golang-aws-lambda-project-structure">Golang AWS Lambda project structure</h2>
<p>Following the prior convention, lambdas can be similary nested in the <code>cmd</code> directory:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">project/
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">├── cmd
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">│   ├── function1
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">│   │   └── main.go
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">│   └── function2
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">│       └── main.go
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">├── go.mod
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">├── go.sum
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">└── internal
</span></span><span class="line"><span class="ln">10</span><span class="cl">    └── user.go</span></span></code></pre></div><p>With very <strong>THIN</strong> <code>main.go</code> entry handlers:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="s">&#34;github.com/aws/aws-lambda-go/lambda&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="s">&#34;github.com/user/repo/internal&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="kd">func</span> <span class="nf">HandleRequest</span><span class="p">()</span> <span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="nx">c</span> <span class="o">:=</span> <span class="nx">internal</span><span class="p">.</span><span class="nf">NewClient</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="nx">c</span><span class="p">.</span><span class="nf">DoSomething</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="nx">lambda</span><span class="p">.</span><span class="nf">Start</span><span class="p">(</span><span class="nx">HandleRequest</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>If <code>cmd</code> doesn&rsquo;t fit your use case, creating another folder is <strong>completely</strong> fine:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">project/
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">├── lambda 
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">│   ├── function1
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">│   │   └── main.go
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">│   └── function2
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">│       └── main.go
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">├── go.mod
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">├── go.sum
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">└── internal
</span></span><span class="line"><span class="ln">10</span><span class="cl">    └── user.go</span></span></code></pre></div><p>Even having separate <code>cmd</code> and <code>lambda</code> folders to distinguish between CLI-invocable apps and Lambda-invocable apps is fine.</p>
<p>The main point is keeping the <code>main.go</code> entry points thin.</p>
<h2 id="golang-aws-lambda-project-structure-with-cdk">Golang AWS Lambda project structure with CDK</h2>
<p>For my use-case, I kept the lambda handlers nested within the <code>cmd</code> directoy. In addition, I created a <code>deploy</code> app for the CDK that contains the stack-creation.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">project/
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">├── cdk.json
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">├── cmd
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">│   ├── function1
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">│   │   └── main.go
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">│   └── infrastructure
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">│       └── main.go
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">├── go.mod
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">├── go.sum
</span></span><span class="line"><span class="ln">10</span><span class="cl">└── internal
</span></span><span class="line"><span class="ln">11</span><span class="cl">    └── s3.go</span></span></code></pre></div><p>The <code>cdk.json</code> is simple:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;app&#34;</span><span class="p">:</span> <span class="s2">&#34;go mod download &amp;&amp; go run cmd/deploy/main.go&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>]]></content:encoded></item><item><title>How to count Amazon Bedrock Anthropic tokens with Langchain</title><link>https://how.wtf/how-to-count-amazon-bedrock-anthropic-tokens-with-langchain.html</link><pubDate>Fri, 24 Nov 2023 01:00:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-count-amazon-bedrock-anthropic-tokens-with-langchain.html</guid><description>Tracking Amazon Bedrock Claude token usage is simple using Langchain!
How to track tokens using Langchain For OpenAI models, Langchain provides a native Callback handler for tracking token usage as documented here.
1from langchain.callbacks import get_openai_callback 2from langchain.llms import OpenAI 3 4llm = OpenAI(temperature=0) 5with get_openai_callback() as cb: 6 llm(&amp;#34;What is the square root of 4?&amp;#34;) 7 8total_tokens = cb.total_tokens 9assert total_tokens &amp;gt; 0However, other model families do not have this luxury.</description><content:encoded><![CDATA[<p><img src="images/bmY6Bu.webp" alt="Count Amazon Bedrock Anthropic tokens with Langchain"></p>
<p>Tracking Amazon Bedrock Claude token usage is simple using Langchain!</p>
<h2 id="how-to-track-tokens-using-langchain">How to track tokens using Langchain</h2>
<p>For OpenAI models, Langchain provides a native Callback handler for tracking token usage as <a href="https://python.langchain.com/docs/modules/callbacks/token_counting">documented here</a>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.callbacks</span> <span class="kn">import</span> <span class="n">get_openai_callback</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.llms</span> <span class="kn">import</span> <span class="n">OpenAI</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">llm</span> <span class="o">=</span> <span class="n">OpenAI</span><span class="p">(</span><span class="n">temperature</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="k">with</span> <span class="n">get_openai_callback</span><span class="p">()</span> <span class="k">as</span> <span class="n">cb</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="n">llm</span><span class="p">(</span><span class="s2">&#34;What is the square root of 4?&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="n">total_tokens</span> <span class="o">=</span> <span class="n">cb</span><span class="o">.</span><span class="n">total_tokens</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="k">assert</span> <span class="n">total_tokens</span> <span class="o">&gt;</span> <span class="mi">0</span></span></span></code></pre></div><p>However, other model families do not have this luxury.</p>
<h2 id="counting-anthropic-bedrock-tokens">Counting Anthropic Bedrock Tokens</h2>
<p>Anthropic released a Bedrock client for their models that provides a method for counting tokens. I wrote an entire article about how to use it <a href="https://how.wtf/how-to-count-amazon-bedrock-claude-tokens-step-by-step-guide.html">here</a>.</p>
<p>Under the hood, Langchain uses the Anthropic client within the Bedrock LLM class to provide token counting.</p>
<h2 id="how-to-count-tokens-using-langchain-bedrock-llm-step-by-step">How to count tokens using Langchain Bedrock LLM Step-by-Step</h2>
<p>Before starting, please review my post about using Bedrock with Langchain <a href="https://how.wtf/langchain-with-amazon-bedrock.html">here</a>. It describes how to use <code>boto3</code> with <code>langchain</code> to easily instantiate clients. For the sake of this tutorial, I&rsquo;ll assume you already have your AWS session configured.</p>
<h3 id="installation">Installation</h3>
<p>Firstly, install the required libraries:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip3 install anthropic boto3 langchain</span></span></code></pre></div><h3 id="counting-bedrock-llm-tokens">Counting Bedrock LLM tokens</h3>
<p>To keep it simple, we&rsquo;ll begin by importing the Bedrock LLM and counting the input and output tokens.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.llms</span> <span class="kn">import</span> <span class="n">Bedrock</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">llm</span> <span class="o">=</span> <span class="n">Bedrock</span><span class="p">(</span><span class="n">client</span><span class="o">=</span><span class="n">client</span><span class="p">,</span> <span class="n">model_id</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-instant-v1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">prompt</span> <span class="o">=</span> <span class="s2">&#34;who are you?&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">llm</span><span class="o">.</span><span class="n">get_num_tokens</span><span class="p">(</span><span class="n">prompt</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="n">llm</span><span class="p">(</span><span class="n">prompt</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">llm</span><span class="o">.</span><span class="n">get_num_tokens</span><span class="p">(</span><span class="n">result</span><span class="p">))</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">4
</span></span><span class="line"><span class="ln">2</span><span class="cl">My name is Claude. I&#39;m an AI assistant created by Anthropic. 16</span></span></code></pre></div><p>In this case, 4 input tokens and 16 output tokens were used.</p>
<h3 id="counting-bedrock-llm-tokens-in-chain">Counting Bedrock LLM tokens in chain</h3>
<p>For my use case, I need to count the tokens used in chains. We&rsquo;ll need to build a custom handler since Langchain does not provide native support for counting Bedrock tokens.</p>
<p>For more information on Callback handlers, please reference the Langchain documentation <a href="https://python.langchain.com/docs/modules/callbacks/custom_callbacks">here</a>.</p>
<p>In the code below, I extended the <code>BaseCallbackHandler</code> class with <code>AnthropicTokenCounter</code>. In the constructor, a Bedrock LLM client is required since it contains the token counting function.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.callbacks.base</span> <span class="kn">import</span> <span class="n">BaseCallbackHandler</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="k">class</span> <span class="nc">AnthropicTokenCounter</span><span class="p">(</span><span class="n">BaseCallbackHandler</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">llm</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">llm</span> <span class="o">=</span> <span class="n">llm</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">input_tokens</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">output_tokens</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="k">def</span> <span class="nf">on_llm_start</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">serialized</span><span class="p">,</span> <span class="n">prompts</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">prompts</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="bp">self</span><span class="o">.</span><span class="n">input_tokens</span> <span class="o">+=</span> <span class="bp">self</span><span class="o">.</span><span class="n">llm</span><span class="o">.</span><span class="n">get_num_tokens</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="k">def</span> <span class="nf">on_llm_end</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">response</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="n">results</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">flatten</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">        <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">            <span class="bp">self</span><span class="o">.</span><span class="n">output_tokens</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">llm</span><span class="o">.</span><span class="n">get_num_tokens</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">generations</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">text</span><span class="p">)</span></span></span></code></pre></div><ol>
<li>The <code>on_llm_start</code> function supplies a list of prompts. For each prompt, I add the tokens to an instance property named <code>input_tokens</code>.</li>
<li>The <code>on_llm_end</code> function supplies a <code>LLMResult</code>.
<ol>
<li>The <code>LLMResult</code>, as I discovered in the <a href="https://github.com/langchain-ai/langchain/blob/751226e067bc54a70910763c0eebb34544aaf47c/libs/core/langchain_core/outputs/llm_result.py#L22">source code</a>, has a <code>flatten()</code> method that converts a <code>LLMResult</code> to a list of <code>LLMResult</code>s with 1 generation.</li>
<li>I add the tokens to an instance property named <code>output_tokens</code>.</li>
</ol>
</li>
</ol>
<p>I used the callback handler when calling the custom chain:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.llms</span> <span class="kn">import</span> <span class="n">Bedrock</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.prompts</span> <span class="kn">import</span> <span class="n">ChatPromptTemplate</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.callbacks.base</span> <span class="kn">import</span> <span class="n">BaseCallbackHandler</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="k">class</span> <span class="nc">AnthropicTokenCounter</span><span class="p">(</span><span class="n">BaseCallbackHandler</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">llm</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">llm</span> <span class="o">=</span> <span class="n">llm</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">input_tokens</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">output_tokens</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="k">def</span> <span class="nf">on_llm_start</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">serialized</span><span class="p">,</span> <span class="n">prompts</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">prompts</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">            <span class="bp">self</span><span class="o">.</span><span class="n">input_tokens</span> <span class="o">+=</span> <span class="bp">self</span><span class="o">.</span><span class="n">llm</span><span class="o">.</span><span class="n">get_num_tokens</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="k">def</span> <span class="nf">on_llm_end</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">response</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">        <span class="n">results</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">flatten</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">        <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">            <span class="bp">self</span><span class="o">.</span><span class="n">output_tokens</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">llm</span><span class="o">.</span><span class="n">get_num_tokens</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">generations</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">
</span></span><span class="line"><span class="ln">23</span><span class="cl">
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">
</span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="n">llm</span> <span class="o">=</span> <span class="n">Bedrock</span><span class="p">(</span><span class="n">client</span><span class="o">=</span><span class="n">client</span><span class="p">,</span> <span class="n">model_id</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-instant-v1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">
</span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="n">prompt</span> <span class="o">=</span> <span class="n">ChatPromptTemplate</span><span class="o">.</span><span class="n">from_template</span><span class="p">(</span><span class="s2">&#34;tell me a joke about </span><span class="si">{subject}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="n">chain</span> <span class="o">=</span> <span class="n">prompt</span> <span class="o">|</span> <span class="n">llm</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="n">token_counter</span> <span class="o">=</span> <span class="n">AnthropicTokenCounter</span><span class="p">(</span><span class="n">llm</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">chain</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span><span class="s2">&#34;subject&#34;</span><span class="p">:</span> <span class="s2">&#34;ai&#34;</span><span class="p">},</span> <span class="n">config</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;callbacks&#34;</span><span class="p">:</span> <span class="p">[</span><span class="n">token_counter</span><span class="p">]}))</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">token_counter</span><span class="o">.</span><span class="n">input_tokens</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">token_counter</span><span class="o">.</span><span class="n">output_tokens</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Here&#39;s one: Why can&#39;t AI assistants tell jokes? Because they lack a sense of humor!
</span></span><span class="line"><span class="ln">2</span><span class="cl">8
</span></span><span class="line"><span class="ln">3</span><span class="cl">20</span></span></code></pre></div>]]></content:encoded></item><item><title>How to count Amazon Bedrock Claude tokens step-by-step guide</title><link>https://how.wtf/how-to-count-amazon-bedrock-claude-tokens-step-by-step-guide.html</link><pubDate>Wed, 22 Nov 2023 11:50:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-count-amazon-bedrock-claude-tokens-step-by-step-guide.html</guid><description>Monitoring token consumption in Anthropic-based models can be straightforward and hassle-free. In fact, Anthropic offers a simple and effective method for accurately counting tokens using Python!
In this guide, I&amp;rsquo;ll show you how to count tokens for Amazon Bedrock Anthropic models.
Installing the Anthropic Bedrock Python Client To begin, install the Amazon Bedrock Python client using pip:
1pip install anthropic-bedrockFor more information about the library, visit the technical documentation here.</description><content:encoded><![CDATA[<p><img src="images/s6Kev8.webp" alt="Counting Amazon Bedrock Claude tokens"></p>
<p>Monitoring token consumption in Anthropic-based models can be straightforward and hassle-free. In fact, Anthropic offers a simple and effective method for accurately counting tokens using Python!</p>
<p>In this guide, I&rsquo;ll show you how to count tokens for Amazon Bedrock Anthropic models.</p>
<h2 id="installing-the-anthropic-bedrock-python-client">Installing the Anthropic Bedrock Python Client</h2>
<p>To begin, install the Amazon Bedrock Python client using <code>pip</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install anthropic-bedrock</span></span></code></pre></div><p>For more information about the library, visit the <a href="https://docs.anthropic.com/claude/docs/claude-on-amazon-bedrock">technical documentation here</a>.</p>
<h2 id="create-the-amazon-bedrock-connection">Create the Amazon Bedrock connection</h2>
<p>Instantiating the client is straightforward: use your AWS credentials to authenticate.</p>
<p>Since the <code>AnthropicBedrock</code> client uses <code>botocore</code> for authentication, you may use any AWS provider of your choosing:</p>
<ul>
<li>Environment variables</li>
<li>AWS Configuration file</li>
<li>Hardcoded <code>aws_access_key</code> + <code>aws_secret_key</code> in the <code>AnthropicBedrock</code> client directly</li>
</ul>
<p>Here is the code snippet from the documentation:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">anthropic_bedrock</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">anthropic_bedrock</span> <span class="kn">import</span> <span class="n">AnthropicBedrock</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">AnthropicBedrock</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="c1"># Authenticate by either providing the keys below or use the default AWS credential providers, such as</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="c1"># using ~/.aws/credentials or the &#34;AWS_SECRET_ACCESS_KEY&#34; and &#34;AWS_ACCESS_KEY_ID&#34; environment variables.</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">aws_access_key</span><span class="o">=</span><span class="s2">&#34;&lt;access key&gt;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">aws_secret_key</span><span class="o">=</span><span class="s2">&#34;&lt;secret key&gt;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="c1"># Temporary credentials can be used with aws_session_token.</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="c1"># Read more at https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html.</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="n">aws_session_token</span><span class="o">=</span><span class="s2">&#34;&lt;session_token&gt;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="c1"># aws_region changes the aws region to which the request is made. By default, we read AWS_REGION,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="c1"># and if that&#39;s not present, we default to us-east-1. Note that we do not read ~/.aws/config for the region.</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="n">aws_region</span><span class="o">=</span><span class="s2">&#34;us-east-1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="p">)</span></span></span></code></pre></div><p>For the sake of this guide, I set my <code>AWS_ACCESS_KEY_ID</code> and <code>AWS_SECRET_ACCESS_KEY</code> environment variables. My client is using the default region of <code>us-east-1</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">anthropic_bedrock</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kn">from</span> <span class="nn">anthropic_bedrock</span> <span class="kn">import</span> <span class="n">AnthropicBedrock</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">AnthropicBedrock</span><span class="p">()</span></span></span></code></pre></div><h2 id="listing-model-access">Listing model access</h2>
<p>The <code>completions</code> Anthropic API requires a model id. To determine what models are accessible on your AWS account, run the following command using the <code>aws</code> cli:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws bedrock list-foundation-models --by-provider anthropic --query <span class="s2">&#34;modelSummaries[*].modelId&#34;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">[
</span></span><span class="line"><span class="ln">2</span><span class="cl">    &#34;anthropic.claude-instant-v1&#34;,
</span></span><span class="line"><span class="ln">3</span><span class="cl">    &#34;anthropic.claude-v1&#34;,
</span></span><span class="line"><span class="ln">4</span><span class="cl">    &#34;anthropic.claude-v2&#34;
</span></span><span class="line"><span class="ln">5</span><span class="cl">]</span></span></code></pre></div><h2 id="calling-claude-on-bedrock-using-the-client">Calling Claude on Bedrock using the client</h2>
<p>Using the <code>anthropic.claude-instant-v1</code> model id from above, here&rsquo;s how to call it using the <code>completions</code> API:</p>





<pre tabindex="0"><code>import anthropic_bedrock
from anthropic_bedrock import AnthropicBedrock

client = AnthropicBedrock()

completion = client.completions.create(
    model=&#34;anthropic.claude-instant-v1&#34;,
    prompt=f&#34;{anthropic_bedrock.HUMAN_PROMPT} Tell me a funny cowboy joke {anthropic_bedrock.AI_PROMPT}&#34;,
    max_tokens_to_sample=2000,
)

print(completion.completion)</code></pre><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl"> Here&#39;s one: Why don&#39;t cowboys like to eat beef jerky in the desert? Because it&#39;s too chewy!</span></span></code></pre></div><p>In the code above, I&rsquo;m calling the <code>client.completions.create</code> function and supplying it:</p>
<ol>
<li>The model id as a string</li>
<li>The prompt using the Anthropic provided constants: <code>anthropic_bedrock.HUMAN_PROMPT</code> and <code>anthropic_bedrock.AI_PROMPT</code></li>
<li>The max tokens to sample is the maximum number of tokens to generate before stopping.</li>
</ol>
<p>The prompt above resolved to this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">anthropic_bedrock</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">print</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">anthropic_bedrock</span><span class="o">.</span><span class="n">HUMAN_PROMPT</span><span class="si">}</span><span class="s2"> Tell me a funny cowboy joke </span><span class="si">{</span><span class="n">anthropic_bedrock</span><span class="o">.</span><span class="n">AI_PROMPT</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl">Human: Tell me a funny cowboy joke
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl">Assistant:</span></span></code></pre></div><p>For more information about asynchronous or streamed responses, please refer to the <a href="https://github.com/anthropics/anthropic-bedrock-python">technical documentation here</a></p>
<h2 id="counting-tokens-using-the-client">Counting tokens using the client</h2>
<p>Using the example before, we can count the token usage using a static method provided by Anthropic.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">anthropic_bedrock</span> <span class="kn">import</span> <span class="n">AnthropicBedrock</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">AnthropicBedrock</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">client</span><span class="o">.</span><span class="n">count_tokens</span><span class="p">(</span><span class="s2">&#34;Hello world!&#34;</span><span class="p">))</span></span></span></code></pre></div><p>As of November 2023, Anthropic charges based on <a href="https://support.anthropic.com/en/articles/8114526-how-will-i-be-billed">prompt tokens and completion tokens</a>.</p>
<p>For tracking tokens, you can leverage this method to estimate:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">anthropic_bedrock</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">anthropic_bedrock</span> <span class="kn">import</span> <span class="n">AnthropicBedrock</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">AnthropicBedrock</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">prompt</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">anthropic_bedrock</span><span class="o">.</span><span class="n">HUMAN_PROMPT</span><span class="si">}</span><span class="s2"> Tell me a funny cowboy joke </span><span class="si">{</span><span class="n">anthropic_bedrock</span><span class="o">.</span><span class="n">AI_PROMPT</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">prompt_tokens</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">count_tokens</span><span class="p">(</span><span class="n">prompt</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">prompt_tokens</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">completions</span><span class="o">.</span><span class="n">create</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="n">model</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-instant-v1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="n">prompt</span><span class="o">=</span><span class="n">prompt</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">max_tokens_to_sample</span><span class="o">=</span><span class="mi">2000</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="n">completion</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">completion</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="n">completion_tokens</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">count_tokens</span><span class="p">(</span><span class="n">completion</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">completion_tokens</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">14
</span></span><span class="line"><span class="ln">2</span><span class="cl">28</span></span></code></pre></div>]]></content:encoded></item><item><title>How to prompt DALL-E effectively</title><link>https://how.wtf/how-to-prompt-dall-e-effectively.html</link><pubDate>Tue, 21 Nov 2023 00:25:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-prompt-dall-e-effectively.html</guid><description>DALL-E is an OpenAI model that generates images from textual descriptions. It combines elements of creativity and technology to produce unique imagery based on human prompts.
Tip 1 - DALL-E Prompt Book To kick things off, I recommend reviewing the DALL-E prompt book released by the dallery gallery. It contains many useful techniques for describing tone, emotion, angles, lightning, illustration style, etc. It has been a wonderful resource for myself and will likely give you enough information to get started.</description><content:encoded><![CDATA[<p><img src="images/wTdq5f.webp" alt="Prompting DALL-E for the best results"></p>
<p>DALL-E is an OpenAI model that generates images from textual descriptions. It combines elements of creativity and technology to produce unique imagery based on human prompts.</p>
<h2 id="tip-1---dall-e-prompt-book">Tip 1 - DALL-E Prompt Book</h2>
<p>To kick things off, I recommend reviewing the DALL-E <a href="https://pitch.com/v/DALL-E-prompt-book-v1-tmd33y">prompt book released by the dallery gallery</a>. It contains <em>many</em> useful techniques for describing tone, emotion, angles, lightning, illustration style, etc. It has been a wonderful resource for myself and will likely give you enough information to get started.</p>
<p>The mascot for <a href="https://how.wtf">https://how.wtf</a> is a bald character, depicted frustratingly slamming his hands on a desk while shouting:</p>
<p><img src="images/8yRnin.webp" alt="angry how.wtf mascot"></p>
<h2 id="tip-2---upload-an-image-and-prompt-dall-e">Tip 2 - Upload an image and prompt DALL-E</h2>
<p>Seeking an image of the same character riding a llama, I:</p>
<ol>
<li>Uploaded the image</li>
<li>Prompted DALL-E with a brief request: &ldquo;Given the uploaded image, render an animated version riding a llama&rdquo;</li>
</ol>
<p><img src="images/a2SaNO.webp" alt="prompt mascot to ride llama joyfully"></p>
<h2 id="tip-3---ask-dall-e-to-describe-an-image">Tip 3 - Ask DALL-E to describe an image</h2>
<p>If you wish to reproduce or modify an image, DALL-E can help describe it. For instance, I asked DALL-E to describe my mascot riding the llama:</p>
<p><strong>Me</strong>: How should I prompt you to get the image attached?</p>
<p><strong>DALL-E</strong>: To create an image similar to the one attached, you could use a prompt like this:</p>
<p>&ldquo;Create an image of a joyful, cartoonish, bald character with large expressive eyes, riding on the back of a fluffy, stylized alpaca. The character has a wide, excited smile and is holding onto reins as if they are having the time of their life. The alpaca appears to be in mid-gallop, creating small clouds of dust behind it to show its speed. The environment is a soft, minimalistic background that doesn&rsquo;t draw attention away from the action of the ride. The lighting should be bright and cheerful, capturing the sense of fun and adventure in the scene.&rdquo;</p>
<p>With DALL-E&rsquo;s guidance, I then requested a Simpsons-style version in a 16:9 aspect ratio:</p>
<p><strong>Me</strong>: Create a 16:9 aspect ratio image of a joyful, cartoonish, bald character with large expressive eyes, riding on the back of a fluffy, stylized alpaca in the style of &ldquo;The Simpsons&rdquo;. The character has a wide, excited smile and is holding onto reins as if they are having the time of their life. The alpaca appears to be in mid-gallop, creating small clouds of dust behind it to show its speed. The environment is a soft, minimalistic background that doesn&rsquo;t draw attention away from the action of the ride. The lighting should be bright and cheerful, capturing the sense of fun and adventure in the scene.</p>
<p>This resulted in the featured image for this blog post!</p>
<h2 id="conclusion">Conclusion</h2>
<p>DALL-E&rsquo;s remarkable ability to generate customized images from textual prompts is evident. By using specific descriptors and understanding the nuances of effective prompting, as detailed in the DALL-E prompt book, users can create vibrant, expressive images that vividly capture their ideas with striking accuracy and creativity.</p>
]]></content:encoded></item><item><title>OpenAI Assistants vs GPTs</title><link>https://how.wtf/openai-assistants-vs-gpts.html</link><pubDate>Sun, 19 Nov 2023 23:00:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/openai-assistants-vs-gpts.html</guid><description>OpenAI has two products that are similar: Assistants and GPTs. In this article, we&amp;rsquo;ll discuss the differences between the two.
What are OpenAI GPTs? GPTs (custom versions of ChatGPT) are specialized tools designed to cater to specific needs and preferences. They enable users, including those without coding skills, to tailor ChatGPT for distinct tasks or interests.
Users can create GPTs for private or public use, with the forthcoming GPT Store showcasing creations from verified builders in various categories like productivity and education.</description><content:encoded><![CDATA[<p><img src="images/qp822M.webp" alt="The difference between OpenAI Assistants and GPTs"></p>
<p>OpenAI has two products that are similar: Assistants and GPTs. In this article, we&rsquo;ll discuss the differences between the two.</p>
<h2 id="what-are-openai-gpts">What are OpenAI GPTs?</h2>
<p>GPTs (custom versions of ChatGPT) are specialized tools designed to cater to specific needs and preferences. They enable users, including those without coding skills, to tailor ChatGPT for distinct tasks or interests.</p>
<p>Users can create GPTs for private or public use, with the forthcoming GPT Store showcasing creations from verified builders in various categories like productivity and education. GPTs emphasize privacy and safety, ensuring user data is controlled and protected, with options for integrating third-party APIs and using chats for model improvement. This feature is particularly beneficial for enterprise customers, allowing them to develop internal-only GPTs for specific company needs. The initiative represents a step towards more interactive and capable AI systems, termed “agents,” and reflects OpenAI’s commitment to involving a broader community in AI development.</p>
<p>ChatGPT Plus now offers updated information and simplified access to various tools, including DALL·E, web browsing, and file attachments for enhanced user experience.</p>
<h2 id="what-are-openai-assistants">What are OpenAI Assistants?</h2>
<p>OpenAI Assistants are AI tools integrated within applications, designed to respond to user queries with tailored instructions and capabilities. They use various models and leverage specific tools, such as Code Interpreter, Retrieval, and Function calling, to provide targeted responses and solutions.</p>
<p>The Assistants API enables developers to embed AI assistants into their own platforms, enhancing the functionality and user interaction experience. This API is an adaptable framework, set to expand with more OpenAI-developed tools and options for custom tool integration.</p>
<h3 id="openai-assistant-example">OpenAI Assistant Example</h3>
<p>Using the <code>OpenAI</code> open-source Python module, we can leverage assistants easily:</p>
<p><strong>WARNING</strong>: This code uses the <code>beta</code> OpenAI client.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">time</span> <span class="kn">import</span> <span class="n">sleep</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">openai</span> <span class="kn">import</span> <span class="n">OpenAI</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="k">def</span> <span class="nf">wait_for_run</span><span class="p">(</span><span class="n">run</span><span class="p">,</span> <span class="n">thread</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="k">while</span> <span class="n">run</span><span class="o">.</span><span class="n">status</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&#34;queued&#34;</span><span class="p">,</span> <span class="s2">&#34;in_progress&#34;</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="n">run</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">beta</span><span class="o">.</span><span class="n">threads</span><span class="o">.</span><span class="n">runs</span><span class="o">.</span><span class="n">retrieve</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            <span class="n">thread_id</span><span class="o">=</span><span class="n">thread</span><span class="o">.</span><span class="n">id</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">            <span class="n">run_id</span><span class="o">=</span><span class="n">run</span><span class="o">.</span><span class="n">id</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="k">return</span> <span class="n">run</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">OpenAI</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="n">assistant</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">beta</span><span class="o">.</span><span class="n">assistants</span><span class="o">.</span><span class="n">create</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="n">instructions</span><span class="o">=</span><span class="s2">&#34;You are a ghost writer for the famous wrapper Eminem. When asked to write an song, write in an Enimen-like rhyme scheme.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="n">model</span><span class="o">=</span><span class="s2">&#34;gpt-4-1106-preview&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="n">thread</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">beta</span><span class="o">.</span><span class="n">threads</span><span class="o">.</span><span class="n">create</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">    <span class="n">messages</span><span class="o">=</span><span class="p">[{</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="s2">&#34;Write a song about AI.&#34;</span><span class="p">}]</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="n">run</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">beta</span><span class="o">.</span><span class="n">threads</span><span class="o">.</span><span class="n">runs</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">thread_id</span><span class="o">=</span><span class="n">thread</span><span class="o">.</span><span class="n">id</span><span class="p">,</span> <span class="n">assistant_id</span><span class="o">=</span><span class="n">assistant</span><span class="o">.</span><span class="n">id</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="n">run</span> <span class="o">=</span> <span class="n">wait_for_run</span><span class="p">(</span><span class="n">run</span><span class="p">,</span> <span class="n">thread</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="n">messages</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">beta</span><span class="o">.</span><span class="n">threads</span><span class="o">.</span><span class="n">messages</span><span class="o">.</span><span class="n">list</span><span class="p">(</span><span class="n">thread</span><span class="o">.</span><span class="n">id</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">messages</span><span class="o">.</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">content</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">text</span><span class="o">.</span><span class="n">value</span><span class="p">)</span></span></span></code></pre></div><p>From a high-level, this code does the following:</p>
<ol>
<li>Creates a thread with a prepopulated message from the user with the message &ldquo;Write a song about AI.&rdquo;</li>
<li>Runs the assistant on the thread</li>
<li>Polls the run for a completion status every half-second</li>
<li>Prints the latest message&rsquo;s content</li>
</ol>
<h2 id="what-is-the-difference-between-assistants-and-gpts">What is the difference between Assistants and GPTs?</h2>
<p>tl;dr - Assistants are accessed through OpenAI&rsquo;s API for developers. GPTs are used to personalize the ChatGPT experience.</p>
<p>The key difference between Assistants and GPTs is their application and integration scopes. Assistants are primarily API-driven tools meant for embedding within external applications, focusing on enhancing functionality with specific tasks like code interpretation, information retrieval, and function execution. They are components in a broader system, augmenting existing applications with AI capabilities.</p>
<p>On the other hand, GPTs are standalone, user-customized versions of ChatGPT, designed to fulfill varied personal, educational, or professional needs. While Assistants enhance specific functionalities within applications, GPTs are more about creating a personalized ChatGPT experience, tailored to the user&rsquo;s unique requirements.</p>
]]></content:encoded></item><item><title>Langchain with Amazon Bedrock</title><link>https://how.wtf/langchain-with-amazon-bedrock.html</link><pubDate>Sat, 18 Nov 2023 02:00:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/langchain-with-amazon-bedrock.html</guid><description>In this article, we&amp;rsquo;ll cover how to easily leverage Amazon Bedrock in Langchain.
What is Amazon Bedrock? Amazon Bedrock is a fully managed service that provides an API to invoke LLMs. At the time of writing, Amazon Bedrock supports:
Anthropic Claude Meta Llama Cohere Command Stability AI SDXL A121 Labs Jurassic with many more slated to come out!
How to use Amazon Bedrock with Langchain Langchain easily integrates with Amazon Bedrock via the langchain.</description><content:encoded><![CDATA[<p><img src="images/X6TLBR.webp" alt="How to use Langchain with Amazon Bedrock"></p>
<p>In this article, we&rsquo;ll cover how to easily leverage Amazon Bedrock in Langchain.</p>
<h2 id="what-is-amazon-bedrock">What is Amazon Bedrock?</h2>
<p><a href="https://aws.amazon.com/bedrock">Amazon Bedrock</a> is a fully managed service that provides an API to invoke LLMs. At the time of writing, Amazon Bedrock supports:</p>
<ul>
<li>Anthropic Claude</li>
<li>Meta Llama</li>
<li>Cohere Command</li>
<li>Stability AI SDXL</li>
<li>A121 Labs Jurassic</li>
</ul>
<p>with many more slated to come out!</p>
<h2 id="how-to-use-amazon-bedrock-with-langchain">How to use Amazon Bedrock with Langchain</h2>
<p>Langchain easily integrates with Amazon Bedrock via the <code>langchain.llms</code> module.</p>
<h3 id="setup-credentials">Setup credentials</h3>
<p>In the execution environment, ensure that the appropriate credentials are configured. This can be inferred from environment variables, the <code>~/.aws/credentials</code> configuration file, credentials in the Amazon Bedrock client, etc.</p>
<p>For the sake of this tutorial, I have exported my <code>AWS_ACCESS_KEY_ID</code> and <code>AWS_SECRET_ACCESS_KEY</code> pair.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">export</span> <span class="nv">AWS_ACCESS_KEY_ID</span><span class="o">=</span>xxxx
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">export</span> <span class="nv">AWS_SECRET_ACCESS_KEY</span><span class="o">=</span>xxxx</span></span></code></pre></div><h3 id="create-a-bedrock-client">Create a bedrock client</h3>
<p>Using <code>boto3</code>, a <code>bedrock-runtime</code> client can be created and passed as a parameter to the Langchain <code>Bedrock</code> class.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.llms</span> <span class="kn">import</span> <span class="n">Bedrock</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="n">Bedrock</span><span class="p">(</span><span class="n">client</span><span class="o">=</span><span class="n">client</span><span class="p">,</span> <span class="n">model_id</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-instant-v1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">model</span><span class="p">(</span><span class="s2">&#34;who are you?&#34;</span><span class="p">))</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">I&#39;m Claude, an AI assistant created by Anthropic.</span></span></code></pre></div><h3 id="creating-a-chain-with-bedrock">Creating a chain with Bedrock</h3>
<p>Now that the <code>model</code> is instantiated, we may use it with the Langchain Expression Language (LCEL) to create a chain.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.llms</span> <span class="kn">import</span> <span class="n">Bedrock</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.schema.output_parser</span> <span class="kn">import</span> <span class="n">StrOutputParser</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.prompts</span> <span class="kn">import</span> <span class="n">ChatPromptTemplate</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;bedrock-runtime&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="n">Bedrock</span><span class="p">(</span><span class="n">client</span><span class="o">=</span><span class="n">client</span><span class="p">,</span> <span class="n">model_id</span><span class="o">=</span><span class="s2">&#34;anthropic.claude-instant-v1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="n">prompt</span> <span class="o">=</span> <span class="n">ChatPromptTemplate</span><span class="o">.</span><span class="n">from_template</span><span class="p">(</span><span class="s2">&#34;write me a haiku about </span><span class="si">{topic}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">chain</span> <span class="o">=</span> <span class="n">prompt</span> <span class="o">|</span> <span class="n">model</span> <span class="o">|</span> <span class="n">StrOutputParser</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">chain</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span><span class="s2">&#34;topic&#34;</span><span class="p">:</span> <span class="s2">&#34;money&#34;</span><span class="p">}))</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Here is a haiku about money:
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl">Green paper bills flow
</span></span><span class="line"><span class="ln">4</span><span class="cl">Endless pursuit of riches
</span></span><span class="line"><span class="ln">5</span><span class="cl">Money rules all things</span></span></code></pre></div><h2 id="conclusion">Conclusion</h2>
<p>Integrating Langchain with Amazon Bedrock unlocks many capabilities for utilizing large language models in diverse applications. This guide has demonstrated the ease of setting up this integration, enabling you to enhance your projects with AI. As Amazon Bedrock expands its model support, the potential applications and efficiencies you can achieve will only grow.</p>
]]></content:encoded></item><item><title>A simple guide for hosting LLMs locally</title><link>https://how.wtf/a-simple-guide-for-hosting-llms-locally.html</link><pubDate>Fri, 17 Nov 2023 01:50:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/a-simple-guide-for-hosting-llms-locally.html</guid><description>Hosting large langage models (LLMs) locally is simple using LocalAI.
What is LocalAI LocalAI is an open source alternative to OpenAI. It serves as a seamless substitute for the REST API, aligning with OpenAI&amp;rsquo;s API standards for on-site data processing.
With LocalAI, you can effortlessly serve Large Language Models (LLMs), as well as create images and audio on your local or on-premise systems using standard consumer hardware. It supports a variety of model families that work with the ggml format and operates without the need for a GPU.</description><content:encoded><![CDATA[<p><img src="images/41N7Nm.webp" alt="Hosting llms locally guide"></p>
<p>Hosting large langage models (LLMs) locally is simple using <code>LocalAI</code>.</p>
<h2 id="what-is-localai">What is LocalAI</h2>
<p>LocalAI is an open source alternative to OpenAI. It serves as a seamless substitute for the REST API, aligning with OpenAI&rsquo;s API standards for on-site data processing.</p>
<p>With LocalAI, you can effortlessly serve Large Language Models (LLMs), as well as create images and audio on your local or on-premise systems using standard consumer hardware. It supports a variety of model families that work with the ggml format and operates without the need for a GPU. Developed and maintained by mudler, LocalAI aims to reshape how we access and utilize AI technologies.</p>
<h2 id="how-to-host-large-language-models-locally">How to host large language models locally</h2>
<p>Installing LocalAI is simple - we&rsquo;ll clone the repository and find a model to use.</p>
<h3 id="clone-the-repository">Clone the repository</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">git clone https://github.com/mudler/LocalAI.git
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">cd</span> LocalAI</span></span></code></pre></div><h3 id="select-a-model">Select a model</h3>
<p>Most ggml-based models should work with LocalAI and can be searched using HuggingFace at this url:</p>
<p><a href="https://huggingface.co/models?search=ggml">https://huggingface.co/models?search=ggml</a></p>
<h3 id="download-the-model">Download the model</h3>
<p>For this tutorial, I&rsquo;m using the <code>TheBloke/Llama-2-7B-Chat-GGML</code> model.</p>
<p>To get the appropriate download link, click on <code>Files and Versions</code> and select a <code>.bin</code> file. I chose the <code>llama-2-7b-chat.ggmlv3.q2_K.bin</code> file.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">wget https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/resolve/main/llama-2-7b-chat.ggmlv3.q2_K.bin <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    -O models/Llama-2-7B-Chat</span></span></code></pre></div><h3 id="run-the-docker-container">Run the docker container</h3>
<p>Run the docker-compose command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">docker compose up -d --pull always</span></span></code></pre></div><p>This may take a few minutes since the docker image was greater than 5 GB.</p>
<h3 id="invoke-the-localai-endpoint">Invoke the LocalAI endpoint</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl http://localhost:8080/v1/chat/completions <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    -H <span class="s2">&#34;Content-Type: application/json&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    -d <span class="s1">&#39;{&#34;model&#34;:&#34;Llama-2-7B-Chat&#34;,&#34;messages&#34;:[{&#34;role&#34;:&#34;user&#34;,&#34;content&#34;:&#34;Who are you?&#34;}],&#34;temperature&#34;: 0.9}&#39;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="s2">&#34;created&#34;</span><span class="p">:</span> <span class="mi">1700201935</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="s2">&#34;object&#34;</span><span class="p">:</span> <span class="s2">&#34;chat.completion&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;b5e4c3ff-c8ad-4350-89cb-293d2cfd806c&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="s2">&#34;model&#34;</span><span class="p">:</span> <span class="s2">&#34;Llama-2-7B-Chat&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="s2">&#34;choices&#34;</span><span class="p">:</span> <span class="p">[{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="s2">&#34;index&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="s2">&#34;finish_reason&#34;</span><span class="p">:</span> <span class="s2">&#34;stop&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="s2">&#34;message&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">            <span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;assistant&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">            <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="s2">&#34;</span><span class="se">\n</span><span class="s2">You are a unique individual, created in the image of God. You have your own personality, gifts, and talents that make you who you are. As a child of God, you have inherent dignity and worth, and are worthy of love and respect.</span><span class="se">\n\n</span><span class="s2">What is your purpose?</span><span class="se">\n\n</span><span class="s2">Your purpose is to live out your identity as a beloved child of God, and to fulfill the unique plan and calling that He has for your life. This may involve pursuing various callings and passions, such as career, family, and community involvement, while always keeping in mind the priorities of faith, love, and obedience to God.</span><span class="se">\n\n</span><span class="s2">What are some challenges you face?</span><span class="se">\n\n</span><span class="s2">As a unique individual, you will likely face many challenges and obstacles throughout your life, including self-doubt, fear, anxiety, and discouragement. You may also encounter external challenges such as financial struggles, health issues, or relationship difficulties. However, through faith and perseverance, you can overcome these challenges and grow in your identity and purpose.</span><span class="se">\n\n</span><span class="s2">How can you grow in your identity and purpose?</span><span class="se">\n\n</span><span class="s2">To grow in your identity and purpose, you must first recognize and embrace your unique identity as a beloved child of God. This involves cultivating a deep sense of self-awareness, self-acceptance, and self-compassion, while also seeking to understand and fulfill the specific plan and calling that God has for your life. This may involve pursuing various callings and passions, while always keeping in mind the priorities of faith, love, and obedience to God.</span><span class="se">\n\n</span><span class="s2">What are some practical steps you can take?</span><span class="se">\n\n</span><span class="s2">Here are some practical steps you can take to grow in your identity and purpose:</span><span class="se">\n\n</span><span class="s2">1. Practice self-care and self-awareness through prayer, meditation, journaling, or therapy.</span><span class="se">\n</span><span class="s2">2. Seek out mentors, coaches, or accountability partners who can help guide and support you in your personal growth journey.</span><span class="se">\n</span><span class="s2">3. Engage in regular spiritual practices such as Bible study, worship, or devotional exercises to deepen your faith and understanding of God&#39;s will for your life.</span><span class="se">\n</span><span class="s2">4. Set clear goals and priorities for your life, based on your unique identity and purpose, and work towards achieving them through consistent effort and persever&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="p">}],</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="s2">&#34;usage&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="s2">&#34;prompt_tokens&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="s2">&#34;completion_tokens&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="s2">&#34;total_tokens&#34;</span><span class="p">:</span> <span class="mi">0</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h3 id="using-langchain-to-call-hosted-model">Using Langchain to call hosted model</h3>
<p>The purpose of LocalAI is to adhere to OpenAI&rsquo;s API specification. Because of this, the OpenAI Python client may be used in Langchain:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.llms</span> <span class="kn">import</span> <span class="n">OpenAI</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">llm</span> <span class="o">=</span> <span class="n">OpenAI</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">temperature</span><span class="o">=</span><span class="mf">0.9</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">openai_api_key</span><span class="o">=</span><span class="s2">&#34;123&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">openai_api_base</span><span class="o">=</span><span class="s2">&#34;http://localhost:8080/v1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">model_name</span><span class="o">=</span><span class="s2">&#34;Llama-2-7B-Chat&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">text</span> <span class="o">=</span> <span class="s2">&#34;What would be a great name for a dog?&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">llm</span><span class="p">(</span><span class="n">text</span><span class="p">))</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">I&#39;m looking for something unique and fun. I want it to be a name that stands out and is memorable. Can you help me come up with some ideas?
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl">I don&#39;t want anything too common or boring, like Max or Bella. I want something that will make my dog stand out in a crowd.
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl">Can you give me some suggestions?
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl">I would love to hear your ideas!</span></span></code></pre></div>]]></content:encoded></item><item><title>How to use Chroma DB step-by-step guide</title><link>https://how.wtf/how-to-use-chroma-db-step-by-step-guide.html</link><pubDate>Thu, 16 Nov 2023 00:45:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-use-chroma-db-step-by-step-guide.html</guid><description>Vector databases have seen an increase in popularity due to the rise of Generative AI and Large Language Models (LLMs). Vector databases can be used in tandem with LLMs for Retrieval-augmented generation (RAG) - i.e. a framework for improving the quality of LLM responses by grounding prompts with context from external systems.
What is Chroma DB? Chroma is an open-source embedding database that enables retrieving relevant information for LLM prompting.</description><content:encoded><![CDATA[<p><img src="images/fZH6cy.webp" alt="how to use chroma db step-by-step"></p>
<p>Vector databases have seen an increase in popularity due to the rise of Generative AI and Large Language Models (LLMs). Vector databases can be used in tandem with LLMs for Retrieval-augmented generation (RAG) - i.e. a framework for improving the quality of LLM responses by grounding prompts with context from external systems.</p>
<h2 id="what-is-chroma-db">What is Chroma DB?</h2>
<p><img src="images/L9tqZZ.webp" alt="Chroma DB embedding process"></p>
<p>Chroma is an open-source embedding database that enables retrieving relevant information for LLM prompting. It emphasizes developer productivity, speed, and ease-of-use.</p>
<p>Chroma provides several great features:</p>
<ul>
<li>Use in-memory mode for quick POC and querying.</li>
<li>Reuse collections between runs with persistent memory options.</li>
<li>Add and delete documents after collection creation.</li>
<li>Query based on document metadata &amp; page content.</li>
</ul>
<h2 id="installing-chroma-db">Installing Chroma DB</h2>
<p>To install Chroma DB for Python, simply run the following <code>pip</code> command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install chromadb</span></span></code></pre></div><h2 id="creating-a-vector-database-using-chroma-db">Creating a vector database using Chroma DB</h2>
<p>Chroma organizes data using a <code>collection</code> primitive type to manage collections of embeddings.</p>
<h3 id="create-a-collection-using-default-embedding-function">Create a collection using default embedding function</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">client</span><span class="o">.</span><span class="n">create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span></span></span></code></pre></div><h3 id="create-a-collection-using-specific-embedding-function">Create a collection using specific embedding function</h3>
<p>Chroma uses the <code>all-MiniLM-L6-v2</code> model for creating embeddings. When instantiating a collection, we can provide the embedding function. Here, we&rsquo;ll use the default function for simplicity.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kn">from</span> <span class="nn">chromadb.utils</span> <span class="kn">import</span> <span class="n">embedding_functions</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">ef</span> <span class="o">=</span> <span class="n">embedding_functions</span><span class="o">.</span><span class="n">DefaultEmbeddingFunction</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="n">client</span><span class="o">.</span><span class="n">create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">,</span> <span class="n">embedding_function</span><span class="o">=</span><span class="n">ef</span><span class="p">)</span></span></span></code></pre></div><p>Chroma offers integrations with vendors such as <a href="https://docs.trychroma.com/embeddings/openai">OpenAI</a>, <a href="https://docs.trychroma.com/embeddings/hugging-face">Hugging Face</a>, <a href="https://docs.trychroma.com/embeddings/cohere">Cohere</a> and more.</p>
<p>Writing a custom embed function is also supported:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">chromadb</span> <span class="kn">import</span> <span class="n">Documents</span><span class="p">,</span> <span class="n">EmbeddingFunction</span><span class="p">,</span> <span class="n">Embeddings</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">class</span> <span class="nc">MyEmbeddingFunction</span><span class="p">(</span><span class="n">EmbeddingFunction</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">texts</span><span class="p">:</span> <span class="n">Documents</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Embeddings</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">        <span class="c1"># embed the documents somehow</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">        <span class="k">return</span> <span class="n">embeddings</span></span></span></code></pre></div><h2 id="using-collections-in-chroma-db">Using collections in Chroma DB</h2>
<p>In this section, we explore useful techniques for managing and using collections in Chroma DB.</p>
<h3 id="delete-collections">Delete collections</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">client</span><span class="o">.</span><span class="n">create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">client</span><span class="o">.</span><span class="n">delete_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span></span></span></code></pre></div><h3 id="get-existing-collection">Get existing collection</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">client</span><span class="o">.</span><span class="n">create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">collection</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span></span></span></code></pre></div><h3 id="get-or-create-collection">Get or create collection</h3>
<p>Chroma provides a convenient method for either getting an existing collection or creating a new one:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">collection</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_or_create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span></span></span></code></pre></div><h3 id="adding-data-to-collections">Adding data to collections</h3>
<p>Adding data to a collection is straightforward with Chroma&rsquo;s API. When you pass a list of documents to Chroma, it automatically tokenizes, embeds, and stores them.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">collection</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_or_create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">collection</span><span class="o">.</span><span class="n">add</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="n">documents</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;document1&#34;</span><span class="p">,</span> <span class="s2">&#34;document2&#34;</span><span class="p">,</span> <span class="s2">&#34;document3&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="n">metadatas</span><span class="o">=</span><span class="p">[{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;recipe&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">    <span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;2&#34;</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="p">)</span></span></span></code></pre></div><ol>
<li>The <code>documents</code> field provides the raw text for automatic conversion using the embedding function</li>
<li><code>metadatas</code> is an optional field corresponding to the uploaded documents. It&rsquo;s optional but recommended for later querying.</li>
<li><code>ids</code> is a required field for the documents. The order is important as it matches the document sequence.</li>
</ol>
<h3 id="querying-data-in-a-collection">Querying data in a collection</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">collection</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_or_create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">collection</span><span class="o">.</span><span class="n">add</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">documents</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;document1&#34;</span><span class="p">,</span> <span class="s2">&#34;document2&#34;</span><span class="p">,</span> <span class="s2">&#34;document3&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">metadatas</span><span class="o">=</span><span class="p">[{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;recipe&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;2&#34;</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">results</span> <span class="o">=</span> <span class="n">collection</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="n">query_texts</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;document&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">n_results</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="n">where</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">results</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">{
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    &#39;ids&#39;: [[&#39;2&#39;, &#39;3&#39;]],
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    &#39;distances&#39;: [
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        [0.5050200819969177, 0.5763288140296936]
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    ],
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    &#39;metadatas&#39;: [
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        [{&#39;type&#39;: &#39;article&#39;}, {&#39;type&#39;: &#39;article&#39;}]
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    ],
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    &#39;embeddings&#39;: None,
</span></span><span class="line"><span class="ln">10</span><span class="cl">    &#39;documents&#39;: [
</span></span><span class="line"><span class="ln">11</span><span class="cl">        [&#39;document2&#39;, &#39;document3&#39;]
</span></span><span class="line"><span class="ln">12</span><span class="cl">    ],
</span></span><span class="line"><span class="ln">13</span><span class="cl">    &#39;uris&#39;: None,
</span></span><span class="line"><span class="ln">14</span><span class="cl">    &#39;data&#39;: None
</span></span><span class="line"><span class="ln">15</span><span class="cl">}</span></span></code></pre></div><ol>
<li>The <code>query_texts</code> field provides the raw query string, which is automatically processed using the embedding function.</li>
<li><code>n_results</code> specifies the number of results to retrieve.</li>
<li>The <code>where</code> clause enables metadata-based filtering.</li>
</ol>
<p>In addition, the <code>where</code> field supports various operators:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">collection</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_or_create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">collection</span><span class="o">.</span><span class="n">add</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">documents</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;document1&#34;</span><span class="p">,</span> <span class="s2">&#34;document2&#34;</span><span class="p">,</span> <span class="s2">&#34;document3&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">metadatas</span><span class="o">=</span><span class="p">[{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;recipe&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;2&#34;</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">results</span> <span class="o">=</span> <span class="n">collection</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="n">query_texts</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;document&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">n_results</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="n">where</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">            <span class="s2">&#34;$eq&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="p">)</span></span></span></code></pre></div><p>For the list of supported operators, refer to the documentation <a href="https://docs.trychroma.com/usage-guide#using-where-filters">here</a>.</p>
<p>Filtering based on document content is also possible:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">collection</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_or_create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">collection</span><span class="o">.</span><span class="n">add</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">documents</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;document1&#34;</span><span class="p">,</span> <span class="s2">&#34;document2&#34;</span><span class="p">,</span> <span class="s2">&#34;document3&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">metadatas</span><span class="o">=</span><span class="p">[{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;recipe&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;2&#34;</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">results</span> <span class="o">=</span> <span class="n">collection</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="n">query_texts</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;document&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">n_results</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="n">where</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">},</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="n">where_document</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;$contains&#34;</span><span class="p">:</span> <span class="s2">&#34;2&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">results</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{
</span></span><span class="line"><span class="ln">2</span><span class="cl">    &#39;ids&#39;: [[&#39;2&#39;]],
</span></span><span class="line"><span class="ln">3</span><span class="cl">    &#39;distances&#39;: [[0.5050200819969177]],
</span></span><span class="line"><span class="ln">4</span><span class="cl">    &#39;metadatas&#39;: [[{&#39;type&#39;: &#39;article&#39;}]],
</span></span><span class="line"><span class="ln">5</span><span class="cl">    &#39;embeddings&#39;: None,
</span></span><span class="line"><span class="ln">6</span><span class="cl">    &#39;documents&#39;: [[&#39;document2&#39;]],
</span></span><span class="line"><span class="ln">7</span><span class="cl">    &#39;uris&#39;: None,
</span></span><span class="line"><span class="ln">8</span><span class="cl">    &#39;data&#39;: None
</span></span><span class="line"><span class="ln">9</span><span class="cl">}</span></span></code></pre></div><h3 id="getting-documents-based-on-id-in-the-collection">Getting documents based on id in the collection</h3>
<p>Retrieve specific documents by their IDs using the <code>collection.get</code> method:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">collection</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_or_create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">collection</span><span class="o">.</span><span class="n">add</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">documents</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;document1&#34;</span><span class="p">,</span> <span class="s2">&#34;document2&#34;</span><span class="p">,</span> <span class="s2">&#34;document3&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">metadatas</span><span class="o">=</span><span class="p">[{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;recipe&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;2&#34;</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">results</span> <span class="o">=</span> <span class="n">collection</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;1&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">results</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{
</span></span><span class="line"><span class="ln">2</span><span class="cl">    &#39;ids&#39;: [&#39;1&#39;],
</span></span><span class="line"><span class="ln">3</span><span class="cl">    &#39;embeddings&#39;: None,
</span></span><span class="line"><span class="ln">4</span><span class="cl">    &#39;metadatas&#39;: [{&#39;type&#39;: &#39;recipe&#39;}],
</span></span><span class="line"><span class="ln">5</span><span class="cl">    &#39;documents&#39;: [&#39;document1&#39;],
</span></span><span class="line"><span class="ln">6</span><span class="cl">    &#39;uris&#39;: None,
</span></span><span class="line"><span class="ln">7</span><span class="cl">    &#39;data&#39;: None
</span></span><span class="line"><span class="ln">8</span><span class="cl">}</span></span></code></pre></div><p><code>where</code> and <code>where_document</code> filters may also be used. If <code>ids</code> are not provided, all items matching the <code>where</code> and <code>where_document</code> conditions will be returned.</p>
<h3 id="getting-all-documents-in-the-collection">Getting all documents in the collection</h3>
<p>Retrieve all documents in a collection:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">collection</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_or_create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">collection</span><span class="o">.</span><span class="n">add</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">documents</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;document1&#34;</span><span class="p">,</span> <span class="s2">&#34;document2&#34;</span><span class="p">,</span> <span class="s2">&#34;document3&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">metadatas</span><span class="o">=</span><span class="p">[{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;recipe&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;2&#34;</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">results</span> <span class="o">=</span> <span class="n">collection</span><span class="o">.</span><span class="n">get</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">results</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">{
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    &#39;ids&#39;: [&#39;1&#39;, &#39;2&#39;, &#39;3&#39;],
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    &#39;embeddings&#39;: None,
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    &#39;metadatas&#39;: [
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        {&#39;type&#39;: &#39;recipe&#39;},
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        {&#39;type&#39;: &#39;article&#39;},
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        {&#39;type&#39;: &#39;article&#39;}
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    ],
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    &#39;documents&#39;: [&#39;document1&#39;, &#39;document2&#39;, &#39;document3&#39;],
</span></span><span class="line"><span class="ln">10</span><span class="cl">    &#39;uris&#39;: None,
</span></span><span class="line"><span class="ln">11</span><span class="cl">    &#39;data&#39;: None
</span></span><span class="line"><span class="ln">12</span><span class="cl">}</span></span></code></pre></div><h3 id="updating-documents-in-a-collection">Updating documents in a collection</h3>
<p>Update existing documents in a collection with new embeddings or data using the <code>collection.update</code> method.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">collection</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_or_create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">collection</span><span class="o">.</span><span class="n">add</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">documents</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;document1&#34;</span><span class="p">,</span> <span class="s2">&#34;document2&#34;</span><span class="p">,</span> <span class="s2">&#34;document3&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">metadatas</span><span class="o">=</span><span class="p">[{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;recipe&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;2&#34;</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">collection</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="n">documents</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;document10&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="n">metadatas</span><span class="o">=</span><span class="p">[{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;1&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="n">results</span> <span class="o">=</span> <span class="n">collection</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;1&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">results</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{
</span></span><span class="line"><span class="ln">2</span><span class="cl">    &#39;ids&#39;: [&#39;1&#39;],
</span></span><span class="line"><span class="ln">3</span><span class="cl">    &#39;embeddings&#39;: None,
</span></span><span class="line"><span class="ln">4</span><span class="cl">    &#39;metadatas&#39;: [{&#39;type&#39;: &#39;article&#39;}],
</span></span><span class="line"><span class="ln">5</span><span class="cl">    &#39;documents&#39;: [&#39;document10&#39;],
</span></span><span class="line"><span class="ln">6</span><span class="cl">    &#39;uris&#39;: None,
</span></span><span class="line"><span class="ln">7</span><span class="cl">    &#39;data&#39;: None
</span></span><span class="line"><span class="ln">8</span><span class="cl">}</span></span></code></pre></div><p>if a provided <code>id</code> is not found, an error is logged and the update is ignored.</p>
<p>Chroma also supports the <code>collection.upsert</code> operation as well:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">collection</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_or_create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">collection</span><span class="o">.</span><span class="n">upsert</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="n">documents</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;document1&#34;</span><span class="p">,</span> <span class="s2">&#34;document2&#34;</span><span class="p">,</span> <span class="s2">&#34;document3&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="n">metadatas</span><span class="o">=</span><span class="p">[{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;recipe&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">    <span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;2&#34;</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="p">)</span></span></span></code></pre></div><h3 id="deleting-documents-in-a-collection">Deleting documents in a collection</h3>
<p>Documents can be deleted from a collection using the <code>collection.delete</code> method:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">collection</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_or_create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">collection</span><span class="o">.</span><span class="n">upsert</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">documents</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;document1&#34;</span><span class="p">,</span> <span class="s2">&#34;document2&#34;</span><span class="p">,</span> <span class="s2">&#34;document3&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">metadatas</span><span class="o">=</span><span class="p">[{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;recipe&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;2&#34;</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">collection</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;1&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">collection</span><span class="o">.</span><span class="n">count</span><span class="p">())</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">2</span></span></code></pre></div><p>Similarly to the <code>collection.get</code>, an optional <code>where</code> filter may be supplied. If no ids are supplied, it deletes all the documents that match the <code>where</code> conditions.</p>
<h3 id="counting-the-number-of-documents-in-a-collection">Counting the number of documents in a collection</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">collection</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_or_create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">collection</span><span class="o">.</span><span class="n">upsert</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">documents</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;document1&#34;</span><span class="p">,</span> <span class="s2">&#34;document2&#34;</span><span class="p">,</span> <span class="s2">&#34;document3&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">metadatas</span><span class="o">=</span><span class="p">[{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;recipe&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;2&#34;</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">collection</span><span class="o">.</span><span class="n">count</span><span class="p">())</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">3</span></span></code></pre></div><h3 id="modifying-an-existing-collection">Modifying an existing collection</h3>
<p>Collection names may be modified after creation:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">collection</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_or_create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">collection</span><span class="o">.</span><span class="n">modify</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;new_collection_name&#34;</span><span class="p">)</span></span></span></code></pre></div><h3 id="listing-all-collections-in-a-client">Listing all collections in a client</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">Client</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">client</span><span class="o">.</span><span class="n">get_or_create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_one&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">client</span><span class="o">.</span><span class="n">get_or_create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_two&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">client</span><span class="o">.</span><span class="n">list_collections</span><span class="p">())</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">[Collection(name=collection_two), Collection(name=collection_one)]</span></span></code></pre></div><h2 id="persisting-vector-databases-using-chroma-db">Persisting vector databases using Chroma DB</h2>
<p>The in-memory Chroma client provides saving and loading to disk functionality with the <code>PersistentClient</code>.</p>
<h3 id="saving-to-disk">Saving to disk</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">PersistentClient</span><span class="p">(</span><span class="n">path</span><span class="o">=</span><span class="s2">&#34;document_store&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">collection</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_or_create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">collection</span><span class="o">.</span><span class="n">upsert</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="n">documents</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;document1&#34;</span><span class="p">,</span> <span class="s2">&#34;document2&#34;</span><span class="p">,</span> <span class="s2">&#34;document3&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="n">metadatas</span><span class="o">=</span><span class="p">[{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;recipe&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;article&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">    <span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;2&#34;</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="p">)</span></span></span></code></pre></div><h3 id="loading-an-existing-from-disk">Loading an existing from disk</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">PersistentClient</span><span class="p">(</span><span class="n">path</span><span class="o">=</span><span class="s2">&#34;document_store&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">collection</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_or_create_collection</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;collection_name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1">#collection.upsert(</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1">#    documents=[&#34;document1&#34;, &#34;document2&#34;, &#34;document3&#34;],</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1">#    metadatas=[{&#34;type&#34;: &#34;recipe&#34;}, {&#34;type&#34;: &#34;article&#34;}, {&#34;type&#34;: &#34;article&#34;}],</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1">#    ids=[&#34;1&#34;, &#34;2&#34;, &#34;3&#34;]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1">#)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">collection</span><span class="o">.</span><span class="n">get</span><span class="p">())</span></span></span></code></pre></div><p>Output:</p>





<pre tabindex="0"><code>{
    &#39;ids&#39;: [&#39;1&#39;, &#39;2&#39;, &#39;3&#39;],
    &#39;embeddings&#39;: None,
    &#39;metadatas&#39;: [
        {&#39;type&#39;: &#39;recipe&#39;},
        {&#39;type&#39;: &#39;article&#39;},
        {&#39;type&#39;: &#39;article&#39;}
    ],
    &#39;documents&#39;: [&#39;document1&#39;, &#39;document2&#39;, &#39;document3&#39;],
    &#39;uris&#39;: None,
    &#39;data&#39;: None
}</code></pre><h2 id="running-chroma-db-as-a-server">Running Chroma DB as a server</h2>
<p>Chroma may be used as a standalone server. Simply run the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">chroma run --path /document_store</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">                (((((((((    (((((####
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">             ((((((((((((((((((((((#########
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">           ((((((((((((((((((((((((###########
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">         ((((((((((((((((((((((((((############
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        (((((((((((((((((((((((((((#############
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        (((((((((((((((((((((((((((#############
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">         (((((((((((((((((((((((((##############
</span></span><span class="line"><span class="ln">10</span><span class="cl">         ((((((((((((((((((((((((##############
</span></span><span class="line"><span class="ln">11</span><span class="cl">           (((((((((((((((((((((#############
</span></span><span class="line"><span class="ln">12</span><span class="cl">             ((((((((((((((((##############
</span></span><span class="line"><span class="ln">13</span><span class="cl">                (((((((((    #########
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl">Running Chroma
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl">Saving data to: document_store
</span></span><span class="line"><span class="ln">20</span><span class="cl">Connect to chroma at: http://localhost:8000
</span></span><span class="line"><span class="ln">21</span><span class="cl">Getting started guide: https://docs.trychroma.com/getting-started</span></span></code></pre></div><p>Then connect to the local host using the <code>HttpClient</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">chromadb</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">chromadb</span><span class="o">.</span><span class="n">HttpClient</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s2">&#34;localhost&#34;</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">8000</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">client</span><span class="o">.</span><span class="n">list_collections</span><span class="p">())</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">[Collection(name=collection_name)]</span></span></code></pre></div>]]></content:encoded></item><item><title>Differences between Langchain and LlamaIndex and their use cases</title><link>https://how.wtf/differences-between-langchain-and-llamaindex-and-their-use-cases.html</link><pubDate>Tue, 14 Nov 2023 00:20:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/differences-between-langchain-and-llamaindex-and-their-use-cases.html</guid><description>What are the differences between Langchain and LlamaIndex and what are their use cases? In this article, we&amp;rsquo;ll explore these differences, helping you choose the most suitable library for your needs.
What is Langchain? As the documentation outlines,
LangChain is a framework for developing applications powered by language models.
Langchain is a framework that enables developers to build solutions powered by language models.
Some use-case examples include:
Retrieval-augmented generation (RAG) Interacting with APIs Chatbots Extraction Summarization Data Generation The main value additions from Langchain include:</description><content:encoded><![CDATA[<p>What are the differences between Langchain and LlamaIndex and what are their use cases? In this article, we&rsquo;ll explore these differences, helping you choose the most suitable library for your needs.</p>
<h2 id="what-is-langchain">What is Langchain?</h2>
<p>As the <a href="https://python.langchain.com/docs/get_started/introduction">documentation outlines</a>,</p>
<blockquote>
<p>LangChain is a framework for developing applications powered by language models.</p>
</blockquote>
<p>Langchain is a framework that enables developers to build solutions powered by language models.</p>
<p>Some use-case examples include:</p>
<ul>
<li>Retrieval-augmented generation (RAG)</li>
<li>Interacting with APIs</li>
<li>Chatbots</li>
<li>Extraction</li>
<li>Summarization</li>
<li>Data Generation</li>
</ul>
<p>The main value additions from Langchain include:</p>
<ol>
<li><strong>Components</strong>: modular tooling that is easy-to-use whether or not you&rsquo;re using the rest of Langchain&rsquo;s framework</li>
<li><strong>Off-the-shelf-chains</strong>: components assembled together to accomplish a higher-level task</li>
</ol>
<p>In addition, Langchain has made strides to streamline hosting and deploying chains with tools like <a href="https://python.langchain.com/docs/langsmith">LangSmith</a> and <a href="https://python.langchain.com/docs/langserve">LangServe</a>.</p>
<h2 id="what-is-llamaindex">What is LlamaIndex?</h2>
<p>LlamaIndex is a data framework specifically designed for language model solutions, focusing on data ingestion and querying. Its primary aim is to streamline the retrieval of necessary information, providing the language model with sufficient context to deliver the desired results.</p>
<p>At its core, the data framework provides a set of tooling that streamlines data retrieval:</p>
<ul>
<li>Data connectors: ingesting data from existing data stores</li>
<li>Data indexes: transform the data for the LLMs to easily consume</li>
<li>Engines: a purposed method for interacting with data: chat engine, query engines for RAG, etc.</li>
<li>Data Agents: LLM-powered workers that work with tools to access domain data</li>
</ul>
<h2 id="which-should-i-use">Which should I use?</h2>
<p>Choosing between the two isn&rsquo;t necessarily an either/or decision, as LlamaIndex can integrate with Langchain. You can&rsquo;t go wrong leveraging Langchain and using LlamaIndex for the RAG-specific scenarios since it&rsquo;s optimized for it.</p>
<p>If you prefer a more streamlined RAG solution without the additional features of Langchain, LlamaIndex is an excellent standalone choice.</p>
]]></content:encoded></item><item><title>Reverting changes to Git submodules</title><link>https://how.wtf/reverting-changes-to-git-submodules.html</link><pubDate>Mon, 13 Nov 2023 00:10:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/reverting-changes-to-git-submodules.html</guid><description>Reverting a submodule in Git is simple.
How to revert changes to a Git submodule The cleanest / easiest method of reverting changes to one or many git submodules is by using the following two commands:
1git submodule deinit -f . 2git submodule update --initThe git submodule deinit -f . command &amp;ldquo;deinitializes&amp;rdquo; all submodules in the repository.
The git submodule update --init command does a new checkout of them.</description><content:encoded><![CDATA[<p>Reverting a submodule in Git is simple.</p>
<h2 id="how-to-revert-changes-to-a-git-submodule">How to revert changes to a Git submodule</h2>
<p>The cleanest / easiest method of reverting changes to one or many <code>git</code> submodules is by using the following two commands:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">git submodule deinit -f .
</span></span><span class="line"><span class="ln">2</span><span class="cl">git submodule update --init</span></span></code></pre></div><p>The <code>git submodule deinit -f .</code> command &ldquo;deinitializes&rdquo; all submodules in the repository.</p>
<p>The <code>git submodule update --init</code> command does a new checkout of them.</p>
]]></content:encoded></item><item><title>Create Lambda Function URL using AWS CDK</title><link>https://how.wtf/create-lambda-function-url-using-aws-cdk.html</link><pubDate>Sun, 12 Nov 2023 01:50:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/create-lambda-function-url-using-aws-cdk.html</guid><description>Deploying Lambda Function URLs with the AWS CDK is simple.
How to deploy Function URLs using AWS Python CDK Follow the instructions below to deploy an AWS Lambda Function with a URL.
Create a requirements.txt For this tutorial, version 2.106.1 of the AWS CDK was used.
1aws-cdk-lib==2.106.1 2constructs&amp;gt;=10.0.0,&amp;lt;11.0.0Install the dependencies 1pip3 install -r requirements.txtCreate /handler folder with an index.py file 1def handler(event, context): 2 return { 3 &amp;#34;statusCode&amp;#34;: 200, 4 &amp;#34;body&amp;#34;: {&amp;#34;message&amp;#34;: &amp;#34;👋&amp;#34;} 5 }Create stack.</description><content:encoded><![CDATA[<p>Deploying Lambda Function URLs with the AWS CDK is simple.</p>
<h2 id="how-to-deploy-function-urls-using-aws-python-cdk">How to deploy Function URLs using AWS Python CDK</h2>
<p>Follow the instructions below to deploy an AWS Lambda Function with a URL.</p>
<h3 id="create-a-requirementstxt">Create a requirements.txt</h3>
<p>For this tutorial, version 2.106.1 of the AWS CDK was used.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">aws-cdk-lib==2.106.1
</span></span><span class="line"><span class="ln">2</span><span class="cl">constructs&gt;=10.0.0,&lt;11.0.0</span></span></code></pre></div><h3 id="install-the-dependencies">Install the dependencies</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip3 install -r requirements.txt</span></span></code></pre></div><h3 id="create-handler-folder-with-an-indexpy-file">Create /handler folder with an index.py file</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">def</span> <span class="nf">handler</span><span class="p">(</span><span class="n">event</span><span class="p">,</span> <span class="n">context</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="s2">&#34;statusCode&#34;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">        <span class="s2">&#34;body&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;message&#34;</span><span class="p">:</span> <span class="s2">&#34;👋&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="p">}</span></span></span></code></pre></div><h3 id="create-stackpy-with-a-basic-lambda-function">Create stack.py with a basic lambda function</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">os</span> <span class="kn">import</span> <span class="n">path</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk</span> <span class="k">as</span> <span class="nn">cdk</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk.aws_lambda</span> <span class="k">as</span> <span class="nn">lambda_</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="k">class</span> <span class="nc">FunctionUrlStack</span><span class="p">(</span><span class="n">cdk</span><span class="o">.</span><span class="n">Stack</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scope</span><span class="p">:</span> <span class="n">cdk</span><span class="o">.</span><span class="n">App</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">scope</span><span class="p">,</span> <span class="n">construct_id</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="n">lambda_function</span> <span class="o">=</span> <span class="n">lambda_</span><span class="o">.</span><span class="n">Function</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">            <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">            <span class="s2">&#34;Function&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="n">runtime</span><span class="o">=</span><span class="n">lambda_</span><span class="o">.</span><span class="n">Runtime</span><span class="o">.</span><span class="n">PYTHON_3_11</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="n">handler</span><span class="o">=</span><span class="s2">&#34;index.handler&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">            <span class="n">code</span><span class="o">=</span><span class="n">lambda_</span><span class="o">.</span><span class="n">Code</span><span class="o">.</span><span class="n">from_asset</span><span class="p">(</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="vm">__file__</span><span class="p">),</span> <span class="s2">&#34;handler&#34;</span><span class="p">)),</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl">        <span class="n">function_url</span> <span class="o">=</span> <span class="n">lambda_function</span><span class="o">.</span><span class="n">add_function_url</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">            <span class="n">auth_type</span><span class="o">=</span><span class="n">lambda_</span><span class="o">.</span><span class="n">FunctionUrlAuthType</span><span class="o">.</span><span class="n">NONE</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">
</span></span><span class="line"><span class="ln">23</span><span class="cl">        <span class="n">cdk</span><span class="o">.</span><span class="n">CfnOutput</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;FunctionUrl&#34;</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="n">function_url</span><span class="o">.</span><span class="n">url</span><span class="p">)</span></span></span></code></pre></div><h3 id="create-apppy">Create app.py</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">aws_cdk</span> <span class="k">as</span> <span class="nn">cdk</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="kn">from</span> <span class="nn">stack</span> <span class="kn">import</span> <span class="n">FunctionUrlStack</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">app</span> <span class="o">=</span> <span class="n">cdk</span><span class="o">.</span><span class="n">App</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="n">FunctionUrlStack</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="s2">&#34;FunctionUrlStack&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="n">app</span><span class="o">.</span><span class="n">synth</span><span class="p">()</span></span></span></code></pre></div><h3 id="create-cdkjson">Create cdk.json</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;app&#34;</span><span class="p">:</span> <span class="s2">&#34;python3 app.py&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>The directory structure should look like this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">project/
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── app.py
</span></span><span class="line"><span class="ln">3</span><span class="cl">├── cdk.json
</span></span><span class="line"><span class="ln">4</span><span class="cl">├── handler
</span></span><span class="line"><span class="ln">5</span><span class="cl">│   └── index.py
</span></span><span class="line"><span class="ln">6</span><span class="cl">├── requirements.txt
</span></span><span class="line"><span class="ln">7</span><span class="cl">└── stack.py</span></span></code></pre></div><h3 id="deploy-the-stack">Deploy the stack</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">cdk deploy</span></span></code></pre></div><p>Because of the <code>CfnOutput</code>, the distribution&rsquo;s domain name is in an output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Outputs:
</span></span><span class="line"><span class="ln">2</span><span class="cl">FunctionUrlStack.FunctionUrl = https://&lt;url&gt;.lambda-url.us-east-1.on.aws/</span></span></code></pre></div><p>The link will display the following text:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;message&#34;</span><span class="p">:</span> <span class="s2">&#34;👋&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Custom memory in Langchain</title><link>https://how.wtf/custom-memory-in-langchain.html</link><pubDate>Sat, 11 Nov 2023 22:10:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/custom-memory-in-langchain.html</guid><description>Implementing custom memory in Langchain is dead simple using the ChatMessageHistory class.
How to implement custom memory in Langchain (including LCEL) One of the easiest methods for storing and retrieving messages with Langchain is using the ChatMessageHistory class that is provided from the langchain.memory module.
It&amp;rsquo;s simple to get started with:
1from langchain.memory import ChatMessageHistory 2 3history = ChatMessageHistory() 4 5history.add_user_message(&amp;#34;Hello!&amp;#34;) 6 7history.add_ai_message(&amp;#34;Yo!&amp;#34;) 8 9print(history.messages) 10 11# [HumanMessage(content=&amp;#39;Hello!&amp;#39;), AIMessage(content=&amp;#39;Yo!&amp;#39;)]The interface for ChatMessageHistory is: add_user_message and add_ai_message.</description><content:encoded><![CDATA[<p>Implementing custom memory in Langchain is dead simple using the <code>ChatMessageHistory</code> class.</p>
<h2 id="how-to-implement-custom-memory-in-langchain-including-lcel">How to implement custom memory in Langchain (including LCEL)</h2>
<p>One of the easiest methods for storing and retrieving messages with Langchain is using the <code>ChatMessageHistory</code> <a href="https://python.langchain.com/docs/modules/memory/chat_messages/">class</a> that is provided from the <code>langchain.memory</code> module.</p>
<p>It&rsquo;s simple to get started with:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.memory</span> <span class="kn">import</span> <span class="n">ChatMessageHistory</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">history</span> <span class="o">=</span> <span class="n">ChatMessageHistory</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">history</span><span class="o">.</span><span class="n">add_user_message</span><span class="p">(</span><span class="s2">&#34;Hello!&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">history</span><span class="o">.</span><span class="n">add_ai_message</span><span class="p">(</span><span class="s2">&#34;Yo!&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">history</span><span class="o">.</span><span class="n">messages</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"># [HumanMessage(content=&#39;Hello!&#39;), AIMessage(content=&#39;Yo!&#39;)]</span></span></span></code></pre></div><p>The interface for <code>ChatMessageHistory</code> is: <code>add_user_message</code> and <code>add_ai_message</code>.</p>
<p>For the sake of this example, I&rsquo;m using a <code>.json</code> file with preloaded messages. A database, file, etc. may be used instead.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="nt">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">            <span class="nt">&#34;sender&#34;</span><span class="p">:</span> <span class="s2">&#34;human&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">            <span class="nt">&#34;body&#34;</span><span class="p">:</span> <span class="s2">&#34;Hello!&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">            <span class="nt">&#34;sender&#34;</span><span class="p">:</span> <span class="s2">&#34;ai&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            <span class="nt">&#34;body&#34;</span><span class="p">:</span> <span class="s2">&#34;Yo!&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.memory</span> <span class="kn">import</span> <span class="n">ChatMessageHistory</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;messages.json&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">json_file</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">content</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">json_file</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">messages</span> <span class="o">=</span> <span class="n">content</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">chat_history</span> <span class="o">=</span> <span class="n">ChatMessageHistory</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">messages</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="k">if</span> <span class="n">m</span><span class="p">[</span><span class="s2">&#34;sender&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;human&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="n">chat_history</span><span class="o">.</span><span class="n">add_user_message</span><span class="p">(</span><span class="n">m</span><span class="p">[</span><span class="s2">&#34;body&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="k">elif</span> <span class="n">m</span><span class="p">[</span><span class="s2">&#34;sender&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;ai&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="n">chat_history</span><span class="o">.</span><span class="n">add_ai_message</span><span class="p">(</span><span class="n">m</span><span class="p">[</span><span class="s2">&#34;body&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">chat_history</span><span class="o">.</span><span class="n">messages</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"># [HumanMessage(content=&#39;Hello!&#39;), AIMessage(content=&#39;Yo!&#39;)]</span></span></span></code></pre></div><p>The <code>chat_history</code> may be used for instantiating other types of memory!</p>
<p>Here is an example from the langchain <a href="https://python.langchain.com/docs/expression_language/cookbook/memory">documentation</a> using the <code>ChatMessageHistory</code> with Langchain Expression Language (LCEL):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">operator</span> <span class="kn">import</span> <span class="n">itemgetter</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.chat_models</span> <span class="kn">import</span> <span class="n">ChatOpenAI</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.memory</span> <span class="kn">import</span> <span class="n">ConversationBufferMemory</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.schema.runnable</span> <span class="kn">import</span> <span class="n">RunnablePassthrough</span><span class="p">,</span> <span class="n">RunnableLambda</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="kn">from</span> <span class="nn">langchain.prompts</span> <span class="kn">import</span> <span class="n">ChatPromptTemplate</span><span class="p">,</span> <span class="n">MessagesPlaceholder</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;messages.json&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">json_file</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="n">content</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">json_file</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">messages</span> <span class="o">=</span> <span class="n">content</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="n">chat_history</span> <span class="o">=</span> <span class="n">ChatMessageHistory</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">messages</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="k">if</span> <span class="n">m</span><span class="p">[</span><span class="s2">&#34;sender&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;human&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">        <span class="n">chat_history</span><span class="o">.</span><span class="n">add_user_message</span><span class="p">(</span><span class="n">m</span><span class="p">[</span><span class="s2">&#34;body&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="k">elif</span> <span class="n">m</span><span class="p">[</span><span class="s2">&#34;sender&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;ai&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">        <span class="n">chat_history</span><span class="o">.</span><span class="n">add_ai_message</span><span class="p">(</span><span class="n">m</span><span class="p">[</span><span class="s2">&#34;body&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="n">ChatOpenAI</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="n">prompt</span> <span class="o">=</span> <span class="n">ChatPromptTemplate</span><span class="o">.</span><span class="n">from_messages</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">    <span class="p">[</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">        <span class="p">(</span><span class="s2">&#34;system&#34;</span><span class="p">,</span> <span class="s2">&#34;You are a helpful chatbot&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">        <span class="n">MessagesPlaceholder</span><span class="p">(</span><span class="n">variable_name</span><span class="o">=</span><span class="s2">&#34;history&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">        <span class="p">(</span><span class="s2">&#34;human&#34;</span><span class="p">,</span> <span class="s2">&#34;</span><span class="si">{input}</span><span class="s2">&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="n">memory</span> <span class="o">=</span> <span class="n">ConversationBufferMemory</span><span class="p">(</span><span class="n">return_messages</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">chat_memory</span><span class="o">=</span><span class="n">chat_history</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="n">chain</span> <span class="o">=</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">    <span class="n">RunnablePassthrough</span><span class="o">.</span><span class="n">assign</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">        <span class="n">history</span><span class="o">=</span><span class="n">RunnableLambda</span><span class="p">(</span><span class="n">memory</span><span class="o">.</span><span class="n">load_memory_variables</span><span class="p">)</span> <span class="o">|</span> <span class="n">itemgetter</span><span class="p">(</span><span class="s2">&#34;history&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">    <span class="o">|</span> <span class="n">prompt</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">    <span class="o">|</span> <span class="n">model</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl">
</span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="n">inputs</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;input&#34;</span><span class="p">:</span> <span class="s2">&#34;hi im bob&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">chain</span><span class="o">.</span><span class="n">invoke</span><span class="p">(</span><span class="n">inputs</span><span class="p">)</span></span></span></code></pre></div>]]></content:encoded></item><item><title>How to iterate through JSON arrays in Bash using jq</title><link>https://how.wtf/how-to-iterate-through-json-arrays-in-bash-using-jq.html</link><pubDate>Tue, 13 Jun 2023 22:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-iterate-through-json-arrays-in-bash-using-jq.html</guid><description>Learn the simple process of iterating through a JSON array in bash with the help of jq.
Iterate through a JSON array using jq Scenario: You have a file named projects.json contains an array named &amp;ldquo;projects&amp;rdquo; that you want to iterate through.
1{ 2 &amp;#34;projects&amp;#34;: [ 3 { 4 &amp;#34;name&amp;#34;: &amp;#34;project 1&amp;#34;, 5 &amp;#34;owner&amp;#34;: &amp;#34;owner 1&amp;#34;, 6 &amp;#34;id&amp;#34;: 1, 7 &amp;#34;version&amp;#34;: &amp;#34;2.3.0&amp;#34; 8 }, 9 { 10 &amp;#34;name&amp;#34;: &amp;#34;project 2&amp;#34;, 11 &amp;#34;owner&amp;#34;: &amp;#34;owner 1&amp;#34;, 12 &amp;#34;id&amp;#34;: 2, 13 &amp;#34;version&amp;#34;: &amp;#34;1.</description><content:encoded><![CDATA[<p>Learn the simple process of iterating through a JSON array in bash with the help of <code>jq</code>.</p>
<h2 id="iterate-through-a-json-array-using-jq">Iterate through a JSON array using <code>jq</code></h2>
<p><strong>Scenario</strong>: You have a file named <code>projects.json</code> contains an array named &ldquo;projects&rdquo; that you want to iterate through.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">	<span class="nt">&#34;projects&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">		<span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">			<span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;project 1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">			<span class="nt">&#34;owner&#34;</span><span class="p">:</span> <span class="s2">&#34;owner 1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">			<span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">			<span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;2.3.0&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">		<span class="p">},</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">		<span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">			<span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;project 2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">			<span class="nt">&#34;owner&#34;</span><span class="p">:</span> <span class="s2">&#34;owner 1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">			<span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">			<span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;1.54.0&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">		<span class="p">},</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">		<span class="p">{</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">			<span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;project 3&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">			<span class="nt">&#34;owner&#34;</span><span class="p">:</span> <span class="s2">&#34;owner 2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">			<span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">			<span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;4.9.2&#34;</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">	<span class="p">]</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>To achieve this, you can use the bash snippet below:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">jq -c <span class="s1">&#39;.projects[]&#39;</span> projects.json <span class="p">|</span> <span class="k">while</span> <span class="nb">read</span> i<span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$i</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">done</span></span></span></code></pre></div><p>The command uses jq to extract each object in the &ldquo;projects&rdquo; array and then uses a while loop to iterate through the extracted objects. The echo statement prints each object.</p>
<p>The output will be:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{&#34;name&#34;:&#34;project 1&#34;,&#34;owner&#34;:&#34;owner 1&#34;,&#34;id&#34;:1,&#34;version&#34;:&#34;2.3.0&#34;}
</span></span><span class="line"><span class="ln">2</span><span class="cl">{&#34;name&#34;:&#34;project 2&#34;,&#34;owner&#34;:&#34;owner 1&#34;,&#34;id&#34;:2,&#34;version&#34;:&#34;1.54.0&#34;}
</span></span><span class="line"><span class="ln">3</span><span class="cl">{&#34;name&#34;:&#34;project 3&#34;,&#34;owner&#34;:&#34;owner 2&#34;,&#34;id&#34;:3,&#34;version&#34;:&#34;4.9.2&#34;}</span></span></code></pre></div><h2 id="iterate-through-a-json-array-using-jq-and-associative-arrays-in-bash">Iterate through a JSON array using <code>jq</code> and associative arrays in Bash</h2>
<p>If your version of bash supports associative arrays, you can use an alternative approach:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">readarray -t projects &lt; &lt;<span class="o">(</span>jq -c <span class="s1">&#39;.projects[]&#39;</span> projects.json<span class="o">)</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">for</span> i in <span class="s2">&#34;</span><span class="si">${</span><span class="nv">projects</span><span class="p">[@]</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$i</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">done</span></span></span></code></pre></div><p>This command stores each object from the &ldquo;projects&rdquo; array in an associative array called projects. Then, it uses a for loop to iterate through the objects and echo to print each object.</p>
<p>The output will be the same as before:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{&#34;name&#34;:&#34;project 1&#34;,&#34;owner&#34;:&#34;owner 1&#34;,&#34;id&#34;:1,&#34;version&#34;:&#34;2.3.0&#34;}
</span></span><span class="line"><span class="ln">2</span><span class="cl">{&#34;name&#34;:&#34;project 2&#34;,&#34;owner&#34;:&#34;owner 1&#34;,&#34;id&#34;:2,&#34;version&#34;:&#34;1.54.0&#34;}
</span></span><span class="line"><span class="ln">3</span><span class="cl">{&#34;name&#34;:&#34;project 3&#34;,&#34;owner&#34;:&#34;owner 2&#34;,&#34;id&#34;:3,&#34;version&#34;:&#34;4.9.2&#34;}</span></span></code></pre></div>]]></content:encoded></item><item><title>DynamoDB auto incrementing keys: Why UUIDs are the recommended choice</title><link>https://how.wtf/dynamodb-auto-incrementing-keys-why-uuids-are-the-recommended-choice.html</link><pubDate>Sun, 11 Jun 2023 11:05:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/dynamodb-auto-incrementing-keys-why-uuids-are-the-recommended-choice.html</guid><description>When working with Amazon DynamoDB, the design of the primary key plays a crucial role. Unlike traditional relational databases, DynamoDB does not natively support auto-incrementing primary keys. However, there are alternative approaches that provide greater flexibility and scalability.
In this article, we will explore the drawbacks of auto-incrementing primary keys in DynamoDB and present UUIDs as a recommended alternative.
The Problem with Auto-Incrementing Keys Auto-incrementing keys can result in hotspots and performance bottlenecks in DynamoDB.</description><content:encoded><![CDATA[<p>When working with Amazon DynamoDB, the design of the primary key plays a crucial role. Unlike traditional relational databases, DynamoDB does not natively support auto-incrementing primary keys. However, there are alternative approaches that provide greater flexibility and scalability.</p>
<p>In this article, we will explore the drawbacks of auto-incrementing primary keys in DynamoDB and present UUIDs as a recommended alternative.</p>
<h2 id="the-problem-with-auto-incrementing-keys">The Problem with Auto-Incrementing Keys</h2>
<p>Auto-incrementing keys can result in hotspots and performance bottlenecks in DynamoDB. This occurs because new records are appended to the end of the table or partition, leading to an uneven distribution of data.</p>
<p>Furthermore, this uneven distribution can cause certain partitions to be overloaded while others remain underutilized, adversely impacting the scalability and performance of the system.</p>
<h2 id="alternatives-to-auto-incrementing">Alternatives to Auto-Incrementing</h2>
<p>As a viable alternative, UUIDs (Universally Unique IDs) offer a solution.</p>
<p>UUIDs ensure a low probability of collisions, even when generated across distributed systems. This makes them highly suitable for maintaining uniqueness in DynamoDB primary keys.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">uuid</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">dynamodb</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s1">&#39;dynamodb&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">table</span> <span class="o">=</span> <span class="n">dynamodb</span><span class="o">.</span><span class="n">Table</span><span class="p">(</span><span class="s1">&#39;users&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">table</span><span class="o">.</span><span class="n">put_item</span><span class="p">(</span><span class="n">Item</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="s1">&#39;user_id&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">uuid</span><span class="o">.</span><span class="n">uuid4</span><span class="p">()),</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="s1">&#39;Foo bar&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="s1">&#39;email&#39;</span><span class="p">:</span> <span class="s1">&#39;foobar@example.com&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="s1">&#39;age&#39;</span><span class="p">:</span> <span class="mi">55</span> 
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><p>In the code snippet above, a user named Foo bar is inserted into a DynamoDB table using a generated UUID as the primary key.</p>
]]></content:encoded></item><item><title>Pico vs Nano A Comparison of Lightweight Text Editors</title><link>https://how.wtf/pico-vs-nano-a-comparison-of-lightweight-text-editors.html</link><pubDate>Sat, 10 Jun 2023 11:15:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/pico-vs-nano-a-comparison-of-lightweight-text-editors.html</guid><description>When it comes to lightweight text editors, Pico and Nano are viable options that are available on Unix-based systems. While they share similarities, understanding their differences will enable users to make an informed choice.
What is Pico? Pico (Pine composer) is a user-friendly text editor known for its simplicity. It features a straightforward interface with an accessible on-screen menu.
The intentions of the software are clear:
Move the cursor by using arrow keys Insert a character by typing Save, spell check, etc.</description><content:encoded><![CDATA[<p>When it comes to lightweight text editors, Pico and Nano are viable options that are available on Unix-based systems. While they share similarities, understanding their differences will enable users to make an informed choice.</p>
<h2 id="what-is-pico">What is Pico?</h2>
<p>Pico (Pine composer) is a user-friendly text editor known for its simplicity. It features a straightforward interface with an accessible on-screen menu.</p>
<p>The intentions of the software are clear:</p>
<ol>
<li>Move the cursor by using arrow keys</li>
<li>Insert a character by typing</li>
<li>Save, spell check, etc. by leveraging the on-screen menu instructions</li>
</ol>
<h2 id="history-of-pico">History of Pico</h2>
<p>Pico was integrated with the Pine email client, which was developed by the University of Washington and made public in 1992.</p>
<p><strong>NOTE</strong>: Pico is not actively developed.</p>
<h2 id="what-is-nano">What is Nano?</h2>
<p>Nano is a modern replacement for Pico that offers additional features and ongoing development. It aims to provide a more powerful editing experience over its predecessor while retaining simplicity.</p>
<p>Nano supports the following features <em>and more</em>:</p>
<ul>
<li>Syntax highlighting for software</li>
<li>Multiple buffers</li>
<li>Regular expression matching</li>
<li>Customizable keybindings</li>
</ul>
<h2 id="history-of-nano">History of Nano</h2>
<p>Nano was released by Chris Allegretta in 1999 and became apart of the GNU Project in 2001. It was developed because Pico&rsquo;s earlier license had ambiguous redistribution terms; however, newer version of Pico were released under Apache License V2.</p>
<p>Nano development continues to this day and has an active community of users.</p>
<h2 id="should-pico-or-nano-be-used">Should <code>pico</code> or <code>nano</code> be used?</h2>
<p>The choice between the two ultimately depends on the user&rsquo;s needs and preferences.</p>
<p>A few notable points:</p>
<ul>
<li><code>pico</code> is not actively developed</li>
<li><code>pico</code> does not contain common program tooling: syntax highlighting, regex search, etc.</li>
<li><code>pico</code> does not support multiple buffers</li>
</ul>
]]></content:encoded></item><item><title>Use virtualenv with a Python Jupyter notebook</title><link>https://how.wtf/use-virtualenv-with-a-python-jupyter-notebook.html</link><pubDate>Thu, 08 Jun 2023 23:50:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/use-virtualenv-with-a-python-jupyter-notebook.html</guid><description>Using a virtual environment with a Jupyter notebook is easy!
Install and use virtualenv For instructions on installing, using, and activating virtualenv, refer to my blog article here.
NOTE: You may use your virtual environment of choice.
Add virtualenv environment to Jupyter notebook Activate the virtual environment Install ipykernel 1pip3 install ipykernel Use the ipykernel install command 1python3 -m ipykernel install --user --name=venv # this name can be anything Open jupyter-lab and click on the environment labeled venv The ipykernel install command uses the current environment when creating the kernel.</description><content:encoded><![CDATA[<p>Using a virtual environment with a Jupyter notebook is easy!</p>
<h2 id="install-and-use-virtualenv">Install and use <code>virtualenv</code></h2>
<p>For instructions on installing, using, and activating <code>virtualenv</code>, refer to my blog article <a href="https://how.wtf/using-virtualenv-with-python.html">here</a>.</p>
<p><strong>NOTE</strong>: You may use your virtual environment of choice.</p>
<h2 id="add-virtualenv-environment-to-jupyter-notebook">Add <code>virtualenv</code> environment to Jupyter notebook</h2>
<ol>
<li>Activate the virtual environment</li>
<li>Install <code>ipykernel</code></li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip3 install ipykernel</span></span></code></pre></div><ol start="3">
<li>Use the <code>ipykernel install</code> command</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">python3 -m ipykernel install --user --name<span class="o">=</span>venv <span class="c1"># this name can be anything</span></span></span></code></pre></div><ol start="4">
<li>Open <code>jupyter-lab</code> and click on the environment labeled <code>venv</code></li>
</ol>
<p>The <code>ipykernel install</code> command uses the current environment when creating the kernel.</p>
]]></content:encoded></item><item><title>Create an HTTP server in one line</title><link>https://how.wtf/create-an-http-server-in-one-line.html</link><pubDate>Wed, 07 Jun 2023 20:40:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/create-an-http-server-in-one-line.html</guid><description>If you need a quick one-liner HTTP server from the command line, Python comes in handy.
How to create an HTTP server in one line Python enables users to run a simple command to spin up an HTTP server:
1python -m http.server &amp;lt;PORT&amp;gt;Example:
1python -m http.server 4000By default, this command will serve the files in the current directory using a single-threaded HTTP server bound to localhost.
In addition, users may specify a different directory:</description><content:encoded><![CDATA[<p>If you need a quick one-liner HTTP server from the command line, Python comes in handy.</p>
<h2 id="how-to-create-an-http-server-in-one-line">How to create an HTTP server in one line</h2>
<p>Python enables users to run a simple command to spin up an HTTP server:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">python -m http.server &lt;PORT&gt;</span></span></code></pre></div><p>Example:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">python -m http.server <span class="m">4000</span></span></span></code></pre></div><p>By default, this command will serve the files in the current directory using a single-threaded HTTP server bound to localhost.</p>
<p>In addition, users may specify a different directory:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">python -m http.server &lt;PORT&gt; --directory &lt;FILE PATH&gt;</span></span></code></pre></div>]]></content:encoded></item><item><title>shuf command in Linux</title><link>https://how.wtf/shuf-command-in-linux.html</link><pubDate>Mon, 05 Jun 2023 23:55:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/shuf-command-in-linux.html</guid><description>What is the shuf command in Linux?
What is the shuf command? The shuf command in Linux is a utility for shuffling lines of input files. It allows users to shuffle contents of a file or produce random output based on supplied arguments.
How is the shuf command used? Given a file named quotes.txt with the following contents:
1&amp;#34;The only way to do great work is to love what you do.</description><content:encoded><![CDATA[<p>What is the <code>shuf</code> command in Linux?</p>
<h2 id="what-is-the-shuf-command">What is the <code>shuf</code> command?</h2>
<p>The <code>shuf</code> command in Linux is a utility for shuffling lines of input files. It allows users to shuffle contents of a file or produce random output based on supplied arguments.</p>
<h2 id="how-is-the-shuf-command-used">How is the <code>shuf</code> command used?</h2>
<p>Given a file named <code>quotes.txt</code> with the following contents:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">&#34;The only way to do great work is to love what you do.&#34; - Steve Jobs
</span></span><span class="line"><span class="ln">2</span><span class="cl">&#34;In the end, it&#39;s not the years in your life that count. It&#39;s the life in your years.&#34; - Abraham Lincoln
</span></span><span class="line"><span class="ln">3</span><span class="cl">&#34;Success is not final, failure is not fatal: It is the courage to continue that counts.&#34; - Winston Churchill
</span></span><span class="line"><span class="ln">4</span><span class="cl">&#34;Believe you can and you&#39;re halfway there.&#34; - Theodore Roosevelt
</span></span><span class="line"><span class="ln">5</span><span class="cl">&#34;Be yourself; everyone else is already taken.&#34; - Oscar Wilde</span></span></code></pre></div><p>the <code>shuf</code> command allows for a random permutation of all the lines.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">% shuf quotes.txt
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s2">&#34;Success is not final, failure is not fatal: It is the courage to continue that counts.&#34;</span> - Winston Churchill
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="s2">&#34;In the end, it&#39;s not the years in your life that count. It&#39;s the life in your years.&#34;</span> - Abraham Lincoln
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="s2">&#34;The only way to do great work is to love what you do.&#34;</span> - Steve Jobs
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="s2">&#34;Believe you can and you&#39;re halfway there.&#34;</span> - Theodore Roosevelt
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="s2">&#34;Be yourself; everyone else is already taken.&#34;</span> - Oscar Wilde</span></span></code></pre></div><p>In addition, it can be used in the following scenarios as well:</p>
<p>List 1 random quote:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">% shuf -n <span class="m">1</span> quotes.txt
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s2">&#34;In the end, it&#39;s not the years in your life that count. It&#39;s the life in your years.&#34;</span> - Abraham Lincoln</span></span></code></pre></div><p>List random numbers between a range of numbers:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">% shuf -i 0-5
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="m">4</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="m">1</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="m">0</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="m">2</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="m">3</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="m">5</span></span></span></code></pre></div><p>Give <code>shuf</code> a list of options using <code>-e</code> and outputing 1 chosen line using <code>-n</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">% shuf -e option1 option2 option3 -n <span class="m">1</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">option3</span></span></code></pre></div><p>Standard input works as well:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">% seq <span class="m">5</span> <span class="p">|</span> shuf
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="m">5</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="m">2</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="m">4</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="m">1</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="m">3</span></span></span></code></pre></div>]]></content:encoded></item><item><title>rev command in Linux and how to reverse strings</title><link>https://how.wtf/rev-command-in-linux-and-how-to-reverse-strings.html</link><pubDate>Sun, 04 Jun 2023 23:00:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/rev-command-in-linux-and-how-to-reverse-strings.html</guid><description>What is the rev command in Linux?
What is the rev command? As the name implies, the rev command (short for reverse) allows users to reverse a line of characters or a file.
How is the rev command used? The rev command is typically supplied a string of characters or a file input.
rev with a file If a file named example.txt contains:
1This is a line of text 2txet fo enil a si siht 3another oneand rev is supplied example.</description><content:encoded><![CDATA[<p>What is the <code>rev</code> command in Linux?</p>
<h2 id="what-is-the-rev-command">What is the <code>rev</code> command?</h2>
<p>As the name implies, the <code>rev</code> command (short for reverse) allows users to reverse a line of characters <em>or</em> a file.</p>
<h2 id="how-is-the-rev-command-used">How is the <code>rev</code> command used?</h2>
<p>The <code>rev</code> command is typically supplied a string of characters <em>or</em> a file input.</p>
<h3 id="rev-with-a-file"><code>rev</code> with a file</h3>
<p>If a file named <code>example.txt</code> contains:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">This is a line of text
</span></span><span class="line"><span class="ln">2</span><span class="cl">txet fo enil a si siht
</span></span><span class="line"><span class="ln">3</span><span class="cl">another one</span></span></code></pre></div><p>and <code>rev</code> is supplied <code>example.txt</code>, then the output will showcase the reversed result.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">% rev example.txt
</span></span><span class="line"><span class="ln">2</span><span class="cl">txet fo enil a si sihT
</span></span><span class="line"><span class="ln">3</span><span class="cl">this is a line of text
</span></span><span class="line"><span class="ln">4</span><span class="cl">eno rehtona</span></span></code></pre></div><h3 id="rev-with-standard-input"><code>rev</code> with standard input</h3>
<p><code>rev</code> accepts standard input by default.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">% rev
</span></span><span class="line"><span class="ln">2</span><span class="cl">this is a line
</span></span><span class="line"><span class="ln">3</span><span class="cl">enil a si siht</span></span></code></pre></div><p><strong>OR</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">% <span class="nb">echo</span> this is a line <span class="p">|</span> rev
</span></span><span class="line"><span class="ln">2</span><span class="cl">enil a si siht</span></span></code></pre></div><p>This is useful for scripting capabilities:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">foo</span><span class="o">=</span><span class="s2">&#34;I want this text reversed&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nv">bar</span><span class="o">=</span><span class="k">$(</span><span class="nb">echo</span> <span class="nv">$foo</span> <span class="p">|</span> rev<span class="k">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">echo</span> <span class="nv">$bar</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Undo and redo changes in Vim</title><link>https://how.wtf/undo-and-redo-changes-in-vim.html</link><pubDate>Sat, 03 Jun 2023 23:25:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/undo-and-redo-changes-in-vim.html</guid><description>Undo and redo operations are seamless using Vim.
How to undo changes in Vim To undo changes in Vim, press u. In addition, using any combination of the :u[ndo] command:
:u :un :und :undo How to redo changes in Vim To redo changes in Vim, press CTRL-R. In addition, using any combination :red[o] command:
:red :redo</description><content:encoded><![CDATA[<p>Undo and redo operations are seamless using Vim.</p>
<h2 id="how-to-undo-changes-in-vim">How to undo changes in Vim</h2>
<p>To undo changes in Vim, press <code>u</code>. In addition, using any combination of the <code>:u[ndo]</code> command:</p>
<ul>
<li><code>:u</code></li>
<li><code>:un</code></li>
<li><code>:und</code></li>
<li><code>:undo</code></li>
</ul>
<h2 id="how-to-redo-changes-in-vim">How to redo changes in Vim</h2>
<p>To redo changes in Vim, press CTRL-R. In addition, using any combination <code>:red[o]</code> command:</p>
<ul>
<li><code>:red</code></li>
<li><code>:redo</code></li>
</ul>
]]></content:encoded></item><item><title>Invalid constructor name error in Apex</title><link>https://how.wtf/invalid-constructor-name-error-in-apex.html</link><pubDate>Sat, 03 Jun 2023 12:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/invalid-constructor-name-error-in-apex.html</guid><description>When deploying apex classes, a user may run into an odd error: Error: Compile Error: Invalid constructor name.
How to solve Invalid constructor name Upon initial inspection, this error may be misleading. The class in question contains a working constructor or a new method was added that is not a constructor.
What gives?
Normally, this error indicates that a new method was added without adding the return type.
Example:
1public class Foo { 2 3 private String bar; 4 5 public Foo(String bar) { 6 this.</description><content:encoded><![CDATA[<p>When deploying apex classes, a user may run into an odd error: <code>Error: Compile Error: Invalid constructor name</code>.</p>
<h2 id="how-to-solve-invalid-constructor-name">How to solve <code>Invalid constructor name</code></h2>
<p>Upon initial inspection, this error may be misleading. The class in question contains a working constructor <em>or</em> a new method was added that is <strong>not</strong> a constructor.</p>
<p><strong>What gives?</strong></p>
<p>Normally, this error indicates that a new method was added without adding the return type.</p>
<p>Example:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">Foo</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">    </span><span class="kd">private</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">bar</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="kd">public</span><span class="w"> </span><span class="nf">Foo</span><span class="p">(</span><span class="n">String</span><span class="w"> </span><span class="n">bar</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">        </span><span class="k">this</span><span class="p">.</span><span class="na">bar</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">bar</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="kd">public</span><span class="w"> </span><span class="nf">newMethod</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">        </span><span class="c1">// logic</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><p>To fix this, simply add the return type to the method:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">Foo</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">    </span><span class="kd">private</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">bar</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="kd">public</span><span class="w"> </span><span class="nf">Foo</span><span class="p">(</span><span class="n">String</span><span class="w"> </span><span class="n">bar</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">        </span><span class="k">this</span><span class="p">.</span><span class="na">bar</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">bar</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="c1">// added void return type</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">newMethod</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">        </span><span class="c1">// logic</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h2 id="why-does-this-error-happen">Why does this error happen?</h2>
<p>When a return type is omitted, the method is interpreted as a constructor because constructors do not contain return types.</p>
]]></content:encoded></item><item><title>What is the apropos command in Linux</title><link>https://how.wtf/what-is-the-apropos-command-in-linux.html</link><pubDate>Thu, 01 Jun 2023 23:40:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/what-is-the-apropos-command-in-linux.html</guid><description>Recently, I was made aware of the apropos command in Linux. What is it? What is it used for?
What is the apropos command? apropos enables users to search terminal commands based on a keywords or descriptions.
This is an incredibly useful tool because it quickly identifies commands based on man pages.
Scenario: I forgot the command name for the qalculate CLI I installed.
1% apropos calculator 2qalc(1) - Powerful and easy to use command line calculator 3transicc(1) - little cms ColorSpace conversion calculator 4bc(1) - arbitrary-precision decimal arithmetic language and calculator 5dc(1) - arbitrary-precision decimal reverse-Polish notation calculator 6bc(1) - arbitrary-precision decimal arithmetic language and calculator 7dc(1) - arbitrary-precision decimal reverse-Polish notation calculatorqalc was the first result.</description><content:encoded><![CDATA[<p>Recently, I was made aware of the <code>apropos</code> command in Linux. What is it? What is it used for?</p>
<h2 id="what-is-the-apropos-command">What is the <code>apropos</code> command?</h2>
<p><code>apropos</code> enables users to search terminal commands based on a keywords or descriptions.</p>
<p>This is an incredibly useful tool because it quickly identifies commands based on man pages.</p>
<p>Scenario: I forgot the command name for the qalculate CLI I installed.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">% apropos calculator
</span></span><span class="line"><span class="ln">2</span><span class="cl">qalc<span class="o">(</span>1<span class="o">)</span>                  - Powerful and easy to use <span class="nb">command</span> line calculator
</span></span><span class="line"><span class="ln">3</span><span class="cl">transicc<span class="o">(</span>1<span class="o">)</span>              - little cms ColorSpace conversion calculator
</span></span><span class="line"><span class="ln">4</span><span class="cl">bc<span class="o">(</span>1<span class="o">)</span>                    - arbitrary-precision decimal arithmetic language and calculator
</span></span><span class="line"><span class="ln">5</span><span class="cl">dc<span class="o">(</span>1<span class="o">)</span>                    - arbitrary-precision decimal reverse-Polish notation calculator
</span></span><span class="line"><span class="ln">6</span><span class="cl">bc<span class="o">(</span>1<span class="o">)</span>                    - arbitrary-precision decimal arithmetic language and calculator
</span></span><span class="line"><span class="ln">7</span><span class="cl">dc<span class="o">(</span>1<span class="o">)</span>                    - arbitrary-precision decimal reverse-Polish notation calculator</span></span></code></pre></div><p><code>qalc</code> was the first result.</p>
<h2 id="nothing-appropriate-error">Nothing appropriate error</h2>
<p>If the man database is not updated, <code>apropos</code> may report an error when looking up commands:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">% apropos calculator
</span></span><span class="line"><span class="ln">2</span><span class="cl">calculator: nothing appropriate.</span></span></code></pre></div><p>To fix it, update the man pages:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">mandb</span></span></code></pre></div>]]></content:encoded></item><item><title>What is double asterisk kwargs in Python</title><link>https://how.wtf/what-is-double-asterisk-kwargs-in-python.html</link><pubDate>Wed, 31 May 2023 23:35:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/what-is-double-asterisk-kwargs-in-python.html</guid><description>When developing in Python, it&amp;rsquo;s common to come across **kwargs.
What is the double asterisk (**) in Python? If a function parameter explictly denotes the double asterisk:
1def foo(**kwargs): 2 print(kwargs) 3 4foo(bar=&amp;#34;test&amp;#34;, baz=5)kwargs will represent a dictionary of the key word arguments given to the function.
NOTE: kwargs is a standard name that refers to &amp;ldquo;key word arguments&amp;rdquo;; however, any name may be used.
Output:
1{&amp;#39;bar&amp;#39;: &amp;#39;test&amp;#39;, &amp;#39;baz&amp;#39;: 5}</description><content:encoded><![CDATA[<p>When developing in Python, it&rsquo;s common to come across <code>**kwargs</code>.</p>
<h2 id="what-is-the-double-asterisk--in-python">What is the double asterisk (**) in Python?</h2>
<p>If a function parameter explictly denotes the double asterisk:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">foo</span><span class="p">(</span><span class="n">bar</span><span class="o">=</span><span class="s2">&#34;test&#34;</span><span class="p">,</span> <span class="n">baz</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span></span></span></code></pre></div><p><code>kwargs</code> will represent a dictionary of the key word arguments given to the function.</p>
<p><strong>NOTE</strong>: <code>kwargs</code> is a standard name that refers to &ldquo;key word arguments&rdquo;; however, any name may be used.</p>
<p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{&#39;bar&#39;: &#39;test&#39;, &#39;baz&#39;: 5}</span></span></code></pre></div>]]></content:encoded></item><item><title>Sort a dictionary by key or value in Python</title><link>https://how.wtf/sort-a-dictionary-by-key-or-value-in-python.html</link><pubDate>Tue, 30 May 2023 23:35:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/sort-a-dictionary-by-key-or-value-in-python.html</guid><description>Sorting based on a dictionary value or key is easy using Python.
Sort by value in a dictionary In Python 3.7 and above, a combination of dictionary comprehension and sorted can be used:
1foo = {&amp;#34;first&amp;#34;: 1, &amp;#34;third&amp;#34;: 3, &amp;#34;second&amp;#34;: 2, &amp;#34;zeroth&amp;#34;: 0} 2print({k: v for k, v in sorted(foo.items(), key=lambda i: i[1])})In addition,
1foo = {&amp;#34;first&amp;#34;: 1, &amp;#34;third&amp;#34;: 3, &amp;#34;second&amp;#34;: 2, &amp;#34;zeroth&amp;#34;: 0} 2print(dict(sorted(foo.items(), key=lambda i: i[1])))Output:
1{&amp;#39;zeroth&amp;#39;: 0, &amp;#39;first&amp;#39;: 1, &amp;#39;second&amp;#39;: 2, &amp;#39;third&amp;#39;: 3}sorted allows a optional keyword argument of key: a function to execute for ordering.</description><content:encoded><![CDATA[<p>Sorting based on a dictionary value or key is <em>easy</em> using Python.</p>
<h2 id="sort-by-value-in-a-dictionary">Sort by value in a dictionary</h2>
<p>In Python 3.7 and above, a combination of dictionary comprehension and <code>sorted</code> can be used:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">foo</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;first&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">&#34;third&#34;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="s2">&#34;second&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="s2">&#34;zeroth&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">}</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">print</span><span class="p">({</span><span class="n">k</span><span class="p">:</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">foo</span><span class="o">.</span><span class="n">items</span><span class="p">(),</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="n">i</span><span class="p">[</span><span class="mi">1</span><span class="p">])})</span></span></span></code></pre></div><p>In addition,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">foo</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;first&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">&#34;third&#34;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="s2">&#34;second&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="s2">&#34;zeroth&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">}</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">foo</span><span class="o">.</span><span class="n">items</span><span class="p">(),</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="n">i</span><span class="p">[</span><span class="mi">1</span><span class="p">])))</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{&#39;zeroth&#39;: 0, &#39;first&#39;: 1, &#39;second&#39;: 2, &#39;third&#39;: 3}</span></span></code></pre></div><p><code>sorted</code> allows a optional keyword argument of <code>key</code>: a function to execute for ordering.</p>
<h2 id="sort-by-key-in-a-dictionary">Sort by key in a dictionary</h2>
<p>Similar to the technique before, the <code>lambda</code> argument can reference the 0th index to sort by the dictionary keys.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">foo</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;first&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">&#34;third&#34;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="s2">&#34;second&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="s2">&#34;zeroth&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">}</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">print</span><span class="p">({</span><span class="n">k</span><span class="p">:</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">foo</span><span class="o">.</span><span class="n">items</span><span class="p">(),</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="n">i</span><span class="p">[</span><span class="mi">0</span><span class="p">])})</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{&#39;first&#39;: 1, &#39;second&#39;: 2, &#39;third&#39;: 3, &#39;zeroth&#39;: 0}</span></span></code></pre></div>]]></content:encoded></item><item><title>Iterate through two lists in parallel in Python</title><link>https://how.wtf/iterate-through-two-lists-in-parallel-in-python.html</link><pubDate>Mon, 29 May 2023 21:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/iterate-through-two-lists-in-parallel-in-python.html</guid><description>Iterating through a two lists in parallel is natively handled in Python using the zip function.
Iterate through two lists using zip Python&amp;rsquo;s zip function will aggregate elements from two or more iterables.
1foo = [&amp;#34;x&amp;#34;, &amp;#34;y&amp;#34;, &amp;#34;z&amp;#34;] 2bar = [1, 2, 3] 3 4for f, b in zip(foo, bar): 5 print(f, b)Output:
1x 1 2y 2 3z 3This works with any number of iterables:
1foo = [&amp;#34;x&amp;#34;, &amp;#34;y&amp;#34;, &amp;#34;z&amp;#34;] 2bar = [1, 2, 3] 3baz = [&amp;#34;!</description><content:encoded><![CDATA[<p>Iterating through a two lists in parallel is natively handled in Python using the <code>zip</code> function.</p>
<h2 id="iterate-through-two-lists-using-zip">Iterate through two lists using <code>zip</code></h2>
<p>Python&rsquo;s <code>zip</code> function will aggregate elements from two or more iterables.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">foo</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;x&#34;</span><span class="p">,</span> <span class="s2">&#34;y&#34;</span><span class="p">,</span> <span class="s2">&#34;z&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">bar</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">for</span> <span class="n">f</span><span class="p">,</span> <span class="n">b</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">foo</span><span class="p">,</span> <span class="n">bar</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">  <span class="nb">print</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">x 1
</span></span><span class="line"><span class="ln">2</span><span class="cl">y 2
</span></span><span class="line"><span class="ln">3</span><span class="cl">z 3</span></span></code></pre></div><p>This works with any number of iterables:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">foo</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;x&#34;</span><span class="p">,</span> <span class="s2">&#34;y&#34;</span><span class="p">,</span> <span class="s2">&#34;z&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">bar</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">baz</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;!&#34;</span><span class="p">,</span> <span class="s2">&#34;@&#34;</span><span class="p">,</span> <span class="s2">&#34;#&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="k">for</span> <span class="n">f</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">z</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">foo</span><span class="p">,</span> <span class="n">bar</span><span class="p">,</span> <span class="n">baz</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">  <span class="nb">print</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">z</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">x 1 !
</span></span><span class="line"><span class="ln">2</span><span class="cl">y 2 @
</span></span><span class="line"><span class="ln">3</span><span class="cl">z 3 #</span></span></code></pre></div><p>If the index is necessary, use <code>enumerate</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">foo</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;x&#34;</span><span class="p">,</span> <span class="s2">&#34;y&#34;</span><span class="p">,</span> <span class="s2">&#34;z&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">bar</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">foo</span><span class="p">,</span> <span class="n">bar</span><span class="p">)):</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">  <span class="nb">print</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">f</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">0 x 1
</span></span><span class="line"><span class="ln">2</span><span class="cl">1 y 2
</span></span><span class="line"><span class="ln">3</span><span class="cl">2 z 3</span></span></code></pre></div>]]></content:encoded></item><item><title>How to install Neovim on Ubuntu</title><link>https://how.wtf/how-to-install-neovim-on-ubuntu.html</link><pubDate>Sun, 28 May 2023 23:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-install-neovim-on-ubuntu.html</guid><description>Installing Neovim on Debian-based distributions: Ubuntu, Mint, etc. is easy!
Install Neovim on Ubuntu Neovim is available through the Debian package manager. Simply execute the following command:
1sudo apt install neovimInstall Neovim using PPA The default Neovim version bundled with apt is normally outdated. To install a newer version, a PPA (Personal Package Archive) must be used.
NOTE: The Neovim PPAs are not maintained by the Neovim team
Neovim stable PPA To install the latest stable Neovim version using apt, add the following PPA:</description><content:encoded><![CDATA[<p>Installing Neovim on Debian-based distributions: Ubuntu, Mint, etc. is easy!</p>
<h2 id="install-neovim-on-ubuntu">Install Neovim on Ubuntu</h2>
<p>Neovim is available through the Debian package manager. Simply execute the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo apt install neovim</span></span></code></pre></div><h2 id="install-neovim-using-ppa">Install Neovim using PPA</h2>
<p>The default Neovim version bundled with <code>apt</code> is normally outdated. To install a newer version, a PPA (Personal Package Archive) must be used.</p>
<p><strong>NOTE</strong>: The Neovim PPAs are <em>not</em> maintained by the Neovim team</p>
<h3 id="neovim-stable-ppa">Neovim stable PPA</h3>
<p>To install the latest stable Neovim version using <code>apt</code>, add the following PPA:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo add-apt-repository ppa:neovim-ppa/stable
</span></span><span class="line"><span class="ln">2</span><span class="cl">sudo apt-get update
</span></span><span class="line"><span class="ln">3</span><span class="cl">sudo apt-get install neovim</span></span></code></pre></div><h3 id="neovim-unstable-ppa">Neovim unstable PPA</h3>
<p>To install the latest unstable Neovim verson using <code>apt</code>, add the following PPA:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo add-apt-repository ppa:neovim-ppa/unstable
</span></span><span class="line"><span class="ln">2</span><span class="cl">sudo apt-get update
</span></span><span class="line"><span class="ln">3</span><span class="cl">sudo apt-get install neovim</span></span></code></pre></div>]]></content:encoded></item><item><title>Find devices on a network in Linux</title><link>https://how.wtf/find-devices-on-a-network-in-linux.html</link><pubDate>Sat, 27 May 2023 22:55:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/find-devices-on-a-network-in-linux.html</guid><description>Finding a device that&amp;rsquo;s connected to a network on Linux is easy with an open source tool named nmap.
What is nmap? nmap is a utility for network discovery and security auditing. It&amp;rsquo;s designed to rapidly scan large networks.
Install nmap nmap is available through most popular package managers.
For Debian-based distributions:
1sudo apt install nmapFor MacOS:
1brew install nmapUsing nmap Firstly, grab your IP address using ifconfig
1ifconfigthe output will contain an IP.</description><content:encoded><![CDATA[<p>Finding a device that&rsquo;s connected to a network on Linux is easy with an open source tool named <code>nmap</code>.</p>
<h2 id="what-is-nmap">What is <code>nmap</code>?</h2>
<p><code>nmap</code> is a utility for network discovery and security auditing. It&rsquo;s designed to rapidly scan large networks.</p>
<h3 id="install-nmap">Install <code>nmap</code></h3>
<p><code>nmap</code> is available through most popular package managers.</p>
<p>For Debian-based distributions:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo apt install nmap</span></span></code></pre></div><p>For MacOS:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">brew install nmap</span></span></code></pre></div><h2 id="using-nmap">Using <code>nmap</code></h2>
<p>Firstly, grab your IP address using <code>ifconfig</code></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">ifconfig</span></span></code></pre></div><p>the output will contain an IP.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">inet 192.168.1.91 netmask 0xffffff00 broadcast 192.168.1.255</span></span></code></pre></div><p><code>nmap</code> is simple to use - simply run the command like the example below:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo nmap -sn 192.168.1.0/24</span></span></code></pre></div><p>The <code>/24</code> is CIDR notation. It&rsquo;s instructing <code>nmap</code> to scan all ip addresses between 192.168.1.0 and 192.168.1.255.</p>
<p>The <code>-sn</code> option is a portless scan of the IP address range.</p>
<p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Nmap scan report for 192.168.1.20
</span></span><span class="line"><span class="ln">2</span><span class="cl">Host is up (0.012s latency).
</span></span><span class="line"><span class="ln">3</span><span class="cl">MAC Address: 00:11:32:C2:7B:96 (Synology Incorporated)</span></span></code></pre></div><p>In my case, I was looking for the IP address of my Synology NAS.</p>
]]></content:encoded></item><item><title>Merge JSON objects using jq</title><link>https://how.wtf/merge-json-objects-using-jq.html</link><pubDate>Fri, 26 May 2023 23:40:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/merge-json-objects-using-jq.html</guid><description>Merging objects in jq is handled natively since 1.14.
Merge objects using jq Given a file named example.json
1{ 2 &amp;#34;key&amp;#34;: &amp;#34;value1&amp;#34;, 3 &amp;#34;anotherKey&amp;#34;: &amp;#34;value2&amp;#34;, 4 &amp;#34;oneMoreKey&amp;#34;: &amp;#34;value3&amp;#34; 5}and another file named example2.json,
1{ 2 &amp;#34;key1&amp;#34;: &amp;#34;value2&amp;#34;, 3 &amp;#34;key2&amp;#34;: &amp;#34;value3&amp;#34;, 4 &amp;#34;key4&amp;#34;: &amp;#34;value4&amp;#34; 5}merging the two objects can be completed using:
1jq -s &amp;#39;.[0] * .[1]&amp;#39; example.json example2.json Output:
1{ 2 &amp;#34;key1&amp;#34;: &amp;#34;value2&amp;#34;, 3 &amp;#34;key2&amp;#34;: &amp;#34;value3&amp;#34;, 4 &amp;#34;key4&amp;#34;: &amp;#34;value4&amp;#34;, 5 &amp;#34;key&amp;#34;: &amp;#34;value1&amp;#34;, 6 &amp;#34;anotherKey&amp;#34;: &amp;#34;value2&amp;#34;, 7 &amp;#34;oneMoreKey&amp;#34;: &amp;#34;value3&amp;#34; 8}</description><content:encoded><![CDATA[<p>Merging objects in <code>jq</code> is handled natively since 1.14.</p>
<h2 id="merge-objects-using-jq">Merge objects using <code>jq</code></h2>
<p>Given a file named <code>example.json</code></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;value1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nt">&#34;anotherKey&#34;</span><span class="p">:</span> <span class="s2">&#34;value2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nt">&#34;oneMoreKey&#34;</span><span class="p">:</span> <span class="s2">&#34;value3&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>and another file named <code>example2.json</code>,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;key1&#34;</span><span class="p">:</span> <span class="s2">&#34;value2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nt">&#34;key2&#34;</span><span class="p">:</span> <span class="s2">&#34;value3&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="nt">&#34;key4&#34;</span><span class="p">:</span> <span class="s2">&#34;value4&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>merging the two objects can be completed using:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">jq -s <span class="s1">&#39;.[0] * .[1]&#39;</span> example.json example2.json </span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;key1&#34;</span><span class="p">:</span> <span class="s2">&#34;value2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nt">&#34;key2&#34;</span><span class="p">:</span> <span class="s2">&#34;value3&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="nt">&#34;key4&#34;</span><span class="p">:</span> <span class="s2">&#34;value4&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">  <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;value1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">  <span class="nt">&#34;anotherKey&#34;</span><span class="p">:</span> <span class="s2">&#34;value2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">  <span class="nt">&#34;oneMoreKey&#34;</span><span class="p">:</span> <span class="s2">&#34;value3&#34;</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Get key names from JSON using jq</title><link>https://how.wtf/get-key-names-from-json-using-jq.html</link><pubDate>Wed, 24 May 2023 23:55:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/get-key-names-from-json-using-jq.html</guid><description>Fetching the key names from a JSON document using jq is simple!
Get key names of JSON using jq Given a file named example.json,
1{ 2 &amp;#34;key&amp;#34;: &amp;#34;value1&amp;#34;, 3 &amp;#34;anotherKey&amp;#34;: &amp;#34;value2&amp;#34;, 4 &amp;#34;oneMoreKey&amp;#34;: &amp;#34;value3&amp;#34; 5}extracting the keys in alphabetical order can be completed using:
1jq &amp;#39;keys&amp;#39; example.jsonOutput:
1[ 2 &amp;#34;anotherKey&amp;#34;, 3 &amp;#34;key&amp;#34;, 4 &amp;#34;oneMoreKey&amp;#34; 5]Get key names of JSON unsorted using jq Taking the previous JSON document example.json, the keys may be returned in order as they appear:</description><content:encoded><![CDATA[<p>Fetching the key names from a JSON document using <code>jq</code> is simple!</p>
<h2 id="get-key-names-of-json-using-jq">Get key names of JSON using <code>jq</code></h2>
<p>Given a file named <code>example.json</code>,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;value1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nt">&#34;anotherKey&#34;</span><span class="p">:</span> <span class="s2">&#34;value2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nt">&#34;oneMoreKey&#34;</span><span class="p">:</span> <span class="s2">&#34;value3&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>extracting the keys in alphabetical order can be completed using:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">jq <span class="s1">&#39;keys&#39;</span> example.json</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">[
</span></span><span class="line"><span class="ln">2</span><span class="cl">  &#34;anotherKey&#34;,
</span></span><span class="line"><span class="ln">3</span><span class="cl">  &#34;key&#34;,
</span></span><span class="line"><span class="ln">4</span><span class="cl">  &#34;oneMoreKey&#34;
</span></span><span class="line"><span class="ln">5</span><span class="cl">]</span></span></code></pre></div><h2 id="get-key-names-of-json-unsorted-using-jq">Get key names of JSON unsorted using <code>jq</code></h2>
<p>Taking the previous JSON document <code>example.json</code>, the keys may be returned in order as they appear:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">jq <span class="s1">&#39;keys_unsorted&#39;</span> example.json</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">[
</span></span><span class="line"><span class="ln">2</span><span class="cl">  &#34;key&#34;,
</span></span><span class="line"><span class="ln">3</span><span class="cl">  &#34;anotherKey&#34;,
</span></span><span class="line"><span class="ln">4</span><span class="cl">  &#34;oneMoreKey&#34;
</span></span><span class="line"><span class="ln">5</span><span class="cl">]</span></span></code></pre></div><h2 id="get-key-names-of-json-in-array-of-objects-using-jq">Get key names of JSON in array of objects using <code>jq</code></h2>
<p>Given a file named <code>example.json</code>,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="nt">&#34;key1&#34;</span><span class="p">:</span> <span class="s2">&#34;value1&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">        <span class="nt">&#34;key2&#34;</span><span class="p">:</span> <span class="s2">&#34;value2&#34;</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="p">]</span></span></span></code></pre></div><p>extracting the keys from the nested array of objects can be completed using:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">jq <span class="s1">&#39;.[] | keys&#39;</span> example.json</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">[
</span></span><span class="line"><span class="ln">2</span><span class="cl">  &#34;key1&#34;
</span></span><span class="line"><span class="ln">3</span><span class="cl">]
</span></span><span class="line"><span class="ln">4</span><span class="cl">[
</span></span><span class="line"><span class="ln">5</span><span class="cl">  &#34;key2&#34;
</span></span><span class="line"><span class="ln">6</span><span class="cl">]</span></span></code></pre></div><p>If the list is required without the brackets:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">jq <span class="s1">&#39;.[] | keys[]&#39;</span> example.json</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">&#34;key1&#34;
</span></span><span class="line"><span class="ln">2</span><span class="cl">&#34;key2&#34;</span></span></code></pre></div><p>Removing the quotes is also an option:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">jq -r <span class="s1">&#39;.[] | keys[]&#39;</span> example.json</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">key1
</span></span><span class="line"><span class="ln">2</span><span class="cl">key2</span></span></code></pre></div>]]></content:encoded></item><item><title>Uninstall AWS CLI</title><link>https://how.wtf/uninstall-aws-cli.html</link><pubDate>Tue, 23 May 2023 23:55:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/uninstall-aws-cli.html</guid><description>The AWS CLI can be installed using several methods: this article attempts to address uninstalling through many of them.
Uninstall AWS CLI using Pip 1pip3 uninstall awscli -y 2# OR 3pip uninstall awscli -yUninstall AWS CLI on Ubuntu 1sudo apt-get remove --auto-remove awscliUninstall AWS CLI using Brew on MacOS 1brew uninstall awscliUninstall AWS CLI using Snap 1sudo snap rm -r aws-cliUninstall AWS CLI with Yum 1sudo yum erase awscliUninstall AWS CLI manually If all else fails, uninstalling manually is a remaining option.</description><content:encoded><![CDATA[<p>The AWS CLI can be installed using several methods: this article attempts to address uninstalling through many of them.</p>
<h2 id="uninstall-aws-cli-using-pip">Uninstall AWS CLI using Pip</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip3 uninstall awscli -y
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"># OR</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">pip uninstall awscli -y</span></span></code></pre></div><h2 id="uninstall-aws-cli-on-ubuntu">Uninstall AWS CLI on Ubuntu</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo apt-get remove --auto-remove awscli</span></span></code></pre></div><h2 id="uninstall-aws-cli-using-brew-on-macos">Uninstall AWS CLI using Brew on MacOS</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">brew uninstall awscli</span></span></code></pre></div><h2 id="uninstall-aws-cli-using-snap">Uninstall AWS CLI using Snap</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo snap rm -r aws-cli</span></span></code></pre></div><h2 id="uninstall-aws-cli-with-yum">Uninstall AWS CLI with Yum</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo yum erase awscli</span></span></code></pre></div><h2 id="uninstall-aws-cli-manually">Uninstall AWS CLI manually</h2>
<p>If all else fails, uninstalling manually is a remaining option. Determine the executing path for the AWS CLI:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">which aws</span></span></code></pre></div><p>Then remove:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo rm -rf <span class="s2">&#34;path from previous command&#34;</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Full scan of DynamoDB table in Python</title><link>https://how.wtf/full-scan-of-dynamodb-table-in-python.html</link><pubDate>Mon, 22 May 2023 21:35:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/full-scan-of-dynamodb-table-in-python.html</guid><description>A full scan of DynamoDB in Python is possible by using the LastEvaluatedKey.
Scanning DynamoDB using LastEvaluatedKey According to the boto3 scan documentation,
If LastEvaluatedKey is present in the response, you need to paginate the result set. For more information, see Paginating the Results in the Amazon DynamoDB Developer Guide.
Simply check for the LastEvaluatedKey in the response using response.get('LastEvaluatedKey').
1import boto3 2 3dynamodb = boto3.resource( 4 &amp;#39;dynamodb&amp;#39;, 5 aws_session_token=token, 6 aws_access_key_id=access_key_id, 7 aws_secret_access_key=secret_access_key, 8 region_name=region 9) 10 11table = dynamodb.</description><content:encoded><![CDATA[<p>A full scan of DynamoDB in Python is possible by using the <code>LastEvaluatedKey</code>.</p>
<h2 id="scanning-dynamodb-using-lastevaluatedkey">Scanning DynamoDB using <code>LastEvaluatedKey</code></h2>
<p>According to the <code>boto3</code> scan <a href="https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/client/scan.html">documentation</a>,</p>
<blockquote>
<p>If LastEvaluatedKey is present in the response, you need to paginate the result set. For more information, see Paginating the Results in the Amazon DynamoDB Developer Guide.</p>
</blockquote>
<p>Simply check for the <code>LastEvaluatedKey</code> in the response using <code>response.get('LastEvaluatedKey')</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">dynamodb</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="s1">&#39;dynamodb&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="n">aws_session_token</span><span class="o">=</span><span class="n">token</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">aws_access_key_id</span><span class="o">=</span><span class="n">access_key_id</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">aws_secret_access_key</span><span class="o">=</span><span class="n">secret_access_key</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">region_name</span><span class="o">=</span><span class="n">region</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">table</span> <span class="o">=</span> <span class="n">dynamodb</span><span class="o">.</span><span class="n">Table</span><span class="p">(</span><span class="s1">&#39;table-name&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">scan</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s1">&#39;Items&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="k">while</span> <span class="n">response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;LastEvaluatedKey&#39;</span><span class="p">)</span> <span class="ow">in</span> <span class="n">response</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="n">response</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">scan</span><span class="p">(</span><span class="n">ExclusiveStartKey</span><span class="o">=</span><span class="n">response</span><span class="p">[</span><span class="s1">&#39;LastEvaluatedKey&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="n">data</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">response</span><span class="p">[</span><span class="s1">&#39;Items&#39;</span><span class="p">])</span></span></span></code></pre></div><p>In the example above, the list of items (<code>data</code>) is extended with each page of items.</p>
]]></content:encoded></item><item><title>Python switch statement example</title><link>https://how.wtf/python-switch-statement-example.html</link><pubDate>Sun, 21 May 2023 23:55:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/python-switch-statement-example.html</guid><description>Python 3.10 added support for the switch keyword.
Implement switch statements in Python The basic syntax for a switch statement is:
1match term: 2 case pattern1: 3 some_action 4 case pattern2: 5 some_other_action 6 case _: 7 default_actionA direct example:
1pizza_size = 0 2match pizza_size: 3 case 0: 4 print(&amp;#34;small pizza&amp;#34;) 5 case 1: 6 print(&amp;#34;medium pizza&amp;#34;) 7 case 2: 8 print(&amp;#34;large pizza&amp;#34;) 9 case _: 10 print(&amp;#34;pizza size is not valid&amp;#34;)Output:</description><content:encoded><![CDATA[<p>Python 3.10 added support for the <code>switch</code> keyword.</p>
<h2 id="implement-switch-statements-in-python">Implement switch statements in Python</h2>
<p>The basic syntax for a switch statement is:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">match</span> <span class="n">term</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="k">case</span> <span class="n">pattern1</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="n">some_action</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="k">case</span> <span class="n">pattern2</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">        <span class="n">some_other_action</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="k">case</span> <span class="n">_</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">        <span class="n">default_action</span></span></span></code></pre></div><p>A direct example:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="n">pizza_size</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="k">match</span> <span class="n">pizza_size</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="k">case</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;small pizza&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="k">case</span> <span class="mi">1</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;medium pizza&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="k">case</span> <span class="mi">2</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;large pizza&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="k">case</span> <span class="n">_</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;pizza size is not valid&#34;</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">small pizza</span></span></code></pre></div><p>In Python, <code>break</code> statements are not required.</p>
]]></content:encoded></item><item><title>Command line recycle bin for Linux</title><link>https://how.wtf/command-line-recycle-bin-for-linux.html</link><pubDate>Sat, 20 May 2023 21:50:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/command-line-recycle-bin-for-linux.html</guid><description>rm is a great tool that gives users enough power to inadvertently erase data. While the data may be recoverable, there is a tool that gives users recycle bin behavior.
What is trash-cli trash-cli is a Python tool that implements the freedesktop.org trash specification. In contrast to rm, users can recover deleted files easily.
Installing trash-cli The recommended way to install trash-cli is through pip (the Python package manager):
1pip3 install trash-cliAlternatively, trash-cli is available on some package managers:</description><content:encoded><![CDATA[<p><code>rm</code> is a great tool that gives users enough power to inadvertently erase data. While the data may be recoverable, there is a tool that gives users recycle bin behavior.</p>
<h2 id="what-is-trash-cli">What is <code>trash-cli</code></h2>
<p><a href="https://github.com/andreafrancia/trash-cli"><code>trash-cli</code> is a Python tool</a> that implements the freedesktop.org trash specification. In contrast to <code>rm</code>, users can recover deleted files easily.</p>
<h2 id="installing-trash-cli">Installing <code>trash-cli</code></h2>
<p>The recommended way to install <code>trash-cli</code> is through <code>pip</code> (the Python package manager):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip3 install trash-cli</span></span></code></pre></div><p>Alternatively, <code>trash-cli</code> is available on some package managers:</p>
<p>Debian/Ubuntu:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo apt install trash-cli</span></span></code></pre></div><p>Arch:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pacman -S trash-cli</span></span></code></pre></div><p>Fedora:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">dnf install trash-cli</span></span></code></pre></div><h2 id="trash-cli-simple-usage"><code>trash-cli</code> simple usage</h2>
<p>Using <code>trash-cli</code> is straightforward.</p>
<p>Trash a file:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">trash path/to/file</span></span></code></pre></div><p>Trash many files:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">trash path/to/file1 path/to/file2</span></span></code></pre></div><p>List trashed files:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">$ trash-list
</span></span><span class="line"><span class="ln">2</span><span class="cl">2023-05-20 21:43:02 /Users/thomas/example2.txt
</span></span><span class="line"><span class="ln">3</span><span class="cl">2023-05-20 21:43:02 /Users/thomas/example1.txt</span></span></code></pre></div><p>Remove specific trashed files:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">$ trash-rm example2.txt
</span></span><span class="line"><span class="ln">2</span><span class="cl">$ trash-list
</span></span><span class="line"><span class="ln">3</span><span class="cl">2023-05-20 21:43:02 /Users/thomas/example1.txt</span></span></code></pre></div><p>Restore trash:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">$ trash-restore
</span></span><span class="line"><span class="ln">2</span><span class="cl">   <span class="m">0</span> 2023-05-20 21:43:02 /Users/thomas/example1.txt
</span></span><span class="line"><span class="ln">3</span><span class="cl">What file to restore <span class="o">[</span>0..0<span class="o">]</span>: <span class="m">0</span></span></span></code></pre></div><p>Lastly, emptying trash:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">$ trash-empty
</span></span><span class="line"><span class="ln">2</span><span class="cl">Would empty the following trash directories:
</span></span><span class="line"><span class="ln">3</span><span class="cl">    - /Users/thomas/.local/share/Trash
</span></span><span class="line"><span class="ln">4</span><span class="cl">Proceed? <span class="o">(</span>y/n<span class="o">)</span> y</span></span></code></pre></div>]]></content:encoded></item><item><title>Check if a variable is set in Bash</title><link>https://how.wtf/check-if-a-variable-is-set-in-bash.html</link><pubDate>Fri, 19 May 2023 22:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/check-if-a-variable-is-set-in-bash.html</guid><description>Checking if a variable is set is easy in Bash; however, there are two common scenarios:
Checking if a variable is empty or unset Checking if a variable is unset Checking if a variable is empty or unset Firstly, a simple test may be used to determine if a variable&amp;rsquo;s value is empty or if it&amp;rsquo;s unset.
1if [[ -z &amp;#34;$var&amp;#34; ]]; then 2 echo &amp;#34;it&amp;#39;s empty or unset&amp;#34; 3fiOR</description><content:encoded><![CDATA[<p>Checking if a variable is set is easy in Bash; however, there are two common scenarios:</p>
<ol>
<li>Checking if a variable is empty or unset</li>
<li>Checking if a variable is unset</li>
</ol>
<h2 id="checking-if-a-variable-is-empty-or-unset">Checking if a variable is empty or unset</h2>
<p>Firstly, a simple test may be used to determine if a variable&rsquo;s value is empty <em>or</em> if it&rsquo;s unset.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">if</span> <span class="o">[[</span> -z <span class="s2">&#34;</span><span class="nv">$var</span><span class="s2">&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;it&#39;s empty or unset&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p><strong>OR</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">var</span><span class="o">=</span><span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">if</span> <span class="o">[[</span> -z <span class="s2">&#34;</span><span class="nv">$var</span><span class="s2">&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;it&#39;s empty or unset&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">it&#39;s empty or unset</span></span></code></pre></div><p>The <code>-z</code> tests if the string length is zero.</p>
<h2 id="checking-if-a-variable-is-unset">Checking if a variable is unset</h2>
<p>Checking if a variable is unset requires a different implementation.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">if</span> <span class="o">[[</span> -z <span class="s2">&#34;</span><span class="si">${</span><span class="nv">var</span><span class="p">+set</span><span class="si">}</span><span class="s2">&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;it&#39;s unset&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">it&#39;s unset</span></span></code></pre></div><p>However, if the <code>var</code> value is set to an <strong>empty</strong> value:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">var</span><span class="o">=</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">if</span> <span class="o">[[</span> -z <span class="s2">&#34;</span><span class="si">${</span><span class="nv">var</span><span class="p">+set</span><span class="si">}</span><span class="s2">&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;it&#39;s unset&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p><strong>OR</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">var</span><span class="o">=</span><span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">if</span> <span class="o">[[</span> -z <span class="s2">&#34;</span><span class="si">${</span><span class="nv">var</span><span class="p">+set</span><span class="si">}</span><span class="s2">&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;it&#39;s unset&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p>the output will not print anything.</p>
<p>The <code>${var+set}</code> works because of <a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02">parameter expansion</a>:</p>
<blockquote>
<p>If parameter is unset or null, null shall be substituted; otherwise, the expansion of word (or an empty string if word is omitted) shall be substituted.</p>
</blockquote>
]]></content:encoded></item><item><title>Count number of files in Linux</title><link>https://how.wtf/count-number-of-files-in-linux.html</link><pubDate>Thu, 18 May 2023 22:20:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/count-number-of-files-in-linux.html</guid><description>Counting the number of files in Linux is made possible using the wc command!
Count number of files and directories in current directory Using wc in combination with ls, the number of files and directories in the current directory can be displayed:
1ls | wc -lOutput:
1~/how.wtf/content/post$ ls | wc -l 2120To include hidden files and directories, use the -A ls option.
1ls -A | wc -lCount number of files in current directory Using find and wc, the number of files in the current directory can be displayed:</description><content:encoded><![CDATA[<p>Counting the number of files in Linux is made possible using the <code>wc</code> command!</p>
<h2 id="count-number-of-files-and-directories-in-current-directory">Count number of files and directories in current directory</h2>
<p>Using <code>wc</code> in combination with <code>ls</code>, the number of files and directories in the <strong>current</strong> directory can be displayed:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">ls <span class="p">|</span> wc -l</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">~/how.wtf/content/post$ ls <span class="p">|</span> wc -l
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="m">120</span></span></span></code></pre></div><p>To include hidden files and directories, use the <code>-A</code> <code>ls</code> option.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">ls -A <span class="p">|</span> wc -l</span></span></code></pre></div><h2 id="count-number-of-files-in-current-directory">Count number of files in current directory</h2>
<p>Using <code>find</code> and <code>wc</code>, the number of files in the current directory can be displayed:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">find . -maxdepth <span class="m">1</span> -type f <span class="p">|</span> wc -l</span></span></code></pre></div><p><code>-maxdepth</code> ensures that subdirectories are not counted.</p>
<h2 id="count-number-of-files-in-current-directory-and-subdirectories">Count number of files in current directory and subdirectories</h2>
<p>Using <code>find</code> and <code>wc</code>, the number of files <strong>excluding</strong> directories can be displayed:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">find . -type f <span class="p">|</span> wc -l</span></span></code></pre></div>]]></content:encoded></item><item><title>Great alternatives to man pages everyone needs</title><link>https://how.wtf/great-alternatives-to-man-pages-everyone-needs.html</link><pubDate>Wed, 17 May 2023 20:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/great-alternatives-to-man-pages-everyone-needs.html</guid><description>man (manual documentation pages) cannot be replaced; however, there are modern CLI tools that provide simplified experiences.
tldr pages tldr is a community-curated collection of simplified man pages. As the name (too long; didn&amp;rsquo;t read) implies, the focus is providing straightforward examples that demonstrate tool usage.
Installing tldr On MacOS,
1brew install tldrUsing the NodeJS client,
1npm -g tldrUsing the Python client,
1pip3 install tldrUsing `tldr Using tldr is straightforward:</description><content:encoded><![CDATA[<p><code>man</code> (manual documentation pages) cannot be replaced; however, there are modern CLI tools that provide simplified experiences.</p>
<h2 id="tldr-pages"><code>tldr</code> pages</h2>
<p><a href="https://tldr.sh"><code>tldr</code></a> is a community-curated collection of simplified man pages. As the name (too long; didn&rsquo;t read) implies, the focus is providing straightforward examples that demonstrate tool usage.</p>
<h3 id="installing-tldr">Installing <code>tldr</code></h3>
<p>On MacOS,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">brew install tldr</span></span></code></pre></div><p>Using the NodeJS client,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">npm -g tldr</span></span></code></pre></div><p>Using the Python client,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip3 install tldr</span></span></code></pre></div><h3 id="using-tldr">Using `tldr</h3>
<p>Using <code>tldr</code> is straightforward:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">tldr &lt;some <span class="nb">command</span> name&gt;</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln"> 1</span><span class="cl">$ tldr tldr
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">tldr
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">Display simple <span class="nb">help</span> pages <span class="k">for</span> command-line tools from the tldr-pages project.
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">More information: &lt;https://tldr.sh&gt;.
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">- Print the tldr page <span class="k">for</span> a specific <span class="nb">command</span> <span class="o">(</span>hint: this is how you got here!<span class="o">)</span>:
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    tldr <span class="nb">command</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">- Print the tldr page <span class="k">for</span> a specific subcommand:
</span></span><span class="line"><span class="ln">12</span><span class="cl">    tldr command-subcommand
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl">- Print the tldr page <span class="k">for</span> a <span class="nb">command</span> <span class="k">for</span> a specific <span class="o">[</span>p<span class="o">]</span>latform:
</span></span><span class="line"><span class="ln">15</span><span class="cl">    tldr -p android<span class="p">|</span>linux<span class="p">|</span>osx<span class="p">|</span>sunos<span class="p">|</span>windows <span class="nb">command</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl">- <span class="o">[</span>u<span class="o">]</span>pdate the <span class="nb">local</span> cache of tldr pages:
</span></span><span class="line"><span class="ln">18</span><span class="cl">    tldr -u</span></span></code></pre></div><h2 id="cheat"><code>cheat</code></h2>
<p><a href="https://github.com/cheat/cheat"><code>cheat</code></a> is a tool used exclusively for supplying command usage. The intention is to provide a &ldquo;cheatsheet&rdquo; for *nix system administrators to quickly view command usage <em>and</em> contribute their own.</p>
<h3 id="installing-cheat">Installing <code>cheat</code></h3>
<p>On MacOS,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">brew install cheat</span></span></code></pre></div><p>Using GO,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">go install github.com/cheat/cheat/cmd/cheat@latest</span></span></code></pre></div><p>To find more installation examples, visit the document <a href="https://github.com/cheat/cheat/blob/master/INSTALLING.md">here</a>.</p>
<h3 id="using-cheat">Using <code>cheat</code></h3>
<p>Using <code>cheat</code> is simple:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">cheat &lt;some <span class="nb">command</span> name&gt;</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln"> 1</span><span class="cl">$ cheat jq
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"># To pretty print the json:</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">jq <span class="s2">&#34;.&#34;</span> &lt; filename.json
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"># To access the value at key &#34;foo&#34;:</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">jq <span class="s1">&#39;.foo&#39;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"># To access first list item:</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">jq <span class="s1">&#39;.[0]&#39;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"># to slice and dice:</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">jq <span class="s1">&#39;.[2:4]&#39;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">jq <span class="s1">&#39;.[:3]&#39;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">jq <span class="s1">&#39;.[-2:]&#39;</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="c1"># to extract all keys from json:</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">jq keys
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="c1"># to sort by a key:</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">jq <span class="s1">&#39;.foo | sort_by(.bar)&#39;</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="c1"># to count elements:</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">jq <span class="s1">&#39;.foo | length&#39;</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="c1"># print only selected fields:</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">jq <span class="s1">&#39;.foo[] | {field_1,field_2}&#39;</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">
</span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="c1"># print selected fields as text instead of json:</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">jq <span class="s1">&#39;.foo[] | {field_1,field_2} | join(&#34; &#34;)&#39;</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="c1"># only print records where given field matches a value</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">jq <span class="s1">&#39;.foo[] | select(.field_1 == &#34;value_1&#34;)&#39;</span></span></span></code></pre></div>]]></content:encoded></item><item><title>AWS SigV4 requests with curl</title><link>https://how.wtf/aws-sigv4-requests-with-curl.html</link><pubDate>Tue, 16 May 2023 22:35:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/aws-sigv4-requests-with-curl.html</guid><description>Curl handles AWS Signature Version 4 API requests natively.
How to create AWS Signature Version 4 requests using curl If an API Gateway is configured to use AWS IAM authorization, curl provides a seamless integration for HTTP requests.
1curl &amp;#34;$url&amp;#34; \ 2 --user &amp;#34;$AWS_ACCESS_KEY_ID&amp;#34;:&amp;#34;$AWS_SECRET_ACCESS_KEY&amp;#34; \ 3 --aws-sigv4 &amp;#34;aws:amz:us-east-1:execute-api&amp;#34;In the example, the $url links to a custom domain that points to an API Gateway.
The --user argument is given the $AWS_ACCESS_KEY_ID and $AWS_SECRET_ACCESS_KEY that links to the AWS IAM user.</description><content:encoded><![CDATA[<p>Curl handles AWS Signature Version 4 API requests natively.</p>
<h2 id="how-to-create-aws-signature-version-4-requests-using-curl">How to create AWS Signature Version 4 requests using <code>curl</code></h2>
<p>If an API Gateway is configured to use AWS IAM authorization, <code>curl</code> provides a seamless integration for HTTP requests.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl <span class="s2">&#34;</span><span class="nv">$url</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	--user <span class="s2">&#34;</span><span class="nv">$AWS_ACCESS_KEY_ID</span><span class="s2">&#34;</span>:<span class="s2">&#34;</span><span class="nv">$AWS_SECRET_ACCESS_KEY</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	--aws-sigv4 <span class="s2">&#34;aws:amz:us-east-1:execute-api&#34;</span></span></span></code></pre></div><p>In the example, the <code>$url</code> links to a custom domain that points to an API Gateway.</p>
<p>The <a href="https://curl.se/docs/manpage.html#-u"><code>--user</code> argument</a> is given the <code>$AWS_ACCESS_KEY_ID</code> and <code>$AWS_SECRET_ACCESS_KEY</code> that links to the AWS IAM user.</p>
<p>The AWS service for invoking an API Gateway is <code>execute-api</code>. For <code>curl</code>, the full provider string is required:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">--aws-sigv4 <span class="s2">&#34;aws:amz:region:service&#34;</span></span></span></code></pre></div><h2 id="how-to-use-session-token-with-aws-sigv4-curl">How to use session token with AWS SigV4 curl</h2>
<p>In addition to using IAM user credentials, you can optionally specify a session token using the header of <code>x-amz-security-token</code>. This is useful for temporary access through role assumptions.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl <span class="s2">&#34;</span><span class="nv">$url</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	--user <span class="s2">&#34;</span><span class="nv">$AWS_ACCESS_KEY_ID</span><span class="s2">&#34;</span>:<span class="s2">&#34;</span><span class="nv">$AWS_SECRET_ACCESS_KEY</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	-H <span class="s2">&#34;x-amz-security-token: </span><span class="nv">$AWS_SESSION_TOKEN</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>	--aws-sigv4 <span class="s2">&#34;aws:amz:us-east-1:execute-api&#34;</span></span></span></code></pre></div>]]></content:encoded></item><item><title>How to use curl for HTTP requests</title><link>https://how.wtf/how-to-use-curl-for-http-requests.html</link><pubDate>Mon, 15 May 2023 23:40:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-use-curl-for-http-requests.html</guid><description>Curl is a command line utility that was created in 1998 for transferring data using URLs. Fundamentally, curl allows users to create network requests to a server by specifying a location in the form of a URL and adding optional data.
curl (short for &amp;ldquo;Client URL&amp;rdquo;) is powered by libcurl – a portable client-side URL transfer library written in C.
Why use the curl command? Common use cases for curl include:</description><content:encoded><![CDATA[<p>Curl is a command line utility that was created in 1998 for transferring data using URLs. Fundamentally, <code>curl</code> allows users to create network requests to a server by specifying a location in the form of a URL and adding optional data.</p>
<p><code>curl</code> (short for &ldquo;Client URL&rdquo;) is powered by libcurl – a portable client-side URL transfer library written in C.</p>
<h2 id="why-use-the-curl-command">Why use the curl command?</h2>
<p>Common use cases for <code>curl</code> include:</p>
<ul>
<li>It can download and upload files</li>
<li>It has great error logging</li>
<li>It allows for quick endpoint testing</li>
<li>It provides granular details which aides debugging</li>
<li>It is portable and works with most operating systems</li>
<li>It is an actively managed open-source tool that is battled tested with a large user base</li>
</ul>
<h2 id="base-curl-command-usage">Base <code>curl</code> command usage</h2>
<p>The basic syntax for a <code>curl</code> command is:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">curl [OPTIONS] [URL]</span></span></code></pre></div><h2 id="http-requests-using-curl">HTTP Requests using <code>curl</code></h2>
<p>Curl provides native support for all HTTP requests methods: <code>GET</code>, <code>POST</code>, <code>PUT</code>, <code>PATCH</code>, <code>DELETE</code>, etc.</p>
<p>For all the following examples, the <a href="https://jsonplaceholder.typicode.com/">JSONPlaceholder API</a> will be used.</p>
<h3 id="make-a-get-request">Make a <code>GET</code> request</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div><p>OR</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X GET https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div><p><strong>NOTE</strong>: The <code>-X</code> flag is a shorthand for <code>--request</code>. It’s not required because the default value is <code>GET</code>.</p>
<p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;userId&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;sunt aut facere repellat provident occaecati excepturi optio reprehenderit&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">  <span class="nt">&#34;body&#34;</span><span class="p">:</span> <span class="s2">&#34;quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto&#34;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>In addition, an optional <code>Accept</code> header may be used:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	-H <span class="s2">&#34;Accept: application/json&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div><h3 id="make-a-post-request">Make a <code>POST</code> request</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X POST -d <span class="s2">&#34;title=foo&amp;body=test&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts</span></span></code></pre></div><p>In the example above, a new post titled <code>foo</code> with a body of <code>test</code> is created.</p>
<p>The default <code>Content-Type</code> of the request is: <code>application/x-www-form-urlencoded</code></p>
<p>If a <code>JSON</code> payload is required, then the <code>Content-Type</code> header can be explicitly included:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X POST <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	-H <span class="s1">&#39;Content-Type: application/json&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	-d <span class="s1">&#39;{&#34;title&#34;:&#34;foo&#34;,&#34;body&#34;:&#34;bar&#34;}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts</span></span></code></pre></div><p>Alternatively, a file may be specified (<code>post.json</code>):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;foo&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nt">&#34;body&#34;</span><span class="p">:</span> <span class="s2">&#34;bar&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X POST <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	-H <span class="s1">&#39;Content-Type: application/json&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	-d @post.json <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;foo&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nt">&#34;body&#34;</span><span class="p">:</span> <span class="s2">&#34;bar&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">101</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h3 id="make-a-put-request">Make a <code>PUT</code> request</h3>
<p>Similarly to <code>POST</code>, a <code>PUT</code> can use all the same options:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X PUT -d <span class="s2">&#34;title=foo&amp;body=test&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div><p>In the example above, post 1 is re-titled to <code>foo</code> and given a new body of <code>test</code>.</p>
<p>The default <code>Content-Type</code> of the request is: <code>application/x-www-form-urlencoded</code></p>
<p>If a <code>JSON</code> payload is required, then the <code>Content-Type</code> header can be explicitly included:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X PUT <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	-H <span class="s1">&#39;Content-Type: application/json&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	-d <span class="s1">&#39;{&#34;title&#34;:&#34;foo&#34;,&#34;body&#34;:&#34;bar&#34;}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div><p>Alternatively, a file may be specified (<code>post.json</code>):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;foo&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nt">&#34;body&#34;</span><span class="p">:</span> <span class="s2">&#34;bar&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X PUT <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	-H <span class="s1">&#39;Content-Type: application/json&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	-d @post.json <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;foo&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nt">&#34;body&#34;</span><span class="p">:</span> <span class="s2">&#34;bar&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h3 id="make-a-patch-request">Make a <code>PATCH</code> request</h3>
<p>Similarly to <code>POST</code> and <code>PUT</code>, a <code>PATCH</code> can use all the same options:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X PATCH -d <span class="s2">&#34;title=foo2&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div><p>In the example above, post 1 is re-titled to <code>foo2</code>.</p>
<p>The default <code>Content-Type</code> of the request is: <code>application/x-www-form-urlencoded</code></p>
<p>If a <code>JSON</code> payload is required, then the <code>Content-Type</code> header can be explicitly included:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X PATCH <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	-H <span class="s1">&#39;Content-Type: application/json&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	-d <span class="s1">&#39;{&#34;title&#34;:&#34;foo2&#34;}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div><p>Alternatively, a file may be specified (<code>post.json</code>):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;foo2&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X PATCH <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	-H <span class="s1">&#39;Content-Type: application/json&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	-d @post.json <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;userId&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;foo2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">  <span class="nt">&#34;body&#34;</span><span class="p">:</span> <span class="s2">&#34;quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto&#34;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h3 id="make-a-delete-request">Make a <code>DELETE</code> request</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X DELETE https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{}</span></span></span></code></pre></div><h2 id="conclusion">Conclusion</h2>
<p><code>curl</code> is a powerful and versatile command line utility that offers a wide range of supporting features: multiple protocols, multiple options, data types, etc. HTTP requests are simple and reliable.</p>
]]></content:encoded></item><item><title>How to make a PATCH request using curl</title><link>https://how.wtf/how-to-make-a-patch-request-using-curl.html</link><pubDate>Sun, 14 May 2023 18:20:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-make-a-patch-request-using-curl.html</guid><description>For more information about curl, checkout the &amp;ldquo;What is curl&amp;rdquo; article. This article will discuss how to interact with an API using PATCH requests through curl.
Make a simple PATCH request The basic syntax for sending a PATCH request using curl is:
1curl -X PATCH https://example.comThe -X argument accepts an HTTP method for interacting with the server. For HTTP, valid values include: GET (default), POST, PUT, DELETE, etc.
NOTE: The -X flag is a shorthand for --request.</description><content:encoded><![CDATA[<p>For more information about <code>curl</code>, checkout the <a href="https://how.wtf/what-is-curl.html">&ldquo;What is curl&rdquo;</a> article. This article will discuss how to interact with an API using <code>PATCH</code> requests through curl.</p>
<h2 id="make-a-simple-patch-request">Make a simple <code>PATCH</code> request</h2>
<p>The basic syntax for sending a <code>PATCH</code> request using curl is:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X PATCH https://example.com</span></span></code></pre></div><p>The <code>-X</code> argument accepts an HTTP method for interacting with the server. For HTTP, valid values include: <code>GET</code> (default), <code>POST</code>, <code>PUT</code>, <code>DELETE</code>, etc.</p>
<p><strong>NOTE</strong>: The <code>-X</code> flag is a shorthand for <code>--request</code>. Either can be used.</p>
<h2 id="make-a-patch-request-with-data">Make a <code>PATCH</code> request with data</h2>
<p>Users can send data along with a <code>PATCH</code> request.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X PATCH -d <span class="s2">&#34;title=bar&amp;body=foo&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div><p>In the example above, a <code>PATCH</code> request is sent to the <a href="https://jsonplaceholder.typicode.com/">JSONPlaceholder API</a> to update an existing post (<code>1</code>) with a <code>title</code> of <code>bar</code> and a body of <code>foo</code>.</p>
<p>The default <code>Content-Type</code> is <code>application/x-www-form-urlencoded</code>.</p>
<p><strong>NOTE</strong>: The <code>-d</code> flag is a shorthand for <code>--data</code>. Either can be used.</p>
<h2 id="make-a-patch-request-with-json-body">Make a <code>PATCH</code> request with JSON body</h2>
<p>Users may optionally send <code>JSON</code> data in their request payloads.</p>
<h3 id="making-a-patch-request-with-json">Making a <code>PATCH</code> request with JSON</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X PATCH <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	-H <span class="s1">&#39;Content-Type: application/json&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	-d <span class="s1">&#39;{&#34;title&#34;:&#34;bar&#34;,&#34;body&#34;:&#34;foo&#34;}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div><p>In the example above, a <code>PATCH</code> request is sent to the <a href="https://jsonplaceholder.typicode.com/">JSONPlaceholder API</a> to update an existing post (<code>1</code>) with a <code>title</code> of <code>bar</code> and a body of <code>foo</code>.</p>
<p>The <code>-H</code> flag accepts a <code>Key: value</code> string that represents a header. In the above case, it sets the content type: <code>Content-Type: application/json</code>.</p>
<p><strong>NOTE</strong>: The <code>-H</code> flag is a shorthand for <code>--header</code>. Either can be used.</p>
<h3 id="making-a-patch-request-with-a-json-file">Making a <code>PATCH</code> request with a JSON file</h3>
<p>In addition to text, the <code>-d</code> parameter accepts a file using the syntax <code>@filename</code>.</p>
<p>If a file is named <code>post.json</code></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span> 
</span></span><span class="line"><span class="ln">2</span><span class="cl">	<span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;bar&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">	<span class="nt">&#34;body&#34;</span><span class="p">:</span> <span class="s2">&#34;foo&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>then curl can pass on its contents:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X PATCH <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	-H <span class="s1">&#39;Content-Type: application/json&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	-d @post.json <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div>]]></content:encoded></item><item><title>How to make a DELETE request using curl</title><link>https://how.wtf/how-to-make-a-delete-request-using-curl.html</link><pubDate>Sun, 14 May 2023 10:15:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-make-a-delete-request-using-curl.html</guid><description>For more information about curl, checkout the &amp;ldquo;What is curl&amp;rdquo; article. This article will discuss how to interact with an API using DELETE requests through curl.
Make a simple DELETE request The basic syntax for sending a DELETE request using curl is:
1curl -X DELETE https://example.comNOTE: The -X flag is a shorthand for --request.
DELETE request example 1curl -X DELETE \ 2 https://jsonplaceholder.typicode.com/posts/1In the example above, a DELETE request is sent to the JSONPlaceholder API to delete a post with an id of 1.</description><content:encoded><![CDATA[<p>For more information about <code>curl</code>, checkout the <a href="https://how.wtf/what-is-curl.html">&ldquo;What is curl&rdquo;</a> article. This article will discuss how to interact with an API using <code>DELETE</code> requests through curl.</p>
<h2 id="make-a-simple-delete-request">Make a simple <code>DELETE</code> request</h2>
<p>The basic syntax for sending a <code>DELETE</code> request using curl is:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X DELETE https://example.com</span></span></code></pre></div><p><strong>NOTE</strong>: The <code>-X</code> flag is a shorthand for <code>--request</code>.</p>
<h2 id="delete-request-example"><code>DELETE</code> request example</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X DELETE <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div><p>In the example above, a <code>DELETE</code> request is sent to the <a href="https://jsonplaceholder.typicode.com/">JSONPlaceholder API</a> to delete a post with an id of <code>1</code>.</p>
]]></content:encoded></item><item><title>How to make a PUT request using curl</title><link>https://how.wtf/how-to-make-a-put-request-using-curl.html</link><pubDate>Sat, 13 May 2023 16:10:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-make-a-put-request-using-curl.html</guid><description>For more information about curl, checkout the &amp;ldquo;What is curl&amp;rdquo; article. This article will discuss how to interact with an API using PUT requests through curl.
Make a simple PUT request The basic syntax for sending a PUT request using curl is:
1curl -X PUT https://example.comThe -X argument accepts an HTTP method for interacting with the server. For HTTP, valid values include: GET (default), POST, PUT, DELETE, etc.
NOTE: The -X flag is a shorthand for --request.</description><content:encoded><![CDATA[<p>For more information about <code>curl</code>, checkout the <a href="https://how.wtf/what-is-curl.html">&ldquo;What is curl&rdquo;</a> article. This article will discuss how to interact with an API using <code>PUT</code> requests through curl.</p>
<h2 id="make-a-simple-put-request">Make a simple <code>PUT</code> request</h2>
<p>The basic syntax for sending a <code>PUT</code> request using curl is:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X PUT https://example.com</span></span></code></pre></div><p>The <code>-X</code> argument accepts an HTTP method for interacting with the server. For HTTP, valid values include: <code>GET</code> (default), <code>POST</code>, <code>PUT</code>, <code>DELETE</code>, etc.</p>
<p><strong>NOTE</strong>: The <code>-X</code> flag is a shorthand for <code>--request</code>. Either can be used.</p>
<h2 id="make-a-put-request-with-data">Make a <code>PUT</code> request with data</h2>
<p>Users can send data along with a <code>PUT</code> request.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X PUT -d <span class="s2">&#34;title=newtitle&amp;body=newbody&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div><p>In the example above, a <code>PUT</code> request is sent to the <a href="https://jsonplaceholder.typicode.com/">JSONPlaceholder API</a> to update an existing post (<code>1</code>) with a <code>title</code> of <code>newtitle</code> and a body of <code>newbody</code>.</p>
<p>The default <code>Content-Type</code> is <code>application/x-www-form-urlencoded</code>.</p>
<p><strong>NOTE</strong>: The <code>-d</code> flag is a shorthand for <code>--data</code>. Either can be used.</p>
<h2 id="make-a-put-request-with-json-body">Make a <code>PUT</code> request with JSON body</h2>
<p>Users may optionally send <code>JSON</code> data in their request payloads.</p>
<h3 id="making-a-put-request-with-json">Making a <code>PUT</code> request with JSON</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X PUT <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	-H <span class="s1">&#39;Content-Type: application/json&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	-d <span class="s1">&#39;{&#34;title&#34;:&#34;newtitle&#34;,&#34;body&#34;:&#34;newbar&#34;}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div><p>In the example above, a <code>PUT</code> request is sent to the <a href="https://jsonplaceholder.typicode.com/">JSONPlaceholder API</a> to update an existing post (<code>1</code>) with a <code>title</code> of <code>newtitle</code> and a body of <code>newbody</code>.</p>
<p>The <code>-H</code> flag accepts a <code>Key: value</code> string that represents a header. In the above case, it sets the content type: <code>Content-Type: application/json</code>.</p>
<p><strong>NOTE</strong>: The <code>-H</code> flag is a shorthand for <code>--header</code>. Either can be used.</p>
<h3 id="making-a-put-request-with-a-json-file">Making a <code>PUT</code> request with a JSON file</h3>
<p>In addition to text, the <code>-d</code> parameter accepts a file using the syntax <code>@filename</code>.</p>
<p>If a file is named <code>post.json</code></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span> 
</span></span><span class="line"><span class="ln">2</span><span class="cl">	<span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;newtitle&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">	<span class="nt">&#34;body&#34;</span><span class="p">:</span> <span class="s2">&#34;newbody&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>then curl can pass on its contents:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X PUT <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	-H <span class="s1">&#39;Content-Type: application/json&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	-d @post.json <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div>]]></content:encoded></item><item><title>How to make a GET request using curl</title><link>https://how.wtf/how-to-make-a-get-request-using-curl.html</link><pubDate>Sat, 13 May 2023 11:50:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-make-a-get-request-using-curl.html</guid><description>For more information about curl, checkout the &amp;ldquo;What is curl&amp;rdquo; article. This article will discuss how to interact with an API using GET requests through curl.
Make a simple GET request The basic syntax for sending a GET request using curl is:
1curl https://example.comOR
1curl -X GET https://example.comNOTE: The -X flag is a shorthand for --request. It&amp;rsquo;s not required because the default value is GET.
Make a GET request for JSON data If the server responds differently per the Accept header, users can specify for it to accept JSON data.</description><content:encoded><![CDATA[<p>For more information about <code>curl</code>, checkout the <a href="https://how.wtf/what-is-curl.html">&ldquo;What is curl&rdquo;</a> article. This article will discuss how to interact with an API using <code>GET</code> requests through curl.</p>
<h2 id="make-a-simple-get-request">Make a simple <code>GET</code> request</h2>
<p>The basic syntax for sending a <code>GET</code> request using curl is:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl https://example.com</span></span></code></pre></div><p>OR</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X GET https://example.com</span></span></code></pre></div><p><strong>NOTE</strong>: The <code>-X</code> flag is a shorthand for <code>--request</code>. It&rsquo;s not required because the default value is <code>GET</code>.</p>
<h2 id="make-a-get-request-for-json-data">Make a <code>GET</code> request for JSON data</h2>
<p>If the server responds differently per the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept"><code>Accept</code> header</a>, users can specify for it to accept JSON data.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	-H <span class="s2">&#34;Accept: application/json&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts/1</span></span></code></pre></div><p>In the example above, a <code>GET</code> request is sent to the <a href="https://jsonplaceholder.typicode.com/">JSONPlaceholder API</a> to fetch a post with an id of <code>1</code> with an <code>Accept</code> header of <code>application/json</code>.</p>
<p>The  <code>-H</code>  flag accepts a  <code>Key: value</code>  string that represents a header.</p>
<p><strong>NOTE</strong>: The  <code>-H</code>  flag is a shorthand for  <code>--header</code>. Either can be used.</p>
<p>This same technique may be used for other <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types">mime types</a>:</p>
<ul>
<li><code>application/xml</code></li>
<li><code>text/html</code></li>
<li><code>img/png</code></li>
<li>etc.</li>
</ul>
]]></content:encoded></item><item><title>How to make a POST request using curl</title><link>https://how.wtf/how-to-make-a-post-request-using-curl.html</link><pubDate>Sat, 13 May 2023 10:25:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-make-a-post-request-using-curl.html</guid><description>For more information about curl, checkout the &amp;ldquo;What is curl&amp;rdquo; article. This article will discuss how to interact with an API using POST requests through curl.
Make a simple POST request The basic syntax for sending a POST request using curl is:
1curl -X POST https://example.comThe -X argument accepts an HTTP method for interacting with the server. For HTTP, valid values include: GET (default), POST, PUT, DELETE, etc.
NOTE: The -X flag is a shorthand for --request.</description><content:encoded><![CDATA[<p>For more information about <code>curl</code>, checkout the <a href="https://how.wtf/what-is-curl.html">&ldquo;What is curl&rdquo;</a> article. This article will discuss how to interact with an API using <code>POST</code> requests through curl.</p>
<h2 id="make-a-simple-post-request">Make a simple <code>POST</code> request</h2>
<p>The basic syntax for sending a <code>POST</code> request using curl is:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X POST https://example.com</span></span></code></pre></div><p>The <code>-X</code> argument accepts an HTTP method for interacting with the server. For HTTP, valid values include: <code>GET</code> (default), <code>POST</code>, <code>PUT</code>, <code>DELETE</code>, etc.</p>
<p><strong>NOTE</strong>: The <code>-X</code> flag is a shorthand for <code>--request</code>. Either can be used.</p>
<h2 id="make-a-post-request-with-data">Make a <code>POST</code> request with data</h2>
<p>Users can send data along with a <code>POST</code> request.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X POST -d <span class="s2">&#34;title=foo&amp;body=test&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts</span></span></code></pre></div><p>In the example above, a <code>POST</code> request is sent to the <a href="https://jsonplaceholder.typicode.com/">JSONPlaceholder API</a> to create a new post with a <code>title</code> of <code>foo</code> and a body of <code>test</code>.</p>
<p>The default <code>Content-Type</code> is <code>application/x-www-form-urlencoded</code>.</p>
<p><strong>NOTE</strong>: The <code>-d</code> flag is a shorthand for <code>--data</code>. Either can be used.</p>
<h2 id="make-a-post-request-with-json-body">Make a <code>POST</code> request with JSON body</h2>
<p>Users may optionally send <code>JSON</code> data in their request payloads.</p>
<h3 id="making-a-post-request-with-json">Making a <code>POST</code> request with JSON</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X POST <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	-H <span class="s1">&#39;Content-Type: application/json&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	-d <span class="s1">&#39;{&#34;title&#34;:&#34;foo&#34;,&#34;body&#34;:&#34;bar&#34;}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts</span></span></code></pre></div><p>In the example above, a <code>POST</code> request is sent to the <a href="https://jsonplaceholder.typicode.com/">JSONPlaceholder API</a> to create a new post with a <code>title</code> of <code>foo</code> and a body of <code>bar</code>.</p>
<p>The <code>-H</code> flag accepts a <code>Key: value</code> string that represents a header. In the above case, it sets the content type: <code>Content-Type: application/json</code>.</p>
<p><strong>NOTE</strong>: The <code>-H</code> flag is a shorthand for <code>--header</code>. Either can be used.</p>
<h3 id="making-a-post-request-with-a-json-file">Making a <code>POST</code> request with a JSON file</h3>
<p>In addition to text, the <code>-d</code> parameter accepts a file using the syntax <code>@filename</code>.</p>
<p>If a file is named <code>post.json</code></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span> 
</span></span><span class="line"><span class="ln">2</span><span class="cl">	<span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;foo&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">	<span class="nt">&#34;body&#34;</span><span class="p">:</span> <span class="s2">&#34;test&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>then curl can pass on its contents:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -X POST <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	-H <span class="s1">&#39;Content-Type: application/json&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	-d @post.json <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>	https://jsonplaceholder.typicode.com/posts</span></span></code></pre></div>]]></content:encoded></item><item><title>What is the curl command</title><link>https://how.wtf/what-is-the-curl-command.html</link><pubDate>Fri, 12 May 2023 00:55:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/what-is-the-curl-command.html</guid><description>Curl is a command line utility that was created in 1998 for transferring data using URLs. Fundamentally, curl allows users to create network requests to a server by specifying a location in the form of a URL and adding optional data.
curl (short for &amp;ldquo;Client URL&amp;rdquo;) is powered by libcurl – a portable client-side URL transfer library written in C.
Why use the curl command? Common use cases for curl include:</description><content:encoded><![CDATA[<p>Curl is a command line utility that was created in 1998 for transferring data using URLs. Fundamentally, <code>curl</code> allows users to create network requests to a server by specifying a location in the form of a URL and adding optional data.</p>
<p><code>curl</code> (short for &ldquo;Client URL&rdquo;) is powered by libcurl – a portable client-side URL transfer library written in C.</p>
<h2 id="why-use-the-curl-command">Why use the curl command?</h2>
<p>Common use cases for <code>curl</code> include:</p>
<ul>
<li>It can download and upload files</li>
<li>It has great error logging</li>
<li>It allows for quick endpoint testing</li>
<li>It provides granular details which aides debugging</li>
<li>It is portable and works with most operating systems</li>
<li>It is an actively managed open-source tool that is battled tested with a large user base</li>
</ul>
<h2 id="base-curl-command-usage">Base <code>curl</code> command usage</h2>
<p>The basic syntax for a <code>curl</code> command is:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">curl [OPTIONS] [URL]</span></span></code></pre></div><h3 id="perform-a-get-request">Perform a <code>GET</code> request</h3>
<p>The simplest usage is a default <code>GET</code> request for a website or API:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl https://pokeapi.co/api/v2/machine/1</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span><span class="nt">&#34;id&#34;</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span><span class="nt">&#34;item&#34;</span><span class="p">:{</span><span class="nt">&#34;name&#34;</span><span class="p">:</span><span class="s2">&#34;tm00&#34;</span><span class="p">,</span><span class="nt">&#34;url&#34;</span><span class="p">:</span><span class="s2">&#34;https://pokeapi.co/api/v2/item/1288/&#34;</span><span class="p">},</span><span class="nt">&#34;move&#34;</span><span class="p">:{</span><span class="nt">&#34;name&#34;</span><span class="p">:</span><span class="s2">&#34;mega-punch&#34;</span><span class="p">,</span><span class="nt">&#34;url&#34;</span><span class="p">:</span><span class="s2">&#34;https://pokeapi.co/api/v2/move/5/&#34;</span><span class="p">},</span><span class="nt">&#34;version_group&#34;</span><span class="p">:{</span><span class="nt">&#34;name&#34;</span><span class="p">:</span><span class="s2">&#34;sword-shield&#34;</span><span class="p">,</span><span class="nt">&#34;url&#34;</span><span class="p">:</span><span class="s2">&#34;https://pokeapi.co/api/v2/version-group/20/&#34;</span><span class="p">}}</span></span></span></code></pre></div><h3 id="download-a-file">Download a file</h3>
<p>Downloading a file using the same name as the remote server:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -O https://github.com/curl/curl/releases/download/curl-8_0_1/curl-8.0.1.tar.gz</span></span></code></pre></div><p>Downloading a file and specifying a new name:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl -o curl.tar.gz https://github.com/curl/curl/releases/download/curl-8_0_1/curl-8.0.1.tar.gz</span></span></code></pre></div><h2 id="conclusion">Conclusion</h2>
<p><code>curl</code> is a powerful and versatile command line utility that offers a wide range of supporting features: multiple protocols, multiple options, data types, etc.</p>
]]></content:encoded></item><item><title>Build a dead simple CLI in Bash</title><link>https://how.wtf/build-a-dead-simple-cli-in-bash.html</link><pubDate>Thu, 11 May 2023 01:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/build-a-dead-simple-cli-in-bash.html</guid><description>Building a simple CLI in Bash may seem like a herculean task; however, getopts provides an easy-to-use interface out of the box! For this tutorial, we&amp;rsquo;ll be using the https://pokeapi.co/ to build a simple CLI for fetching resources from the Pokemon world.
What is getopts? Given from the documentation,
The getopts utility shall retrieve options and option-arguments from a list of parameters. It shall support the Utility Syntax Guidelines 3 to 10, inclusive, described in XBD Utility Syntax Guidelines.</description><content:encoded><![CDATA[<p>Building a simple CLI in Bash may seem like a herculean task; however, <code>getopts</code> provides an easy-to-use interface out of the box! For this tutorial, we&rsquo;ll be using the <a href="https://pokeapi.co/">https://pokeapi.co/</a> to build a simple CLI for fetching resources from the Pokemon world.</p>
<h2 id="what-is-getopts">What is <code>getopts</code>?</h2>
<p>Given from the <a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/getopts.html">documentation</a>,</p>
<blockquote>
<p>The <em>getopts</em> utility shall retrieve options and option-arguments from a list of parameters. It shall support the Utility Syntax Guidelines 3 to 10, inclusive, described in XBD <a href="https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02"><em>Utility Syntax Guidelines</em></a>.</p>
</blockquote>
<p><code>getopts</code> is a command that makes defining options and option-arguments seamless using a list of parameters.</p>
<h2 id="use-getopts-to-get-pokemon">Use <code>getopts</code> to get <code>pokemon</code></h2>
<p>Let&rsquo;s start by making the boilerplate:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">usage<span class="o">()</span> <span class="o">{</span> 
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="nb">echo</span> <span class="s2">&#34;Usage: </span><span class="nv">$0</span><span class="s2"> -p &lt;pokemon&gt;&#34;</span> 1&gt;<span class="p">&amp;</span><span class="m">2</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">  <span class="nb">exit</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="k">while</span> <span class="nb">getopts</span> <span class="s2">&#34;hp:&#34;</span> o<span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">  <span class="k">case</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">o</span><span class="si">}</span><span class="s2">&#34;</span> in
</span></span><span class="line"><span class="ln">10</span><span class="cl">    p<span class="o">)</span> <span class="nv">pokemon_name</span><span class="o">=</span><span class="s2">&#34;</span><span class="k">$(</span><span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$OPTARG</span><span class="s2">&#34;</span> <span class="p">|</span> tr <span class="s1">&#39;[:upper:]&#39;</span> <span class="s1">&#39;[:lower:]&#39;</span><span class="k">)</span><span class="s2">&#34;</span> <span class="p">;;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    h<span class="o">)</span> usage <span class="p">;;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">  <span class="k">esac</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="k">done</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="o">[[</span> -z <span class="s2">&#34;</span><span class="nv">$pokemon_name</span><span class="s2">&#34;</span> <span class="o">]]</span> <span class="o">&amp;&amp;</span> usage</span></span></code></pre></div><p>As seen above, <code>getopts</code> accepts a parameter list – ie. <code>hn:</code>. Colons (<code>:</code>) are used to denote that an argument requires a value.  In this case, <code>h</code> is as an option (<code>-h</code>) while <code>n</code> is  as an option-argument (<code>-n &lt;name&gt;</code>). If <code>$name</code> is not provided, then the <code>usage</code> function is called.</p>
<p>Within the <code>case</code> statement, <code>$OPTARG</code> contains the option-argument value that is passed from the user. For good measure, it is piped through <code>tr</code> to lowercase it (click <a href="https://how.wtf/convert-a-string-to-lowercase-in-bash.html">here</a> for more information about casing strings in Bash).</p>
<p>Now, let&rsquo;s add a simple curl command that calls the <code>/pokemon</code> api given the name:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">usage<span class="o">()</span> <span class="o">{</span> 
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="nb">echo</span> <span class="s2">&#34;Usage: </span><span class="nv">$0</span><span class="s2"> -p &lt;pokemon&gt;&#34;</span> 1&gt;<span class="p">&amp;</span><span class="m">2</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">  <span class="nb">exit</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">pokemon<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">  <span class="nb">local</span> <span class="nv">name</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$1</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">  curl -o <span class="s2">&#34;</span><span class="nv">$name</span><span class="s2">.json&#34;</span> https://pokeapi.co/api/v2/pokemon/<span class="nv">$name</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="se"></span>    -H <span class="s2">&#34;Accept: application/json&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">  <span class="nb">exit</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="k">while</span> <span class="nb">getopts</span> <span class="s2">&#34;hp:&#34;</span> o<span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">  <span class="k">case</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">o</span><span class="si">}</span><span class="s2">&#34;</span> in
</span></span><span class="line"><span class="ln">17</span><span class="cl">    p<span class="o">)</span> <span class="nv">pokemon_name</span><span class="o">=</span><span class="s2">&#34;</span><span class="k">$(</span><span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$OPTARG</span><span class="s2">&#34;</span> <span class="p">|</span> tr <span class="s1">&#39;[:upper:]&#39;</span> <span class="s1">&#39;[:lower:]&#39;</span><span class="k">)</span><span class="s2">&#34;</span> <span class="p">;;</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    h<span class="o">)</span> usage <span class="p">;;</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">  <span class="k">esac</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="k">done</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="o">[[</span> -z <span class="s2">&#34;</span><span class="nv">$pokemon_name</span><span class="s2">&#34;</span> <span class="o">]]</span> <span class="o">&amp;&amp;</span> usage
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="o">[[</span> <span class="s2">&#34;</span><span class="nv">$pokemon_name</span><span class="s2">&#34;</span> <span class="o">]]</span> <span class="o">&amp;&amp;</span> pokemon <span class="s2">&#34;</span><span class="nv">$pokemon_name</span><span class="s2">&#34;</span></span></span></code></pre></div><p>The <code>pokemon</code> function is called with the <code>$pokemon_name</code> that was passed in.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">./poke.sh -p pikachu</span></span></code></pre></div><p>The output is a <code>json</code> file that contains pikachu&rsquo;s information.</p>
<h2 id="use-getopts-to-get-items">Use <code>getopts</code> to get <code>items</code></h2>
<p>Building upon the last example, we can easily capture <code>items</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">usage<span class="o">()</span> <span class="o">{</span> 
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="nb">echo</span> <span class="s2">&#34;Usage: </span><span class="nv">$0</span><span class="s2"> [-p &lt;pokemon&gt;] [-i &lt;item&gt;]&#34;</span> 1&gt;<span class="p">&amp;</span><span class="m">2</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">  <span class="nb">exit</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">request<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">  <span class="nb">local</span> <span class="nv">path</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$1</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">  <span class="nb">local</span> <span class="nv">file_name</span><span class="o">=</span><span class="k">$(</span><span class="nb">echo</span> <span class="nv">$path</span> <span class="p">|</span> sed <span class="s1">&#39;s|.*/||&#39;</span><span class="k">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  curl -o <span class="s2">&#34;</span><span class="nv">$file_name</span><span class="s2">.json&#34;</span> https://pokeapi.co/api/v2/<span class="nv">$path</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="se"></span>    -H <span class="s2">&#34;Accept: application/json&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl">pokemon<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">  request <span class="s2">&#34;pokemon/</span><span class="nv">$1</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">  <span class="nb">exit</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl">item<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">  request <span class="s2">&#34;item/</span><span class="nv">$1</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">  <span class="nb">exit</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="k">while</span> <span class="nb">getopts</span> <span class="s2">&#34;hp:i:&#34;</span> o<span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">  <span class="k">case</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">o</span><span class="si">}</span><span class="s2">&#34;</span> in
</span></span><span class="line"><span class="ln">27</span><span class="cl">    p<span class="o">)</span> <span class="nv">pokemon_name</span><span class="o">=</span><span class="s2">&#34;</span><span class="k">$(</span><span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$OPTARG</span><span class="s2">&#34;</span> <span class="p">|</span> tr <span class="s1">&#39;[:upper:]&#39;</span> <span class="s1">&#39;[:lower:]&#39;</span><span class="k">)</span><span class="s2">&#34;</span> <span class="p">;;</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">    i<span class="o">)</span> <span class="nv">item_name</span><span class="o">=</span><span class="s2">&#34;</span><span class="k">$(</span><span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$OPTARG</span><span class="s2">&#34;</span> <span class="p">|</span> tr <span class="s1">&#39;[:upper:]&#39;</span> <span class="s1">&#39;[:lower:]&#39;</span><span class="k">)</span><span class="s2">&#34;</span> <span class="p">;;</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">    h<span class="o">)</span> usage <span class="p">;;</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">  <span class="k">esac</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="k">done</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="o">[[</span> -z <span class="s2">&#34;</span><span class="nv">$pokemon_name</span><span class="s2">&#34;</span> <span class="o">&amp;&amp;</span> -z <span class="s2">&#34;</span><span class="nv">$item_name</span><span class="s2">&#34;</span> <span class="o">]]</span> <span class="o">&amp;&amp;</span> usage
</span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="o">[[</span> <span class="s2">&#34;</span><span class="nv">$pokemon_name</span><span class="s2">&#34;</span> <span class="o">]]</span> <span class="o">&amp;&amp;</span> pokemon <span class="s2">&#34;</span><span class="nv">$pokemon_name</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="o">[[</span> <span class="s2">&#34;</span><span class="nv">$item_name</span><span class="s2">&#34;</span> <span class="o">]]</span> <span class="o">&amp;&amp;</span> item <span class="s2">&#34;</span><span class="nv">$item_name</span><span class="s2">&#34;</span></span></span></code></pre></div><p>A few things happened:</p>
<ol>
<li>I abstracted the <code>curl</code> to its own function named <code>request</code>
<ol>
<li>The <code>file_name</code> is parsed from the path. Ie. <code>/items/master-ball</code> -&gt; <code>master-ball.json</code></li>
</ol>
</li>
<li><code>pokemon</code> and <code>item</code> both call <code>request</code></li>
<li><code>i:</code> was added to the <code>getopts</code> string to allow the<code>-i &lt;item&gt;</code> option-argument.</li>
</ol>
<h2 id="whats-next">What&rsquo;s next?</h2>
<p><code>getopts</code> is useful for building plain / simple CLIs. If something more advanced is necessary, <code>bash</code> is not the best language for the task.</p>
]]></content:encoded></item><item><title>Get file name or extension in Bash</title><link>https://how.wtf/get-file-name-or-extension-in-bash.html</link><pubDate>Wed, 10 May 2023 00:20:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/get-file-name-or-extension-in-bash.html</guid><description>Retrieving the file name and extension in Bash can be completed using basename and shell parameter expansion.
Get the file name Using the native unix basename command, the file name can be extracted from the path.
1file_path=&amp;#34;/path/to/package.tar.gz&amp;#34; 2file_name=$(basename &amp;#34;$file_path&amp;#34;) 3echo &amp;#34;$file_name&amp;#34;Output:
1package.tar.gzGet the file extension Using shell parameter expansion, the prior example can include capturing the file extension:
1file_path=&amp;#34;/path/to/package.tar.gz&amp;#34; 2file_name=$(basename &amp;#34;$file_path&amp;#34;) 3file_ext=&amp;#34;${file_name#*.}&amp;#34; 4echo &amp;#34;$file_ext&amp;#34;Output:
1tar.gzMatch on file extension using a case statement If there is conditional logic required for specific file extensions, a case statement may be used.</description><content:encoded><![CDATA[<p>Retrieving the file name and extension in Bash can be completed using <code>basename</code> and <a href="https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html">shell parameter expansion</a>.</p>
<h2 id="get-the-file-name">Get the file name</h2>
<p>Using the native unix <code>basename</code> command, the file name can be extracted from the path.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">file_path</span><span class="o">=</span><span class="s2">&#34;/path/to/package.tar.gz&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nv">file_name</span><span class="o">=</span><span class="k">$(</span>basename <span class="s2">&#34;</span><span class="nv">$file_path</span><span class="s2">&#34;</span><span class="k">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$file_name</span><span class="s2">&#34;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">package.tar.gz</span></span></code></pre></div><h2 id="get-the-file-extension">Get the file extension</h2>
<p>Using shell parameter expansion, the prior example can include capturing the file extension:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">file_path</span><span class="o">=</span><span class="s2">&#34;/path/to/package.tar.gz&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nv">file_name</span><span class="o">=</span><span class="k">$(</span>basename <span class="s2">&#34;</span><span class="nv">$file_path</span><span class="s2">&#34;</span><span class="k">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nv">file_ext</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">file_name</span><span class="p">#*.</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$file_ext</span><span class="s2">&#34;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">tar.gz</span></span></code></pre></div><h2 id="match-on-file-extension-using-a-case-statement">Match on file extension using a <code>case</code> statement</h2>
<p>If there is conditional logic required for specific file extensions, a <code>case</code> statement may be used. In addition, this is standard <code>sh</code> (not exclusive to <code>bash</code>)</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">file_path</span><span class="o">=</span><span class="s2">&#34;/path/to/package.tar.gz&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nv">file_name</span><span class="o">=</span><span class="k">$(</span>basename <span class="s2">&#34;</span><span class="nv">$file_path</span><span class="s2">&#34;</span><span class="k">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">case</span> <span class="s2">&#34;</span><span class="nv">$file_name</span><span class="s2">&#34;</span> in
</span></span><span class="line"><span class="ln">5</span><span class="cl">    *.tar.gz<span class="o">)</span> <span class="nb">echo</span> <span class="s2">&#34;matched tar.gz!&#34;</span> <span class="p">;;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="k">esac</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">matched tar.gz!</span></span></code></pre></div>]]></content:encoded></item><item><title>Convert a string to lowercase in Bash</title><link>https://how.wtf/convert-a-string-to-lowercase-in-bash.html</link><pubDate>Tue, 09 May 2023 00:10:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/convert-a-string-to-lowercase-in-bash.html</guid><description>Here are the top 3 ways for converting a string to lowercase in Bash.
Using tr One of the most popular ways for lowercasing a string is using tr. This is a POSIX standard method for accomplishing the task.
1echo &amp;#34;I WANT this LoWeRcAsEd&amp;#34; | tr &amp;#39;[:upper:]&amp;#39; &amp;#39;[:lower:]&amp;#39; 2# Outputs: i want this lowercasedUsing awk Another POXIS standard is using awk&amp;rsquo;s native toLower method.
1echo &amp;#34;I WANT this LoWeRcAsEd&amp;#34; | awk &amp;#39;{print tolower($0)}&amp;#39; 2# Outputs: i want this lowercasedUsing Bash 4.</description><content:encoded><![CDATA[<p>Here are the top 3 ways for converting a string to lowercase in Bash.</p>
<h2 id="using-tr">Using <code>tr</code></h2>
<p>One of the most popular ways for lowercasing a string is using <code>tr</code>. This is a POSIX standard method for accomplishing the task.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;I WANT this LoWeRcAsEd&#34;</span> <span class="p">|</span> tr <span class="s1">&#39;[:upper:]&#39;</span> <span class="s1">&#39;[:lower:]&#39;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"># Outputs: i want this lowercased</span></span></span></code></pre></div><h2 id="using-awk">Using <code>awk</code></h2>
<p>Another POXIS standard is using <code>awk</code>&rsquo;s native <code>toLower</code> method.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;I WANT this LoWeRcAsEd&#34;</span> <span class="p">|</span> awk <span class="s1">&#39;{print tolower($0)}&#39;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"># Outputs: i want this lowercased</span></span></span></code></pre></div><h2 id="using-bash-40">Using <code>Bash</code> 4.0</h2>
<p><code>bash</code> 4.0 natively supports converting strings to lowercase.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">toLower</span><span class="o">=</span><span class="s2">&#34;I WANT this LoWeRcAsEd&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">toLower</span><span class="p">,,</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"># Outputs: i want this lowercased</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Use Linux terminal as a calculator</title><link>https://how.wtf/use-linux-terminal-as-a-calculator.html</link><pubDate>Mon, 08 May 2023 01:20:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/use-linux-terminal-as-a-calculator.html</guid><description>Linux provides several methods for calculating expressions using the command line.
Using bc — basic calculator for command line bc is a native Linux tool (originated on Unix systems in 1975) that stands for &amp;ldquo;basic calculator&amp;rdquo;. To use it, simply type bc followed by an expression. To quit, type quit.
1&amp;gt; bc 2Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006, 2008, 2012-2017 Free Software Foundation, Inc. 3This is free software with ABSOLUTELY NO WARRANTY.</description><content:encoded><![CDATA[<p>Linux provides several methods for calculating expressions using the command line.</p>
<h2 id="using-bc---basic-calculator-for-command-line">Using <code>bc</code>  — basic calculator for command line</h2>
<p><code>bc</code> is a native Linux tool (originated on Unix systems in 1975) that stands for &ldquo;basic calculator&rdquo;. To use it, simply type <code>bc</code> followed by an expression. To quit, type <code>quit</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln"> 1</span><span class="cl">&gt; bc
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">This is free software with ABSOLUTELY NO WARRANTY.
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">For details <span class="nb">type</span> <span class="sb">`</span>warranty<span class="err">&#39;</span>. 
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="m">5</span> + <span class="m">5</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="m">10</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="m">25</span> * <span class="m">4</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="m">100</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="m">100</span> / <span class="m">2</span> * <span class="m">35</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="m">1750</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="m">2</span> * <span class="o">(</span><span class="m">2</span> * 5<span class="o">)</span> + <span class="m">15</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="m">35</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">quit</span></span></code></pre></div><p>Additionally, variables, arrays, algebraic expressions, etc. can be used. Refer to the <a href="https://www.gnu.org/software/bc/manual/html_mono/bc.html"><code>bc</code> manual</a> for more information.</p>
<h2 id="using-expr">Using <code>expr</code></h2>
<p>The <code>expr</code> command evaluates basic expressions.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">&gt; expr <span class="m">5</span> + <span class="m">5</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="m">10</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">&gt; expr <span class="m">25</span> <span class="se">\*</span> <span class="m">4</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="m">100</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">&gt; expr <span class="m">100</span> / <span class="m">2</span> <span class="se">\*</span> <span class="m">35</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="m">1750</span></span></span></code></pre></div><p>Keep in mind, it should be used for basic calculations. If something more advanced is required (like parenthesis), <code>bc</code> or arithmetic expansion may be more suitable.</p>
<h2 id="using-arithmetic-expansion">Using arithmetic expansion</h2>
<p>Arithmetic expansion evaluates an expression and substitutes the result. In combination with <code>echo</code>, it can be used as a calculator.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">&gt; <span class="nb">echo</span> <span class="s2">&#34;</span><span class="k">$((</span><span class="m">5</span> <span class="o">+</span> <span class="m">5</span><span class="k">))</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="m">10</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">&gt; <span class="nb">echo</span> <span class="s2">&#34;</span><span class="k">$((</span><span class="m">25</span> <span class="o">*</span> <span class="m">4</span><span class="k">))</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="m">100</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">&gt; <span class="nb">echo</span> <span class="s2">&#34;</span><span class="k">$((</span><span class="m">100</span> <span class="o">/</span> <span class="m">2</span> <span class="o">*</span> <span class="m">35</span><span class="k">))</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="m">1750</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">&gt; <span class="nb">echo</span> <span class="s2">&#34;</span><span class="k">$((</span><span class="m">2</span> <span class="o">*</span> <span class="o">(</span><span class="m">2</span> <span class="o">*</span> <span class="m">5</span><span class="o">)</span> <span class="o">+</span> <span class="m">15</span><span class="k">))</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="m">35</span></span></span></code></pre></div><h2 id="using-qalc">Using <code>qalc</code></h2>
<p>Qalc is a multi-purpose cross-platform desktop calculator. It provides versatility and supports many everyday needs: currency conversion, percent calculation, etc.</p>
<p>Install it on Ubuntu via <code>apt</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo apt install qalc</span></span></code></pre></div><p>Example usage:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln"> 1</span><span class="cl">&gt; sqrt<span class="o">(</span>72<span class="o">)</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  sqrt<span class="o">(</span>72<span class="o">)</span> <span class="o">=</span> <span class="m">6</span> × √<span class="o">(</span>2<span class="o">)</span> ≈ 8.485281374
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">&gt; fibonacci<span class="o">(</span>133<span class="o">)</span> to hex
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  fibonacci<span class="o">(</span>133<span class="o">)</span> ≈ 0x90540BE2616C26F81F876B9
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">&gt; 5/3 + 3/7
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="o">(</span><span class="m">5</span> / 3<span class="o">)</span> + <span class="o">(</span><span class="m">3</span> / 7<span class="o">)</span> <span class="o">=</span> 44/21 <span class="o">=</span> <span class="m">2</span> + 2/21 ≈ 2.095238095
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl">&gt; <span class="m">5</span> + <span class="m">5</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl">  <span class="m">5</span> + <span class="nv">5</span> <span class="o">=</span> <span class="m">10</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl">&gt; exit</span></span></code></pre></div>]]></content:encoded></item><item><title>Installing Docker on Ubuntu</title><link>https://how.wtf/installing-docker-on-ubuntu.html</link><pubDate>Sat, 06 May 2023 21:25:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/installing-docker-on-ubuntu.html</guid><description>Installing Docker on Ubuntu-based Linux distributions: Linux Mint, Zorin, Pop OS, etc. is simple!
Installing Docker from CLI Docker is available in the default repositories of apt. Install via:
1sudo apt install docker.ioAdd permissions to the docker group by adding the current user:
1sudo usermod -a -G docker $(whoami)Verify that everything worked:
1docker psOutput:
1CONTAINER ID IMAGE COMMAND CREATEDTroubleshooting If the following error occurs after docker ps:
1Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.</description><content:encoded><![CDATA[<p>Installing Docker on Ubuntu-based Linux distributions: Linux Mint, Zorin, Pop OS, etc. is simple!</p>
<h2 id="installing-docker-from-cli">Installing Docker from CLI</h2>
<p>Docker is available in the default repositories of <code>apt</code>. Install via:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo apt install docker.io</span></span></code></pre></div><p>Add permissions to the <code>docker</code> group by adding the current user:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo usermod -a -G docker <span class="k">$(</span>whoami<span class="k">)</span></span></span></code></pre></div><p>Verify that everything worked:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">docker ps</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">CONTAINER ID        IMAGE               COMMAND             CREATED</span></span></code></pre></div><h2 id="troubleshooting">Troubleshooting</h2>
<p>If the following error occurs after <code>docker ps</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">Got permission denied <span class="k">while</span> trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json: dial unix /var/run/docker.sock: connect: permission denied</span></span></code></pre></div><p><strong>1. Check if Docker is running:</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo systemctl status docker</span></span></code></pre></div><p>the status should show <code>active (running)</code>.</p>
<p>If not, restart the docker service with the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo systemctl restart docker</span></span></code></pre></div><p><strong>2. Verify that the current user is apart of the <code>docker</code> group</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">grep docker /etc/group</span></span></code></pre></div><p>the output should show <code>docker:x:135:USER</code> with <code>USER</code> as the current user given from <code>$(whoami)</code>. If not, add the current user to the <code>docker</code> group using the instructions above.</p>
<p><strong>3. Verify that the tty session shows correct group membership</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">id -nG</span></span></code></pre></div><p>the output should contain <code>docker</code> in the list. If not, reboot.</p>
<p><strong>4. Reboot</strong></p>
<p>If all the prior steps were successful, simply reboot.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo reboot</span></span></code></pre></div>]]></content:encoded></item><item><title>Test AWS credentials using AWS CLI</title><link>https://how.wtf/test-aws-credentials-using-aws-cli.html</link><pubDate>Fri, 05 May 2023 23:55:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/test-aws-credentials-using-aws-cli.html</guid><description>Testing for AWS credentials is a straightforward operation.
Using get-caller-identity There is a single API call that will always work regardless of permissions: GetCallerIdentity
1aws sts get-caller-identityOutput:
1{ 2 &amp;#34;UserId&amp;#34;: &amp;#34;AIDA...&amp;#34;, 3 &amp;#34;Account&amp;#34;: &amp;#34;123456789012&amp;#34;, 4 &amp;#34;Arn&amp;#34;: &amp;#34;arn:aws:iam::123456789012:user/thomas&amp;#34; 5}The Arn value depends on the type of credentials, but mostly includes the human-friendly name.
In addition, checking the status is reliable: 0 for success, 255 for failure.</description><content:encoded><![CDATA[<p>Testing for AWS credentials is a straightforward operation.</p>
<h2 id="using-get-caller-identity">Using <code>get-caller-identity</code></h2>
<p>There is a single API call that will always work regardless of permissions: <a href="https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html">GetCallerIdentity</a></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws sts get-caller-identity</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{
</span></span><span class="line"><span class="ln">2</span><span class="cl">    &#34;UserId&#34;: &#34;AIDA...&#34;,
</span></span><span class="line"><span class="ln">3</span><span class="cl">    &#34;Account&#34;: &#34;123456789012&#34;,
</span></span><span class="line"><span class="ln">4</span><span class="cl">    &#34;Arn&#34;: &#34;arn:aws:iam::123456789012:user/thomas&#34;
</span></span><span class="line"><span class="ln">5</span><span class="cl">}</span></span></code></pre></div><p>The <code>Arn</code> value depends on the type of credentials, but mostly includes the human-friendly name.</p>
<p>In addition, checking the status is reliable: <code>0</code> for success, <code>255</code> for failure.</p>
]]></content:encoded></item><item><title>Split a list into evenly sized batches in Python</title><link>https://how.wtf/split-a-list-into-evenly-sized-batches-in-python.html</link><pubDate>Thu, 04 May 2023 21:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/split-a-list-into-evenly-sized-batches-in-python.html</guid><description>Splitting a list into evenly sized chunks or batches can be accomplished using Python.
Using itertools.batched In Python 3.12, itertools.batched is available for consumption.
1import itertools 2 3lst = [&amp;#39;mary&amp;#39;, &amp;#39;sam&amp;#39;, &amp;#39;joseph&amp;#39;] 4print(list(itertools.batched(lst, 2))) # [(&amp;#39;mary&amp;#39;, &amp;#39;sam&amp;#39;), (&amp;#39;joseph&amp;#39;)]Using yield If the version of Python is lower than 3.12, the yield keyword may be used.
1def chunks(lst, n): 2 for i in range(0, len(lst), n): 3 yield lst[i:i + n] 4 5lst = [&amp;#39;mary&amp;#39;, &amp;#39;sam&amp;#39;, &amp;#39;joseph&amp;#39;] 6print(list(chunks(lst, 2))) # [[&amp;#39;mary&amp;#39;, &amp;#39;sam&amp;#39;], [&amp;#39;joseph&amp;#39;]]Using itertools.</description><content:encoded><![CDATA[<p>Splitting a list into evenly sized chunks or batches can be accomplished using Python.</p>
<h2 id="using-itertoolsbatched">Using <code>itertools.batched</code></h2>
<p>In Python 3.12, <code>itertools.batched</code> is available for <a href="https://docs.python.org/3.12/library/itertools.html?highlight=batched#itertools.batched">consumption</a>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">itertools</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">lst</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;mary&#39;</span><span class="p">,</span> <span class="s1">&#39;sam&#39;</span><span class="p">,</span> <span class="s1">&#39;joseph&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">itertools</span><span class="o">.</span><span class="n">batched</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="mi">2</span><span class="p">)))</span> <span class="c1"># [(&#39;mary&#39;, &#39;sam&#39;), (&#39;joseph&#39;)]</span></span></span></code></pre></div><h2 id="using-yield">Using <code>yield</code></h2>
<p>If the version of Python is lower than 3.12, the <code>yield</code> keyword may be used.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">def</span> <span class="nf">chunks</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="n">n</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">lst</span><span class="p">),</span> <span class="n">n</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="k">yield</span> <span class="n">lst</span><span class="p">[</span><span class="n">i</span><span class="p">:</span><span class="n">i</span> <span class="o">+</span> <span class="n">n</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">lst</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;mary&#39;</span><span class="p">,</span> <span class="s1">&#39;sam&#39;</span><span class="p">,</span> <span class="s1">&#39;joseph&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">chunks</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="mi">2</span><span class="p">)))</span> <span class="c1"># [[&#39;mary&#39;, &#39;sam&#39;], [&#39;joseph&#39;]]</span></span></span></code></pre></div><h2 id="using-itertoolsislice">Using <code>itertools.islice</code></h2>
<p>The <code>itertools.islice</code> function can additionally be used.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">islice</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">def</span> <span class="nf">chunks</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="n">n</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="n">it</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="n">lst</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="k">return</span> <span class="nb">iter</span><span class="p">(</span><span class="k">lambda</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">islice</span><span class="p">(</span><span class="n">it</span><span class="p">,</span> <span class="n">n</span><span class="p">)),</span> <span class="p">())</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="n">lst</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;mary&#39;</span><span class="p">,</span> <span class="s1">&#39;sam&#39;</span><span class="p">,</span> <span class="s1">&#39;joseph&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">chunks</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="mi">2</span><span class="p">)))</span> <span class="c1"># [(&#39;mary&#39;, &#39;sam&#39;), (&#39;joseph&#39;,)]</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Delete local branches not on remote using Git</title><link>https://how.wtf/delete-local-branches-not-on-remote-using-git.html</link><pubDate>Wed, 03 May 2023 23:55:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/delete-local-branches-not-on-remote-using-git.html</guid><description>After merging changes or working on temporary branches, users may retain a list of orphaned git branches on their local machine. Rather than deleting each branch one-by-one, running a simple script can clear them out.
Delete local branches not found on remote The one-liner script to delete local branches not found one remote:
1git fetch -p &amp;amp;&amp;amp; for branch in $(git for-each-ref --format &amp;#39;%(refname) %(upstream:track)&amp;#39; refs/heads | awk &amp;#39;$2 == &amp;#34;[gone]&amp;#34; {sub(&amp;#34;refs/heads/&amp;#34;, &amp;#34;&amp;#34;, $1); print $1}&amp;#39;); do git branch -D $branch; doneThis works by detected if a branch is [gone] from remote.</description><content:encoded><![CDATA[<p>After merging changes or working on temporary branches, users may retain a list of orphaned git branches on their local machine. Rather than deleting each branch one-by-one, running a simple script can clear them out.</p>
<h2 id="delete-local-branches-not-found-on-remote">Delete local branches not found on remote</h2>
<p>The one-liner script to delete local branches not found one remote:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">git fetch -p <span class="o">&amp;&amp;</span> <span class="k">for</span> branch in <span class="k">$(</span>git <span class="k">for</span>-each-ref --format <span class="s1">&#39;%(refname) %(upstream:track)&#39;</span> refs/heads <span class="p">|</span> awk <span class="s1">&#39;$2 == &#34;[gone]&#34; {sub(&#34;refs/heads/&#34;, &#34;&#34;, $1); print $1}&#39;</span><span class="k">)</span><span class="p">;</span> <span class="k">do</span> git branch -D <span class="nv">$branch</span><span class="p">;</span> <span class="k">done</span></span></span></code></pre></div><p>This works by detected if a branch is <code>[gone]</code> from remote.</p>
]]></content:encoded></item><item><title>Access the current index in for loops in Python</title><link>https://how.wtf/access-the-current-index-in-for-loops-in-python.html</link><pubDate>Tue, 02 May 2023 23:50:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/access-the-current-index-in-for-loops-in-python.html</guid><description>In Python, an iterable may be traversed using a simple for in loop:
1names = [&amp;#34;sally&amp;#34;, &amp;#34;mary&amp;#34;, &amp;#34;billy&amp;#34;] 2for n in names: 3 print(n)However, what if the current index is desired?
Access the index in a Python for loop The recommended pythonic solution is to use the built-in enumerate function.
1names = [&amp;#34;sally&amp;#34;, &amp;#34;mary&amp;#34;, &amp;#34;billy&amp;#34;] 2for i, n in enumerate(names): 3 print(i, n)Output:
10 sally 21 mary 32 billyFor contrast, the unidiomatic way to access the current index is by using range:</description><content:encoded><![CDATA[<p>In Python, an iterable may be traversed using a simple for in loop:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">names</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;sally&#34;</span><span class="p">,</span> <span class="s2">&#34;mary&#34;</span><span class="p">,</span> <span class="s2">&#34;billy&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">names</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">	<span class="nb">print</span><span class="p">(</span><span class="n">n</span><span class="p">)</span></span></span></code></pre></div><p>However, what if the current index is desired?</p>
<h2 id="access-the-index-in-a-python-for-loop">Access the index in a Python <code>for</code> loop</h2>
<p>The <em>recommended</em> pythonic solution is to use the built-in <code>enumerate</code> function.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">names</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;sally&#34;</span><span class="p">,</span> <span class="s2">&#34;mary&#34;</span><span class="p">,</span> <span class="s2">&#34;billy&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">names</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">	<span class="nb">print</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">0 sally
</span></span><span class="line"><span class="ln">2</span><span class="cl">1 mary
</span></span><span class="line"><span class="ln">3</span><span class="cl">2 billy</span></span></code></pre></div><p>For contrast, the unidiomatic way to access the current index is by using <code>range</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">names</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;sally&#34;</span><span class="p">,</span> <span class="s2">&#34;mary&#34;</span><span class="p">,</span> <span class="s2">&#34;billy&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">names</span><span class="p">)):</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">	<span class="nb">print</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">names</span><span class="p">[</span><span class="n">i</span><span class="p">])</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">0 sally
</span></span><span class="line"><span class="ln">2</span><span class="cl">1 mary
</span></span><span class="line"><span class="ln">3</span><span class="cl">2 billy</span></span></code></pre></div>]]></content:encoded></item><item><title>Kill all processes that match a name</title><link>https://how.wtf/kill-all-processes-that-match-a-name.html</link><pubDate>Mon, 01 May 2023 23:40:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/kill-all-processes-that-match-a-name.html</guid><description>Killing all processes that match a certain substring or name is easy using pkill.
Killing all processes using pkill pkill is a native Linux tool that provides command line access for killing or reloading processes.
To kill all processes that match a pattern:
1pkill -f firefoxIf pkill is not successful, trying adding the -9 flag.
1pkill -9 -f firefox</description><content:encoded><![CDATA[<p>Killing all processes that match a certain substring or name is easy using <code>pkill</code>.</p>
<h2 id="killing-all-processes-using-pkill">Killing all processes using <code>pkill</code></h2>
<p><code>pkill</code> is a native Linux tool that provides command line access for killing or reloading processes.</p>
<p>To kill all processes that match a pattern:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pkill -f firefox</span></span></code></pre></div><p>If <code>pkill</code> is not successful, trying adding the <code>-9</code> flag.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pkill -9 -f firefox</span></span></code></pre></div>]]></content:encoded></item><item><title>Confirmation prompt yes/no in Bash</title><link>https://how.wtf/confirmation-prompt-yes/no-in-bash.html</link><pubDate>Sun, 30 Apr 2023 23:55:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/confirmation-prompt-yes/no-in-bash.html</guid><description>Asking for user confirmation in a bash script is easy!
Yes/No prompt with default no If the default is No for an invalid character or space, simply check if the prompt answer is y. Using read, user input can be limited to a single character using the -n 1 parameter.
1read -r -p &amp;#34;Are you sure? [y/N]&amp;#34; -n 1 2echo # (optional) move to a new line 3if [[ &amp;#34;$REPLY&amp;#34; =~ ^[Yy]$ ]]; then 4 echo &amp;#34;Operation continues&amp;#34; 5fiSimilarly, a case statement may be used:</description><content:encoded><![CDATA[<p>Asking for user confirmation in a <code>bash</code> script is easy!</p>
<h2 id="yesno-prompt-with-default-no">Yes/No prompt with default no</h2>
<p>If the default is <code>No</code> for an invalid character <em>or</em> space, simply check if the prompt answer is <code>y</code>.  Using <code>read</code>, user input can be limited to a single character using the <code>-n 1</code> parameter.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">read</span> -r -p <span class="s2">&#34;Are you sure? [y/N]&#34;</span> -n <span class="m">1</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">echo</span> <span class="c1"># (optional) move to a new line</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">if</span> <span class="o">[[</span> <span class="s2">&#34;</span><span class="nv">$REPLY</span><span class="s2">&#34;</span> <span class="o">=</span>~ ^<span class="o">[</span>Yy<span class="o">]</span>$ <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;Operation continues&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p>Similarly, a case statement may be used:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">read</span> -r -p <span class="s2">&#34;Are you sure? [y/N]&#34;</span> -n <span class="m">1</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">echo</span> <span class="c1"># (optional) move to a new line</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">case</span> <span class="s2">&#34;</span><span class="nv">$REPLY</span><span class="s2">&#34;</span> in 
</span></span><span class="line"><span class="ln">4</span><span class="cl">  y<span class="p">|</span>Y <span class="o">)</span> <span class="nb">echo</span> <span class="s2">&#34;Operation continues&#34;</span><span class="p">;;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">  * <span class="o">)</span> <span class="nb">echo</span> <span class="s2">&#34;Operation is cancelled&#34;</span><span class="p">;;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="k">esac</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Create dictionaries or maps in Bash</title><link>https://how.wtf/create-dictionaries-or-maps-in-bash.html</link><pubDate>Sat, 29 Apr 2023 23:55:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/create-dictionaries-or-maps-in-bash.html</guid><description>bash 4.0 natively supports creating hash tables / maps / dictionaries.
Using maps in Bash Variables in bash are loosely typed; however, declaring provides a type-like behavior. One of the supported types in bash is an associative array (-A).
To declare an associative array:
1declare -A scoresTo declare and instantiate in a single line:
1declare -A scores=( [&amp;#34;peter&amp;#34;]=95 [&amp;#34;sally&amp;#34;]=98 )Add key/value pairs Adding key/value pairs to an existing associate array:</description><content:encoded><![CDATA[<p><code>bash</code> 4.0 natively supports creating hash tables / maps / dictionaries.</p>
<h2 id="using-maps-in-bash">Using maps in Bash</h2>
<p>Variables in <code>bash</code> are loosely typed; however, declaring provides a type-like behavior. One of the supported types in <code>bash</code> is an associative array (<code>-A</code>).</p>
<p>To declare an associative array:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">declare</span> -A scores</span></span></code></pre></div><p>To declare and instantiate in a single line:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">declare</span> -A <span class="nv">scores</span><span class="o">=(</span> <span class="o">[</span><span class="s2">&#34;peter&#34;</span><span class="o">]=</span><span class="m">95</span> <span class="o">[</span><span class="s2">&#34;sally&#34;</span><span class="o">]=</span><span class="m">98</span> <span class="o">)</span></span></span></code></pre></div><h3 id="add-keyvalue-pairs">Add key/value pairs</h3>
<p>Adding key/value pairs to an existing associate array:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">scores<span class="o">[</span><span class="s2">&#34;tom&#34;</span><span class="o">]=</span><span class="m">85</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"># using variables</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nv">name</span><span class="o">=</span><span class="s2">&#34;brandon&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="nv">score</span><span class="o">=</span><span class="m">50</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">scores<span class="o">[</span><span class="nv">$name</span><span class="o">]=</span><span class="nv">$score</span></span></span></code></pre></div><h3 id="retrieve-keyvalue-pairs">Retrieve key/value pairs</h3>
<p>Retrieving key/value pairs from an existing associative array:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">name</span><span class="o">=</span><span class="s2">&#34;peter&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">scores</span><span class="p">[</span><span class="nv">$name</span><span class="p">]</span><span class="si">}</span> <span class="c1"># 95</span></span></span></code></pre></div><h3 id="update-an-existing-keyvalue-pair">Update an existing key/value pair</h3>
<p>Updating an existing key/value pair in an existing associative array:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">name</span><span class="o">=</span><span class="s2">&#34;peter&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">scores<span class="o">[</span><span class="nv">$name</span><span class="o">]=</span><span class="m">100</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">scores</span><span class="p">[</span><span class="nv">$name</span><span class="p">]</span><span class="si">}</span> <span class="c1"># 100</span></span></span></code></pre></div><h3 id="check-if-a-key-exists">Check if a key exists</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">name</span><span class="o">=</span><span class="s2">&#34;peter&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">if</span> <span class="o">[</span> -v scores<span class="o">[</span><span class="nv">$name</span><span class="o">]</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$name</span><span class="s2"> exists in the map&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1"># Output: peter exists in the map</span></span></span></code></pre></div><h3 id="remove-a-key">Remove a key</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">name</span><span class="o">=</span><span class="s2">&#34;peter&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">unset</span> scores<span class="o">[</span><span class="nv">$name</span><span class="o">]</span></span></span></code></pre></div><h3 id="iterate-map">Iterate map</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">for</span> key in <span class="s2">&#34;</span><span class="si">${</span><span class="p">!scores[@]</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$key</span><span class="s2"> </span><span class="si">${</span><span class="nv">scores</span><span class="p">[</span><span class="nv">$key</span><span class="p">]</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">done</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">tom 85
</span></span><span class="line"><span class="ln">2</span><span class="cl">brandon 50
</span></span><span class="line"><span class="ln">3</span><span class="cl">sally 98
</span></span><span class="line"><span class="ln">4</span><span class="cl">peter 100</span></span></code></pre></div>]]></content:encoded></item><item><title>Get seconds since Epoch in Bash</title><link>https://how.wtf/get-seconds-since-epoch-in-bash.html</link><pubDate>Fri, 28 Apr 2023 23:50:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/get-seconds-since-epoch-in-bash.html</guid><description>bash 5.0 natively supports retrieving seconds since Epoch using a variable.
Native bash method 1echo $EPOCHSECONDS # 1682740449If seconds are preferred:
1echo $EPOCHREALTIME # 1682740449.252199If milliseconds are preferred:
1echo $(( ${EPOCHREALTIME/./} / 1000 )) # 1682740449252Using date In addition to using the native bash method, date may be used.
According to the date manual:
%s seconds since the Epoch (1970-01-01 00:00 UTC)
1echo $(date +%s) # 1682740326If milliseconds seconds are preferred:</description><content:encoded><![CDATA[<p><code>bash</code> 5.0 natively supports retrieving seconds since Epoch using a variable.</p>
<h2 id="native-bash-method">Native <code>bash</code> method</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="nv">$EPOCHSECONDS</span> <span class="c1"># 1682740449</span></span></span></code></pre></div><p>If seconds are preferred:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="nv">$EPOCHREALTIME</span> <span class="c1"># 1682740449.252199</span></span></span></code></pre></div><p>If milliseconds are preferred:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="k">$((</span> <span class="si">${</span><span class="nv">EPOCHREALTIME</span><span class="p">/./</span><span class="si">}</span> <span class="o">/</span> <span class="m">1000</span> <span class="k">))</span> <span class="c1"># 1682740449252</span></span></span></code></pre></div><h2 id="using-date">Using <code>date</code></h2>
<p>In addition to using the native <code>bash</code> method, <code>date</code> may be used.</p>
<p>According to the <code>date</code> manual:</p>
<blockquote>
<p>%s seconds since the Epoch (1970-01-01 00:00 UTC)</p>
</blockquote>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="k">$(</span>date +%s<span class="k">)</span> <span class="c1"># 1682740326</span></span></span></code></pre></div><p>If milliseconds seconds are preferred:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="k">$(</span>date +%s%3N<span class="k">)</span> <span class="c1"># 1682740449252</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Catch and handle errors in Bash</title><link>https://how.wtf/catch-and-handle-errors-in-bash.html</link><pubDate>Thu, 27 Apr 2023 22:10:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/catch-and-handle-errors-in-bash.html</guid><description>Bash does not natively support a try/catch syntax for errors; however, there are options for handling errors within a script.
Try and Catch errors in Bash For the first technique, simply detect if there&amp;rsquo;s a non-zero status by using the following syntax:
1if ! command_call; then 2 echo &amp;#34;command_call did not complete successfully&amp;#34; 3fiIn addition, an || (or) expression may be used instead:
1command_call || echo &amp;#34;command_call did not complete successfully&amp;#34;For explicitness, the full syntax for a try/catch in Bash is:</description><content:encoded><![CDATA[<p>Bash does not natively support a try/catch syntax for errors; however, there are options for handling errors within a script.</p>
<h2 id="try-and-catch-errors-in-bash">Try and Catch errors in Bash</h2>
<p>For the first technique, simply detect if there&rsquo;s a non-zero status by using the following syntax:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">if</span> ! command_call<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;command_call did not complete successfully&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p>In addition, an <code>||</code> (or) expression may be used instead:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">command_call <span class="o">||</span> <span class="nb">echo</span> <span class="s2">&#34;command_call did not complete successfully&#34;</span></span></span></code></pre></div><p>For explicitness, the full syntax for a <code>try/catch</code> in Bash is:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">if</span> command_call <span class="p">;</span> <span class="k">then</span> <span class="c1"># try</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;tried and was successful&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">else</span> <span class="c1"># catch</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;command_call did not complete successfully&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p>If <code>command_call</code> is not successful, the echo statement will be invoked in all scenarios.</p>
<h2 id="error-handling-in-bash">Error handling in Bash</h2>
<p>For the second technique, <code>bash</code> provides a native variable for reporting exit codes: <code>$?</code>. Some users may want to catch and handle <em>specific</em> exit codes.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">command_call
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nv">status</span><span class="o">=</span><span class="nv">$?</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">if</span> <span class="o">[</span> <span class="nv">$status</span> -eq <span class="m">1</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;General exception&#34;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="k">elif</span> <span class="o">[</span> <span class="nv">$status</span> -eq <span class="m">127</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;The command could not be found!&#34;</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Top free PostgreSQL database hosting options</title><link>https://how.wtf/top-free-postgresql-database-hosting-options.html</link><pubDate>Thu, 27 Apr 2023 00:05:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/top-free-postgresql-database-hosting-options.html</guid><description>Hosting a free PostgreSQL database for side projects, MVPs, learning, etc. is easy with free tiers provided by following services in this article.
The following list is not comprehensive nor in any specific order.
Top free PostgreSQL database hosting online Here are the top free PostgreSQL database online hosting services:
Neon Neon provides a generous free tier for a fully managed PostgreSQL database. Its product offerings focus on the modern development experience: serverless architecture, branching, unlimited storage, and more!</description><content:encoded><![CDATA[<p>Hosting a free PostgreSQL database for side projects, MVPs, learning, etc. is easy with free tiers provided by following services in this article.</p>
<p>The following list is not comprehensive nor in any specific order.</p>
<h2 id="top-free-postgresql-database-hosting-online">Top free PostgreSQL database hosting online</h2>
<p>Here are the top free PostgreSQL database online hosting services:</p>
<h3 id="neon">Neon</h3>
<p><a href="https://neon.tech/docs/introduction/technical-preview-free-tier">Neon</a> provides a generous free tier for a fully managed PostgreSQL database. Its product offerings focus on the modern development experience: serverless architecture, branching, unlimited storage, and more!</p>
<p><strong>Free tier:</strong></p>
<ul>
<li>1 project</li>
<li>10 branches</li>
<li>3 GB of data per branch</li>
<li>A shared compute with 1 GB of RAM</li>
<li>Auto-suspend compute</li>
</ul>
<p>Click <a href="https://neon.tech/docs/introduction/technical-preview-free-tier">here</a> for more information about the free tier.</p>
<h3 id="supabase">Supabase</h3>
<p><a href="https://supabase.com/pricing">Supabase</a> provides a PostgreSQL database with APIs, real-time WebSocket interaction, and user authentication out-of-the-box. It enables for fast development by making backend straightforward while allowing developers to focus on what matters: building business logic.</p>
<p><strong>Free tier:</strong></p>
<ul>
<li>Up to 500MB database &amp; 1GB file storage</li>
<li>Up to 2GB bandwidth</li>
<li>Up to 50MB file uploads</li>
<li>Social OAuth providers</li>
<li>50,000 monthly active users</li>
<li>Up to 500K Edge Function invocations</li>
<li>1-day log retention</li>
<li>Community support</li>
</ul>
<p>Click <a href="https://supabase.com/pricing">here</a> for more information about the free tier.</p>
<h3 id="elephantsql">ElephantSQL</h3>
<p><a href="https://www.elephantsql.com/plans.html">ElephantSQL</a> is dubbed &ldquo;PostgreSQL as a Service&rdquo;. This service provides fully-managed highly-available PostgreSQL databases that can be configured in minutes.</p>
<p><strong>Free tier:</strong></p>
<ul>
<li>Shared high performance server</li>
<li>20 MB data</li>
<li>5 concurrent connections</li>
</ul>
<p>Click <a href="https://www.elephantsql.com/plans.html">here</a> for more information about the free tier.</p>
<h3 id="amazon-rds">Amazon RDS</h3>
<p><a href="https://aws.amazon.com/free/database/">Amazon Web Services</a> provides a free database tier for 12 months with Amazon RDS. AWS is an industry standard.</p>
<p><strong>Free tier:</strong></p>
<ul>
<li>12 months free</li>
<li>750 hours per month of db.t2.micro, db.t3.micro, and db.t4g.micro</li>
<li>20 GB of general purpose (SSD) database storage</li>
<li>20 GB of storage for database backups and database snapshots</li>
</ul>
<p>Click <a href="https://aws.amazon.com/free/database/">here</a> for more information about the free tier.</p>
<h2 id="summary">Summary</h2>
<p>This article presented 4 free solutions for PostgreSQL:</p>
<ul>
<li>Neon</li>
<li>Supabase</li>
<li>ElephantSQL</li>
<li>Amazon RDS</li>
</ul>
<p>If there are more, please feel free to leave a comment below.</p>
]]></content:encoded></item><item><title>Find all files containing a specific text or pattern on Linux</title><link>https://how.wtf/find-all-files-containing-a-specific-text-or-pattern-on-linux.html</link><pubDate>Wed, 26 Apr 2023 00:40:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/find-all-files-containing-a-specific-text-or-pattern-on-linux.html</guid><description>Searching for a specific text or pattern across multiple files can be completed using grep.
Using grep to search file contents grep provides searching functionality out-of-the-box:
1grep -rnw &amp;#39;/path/to/directory&amp;#39; -e &amp;#39;pattern&amp;#39;Here are a breakdown of the grep options:
-r for recursiveness -n for line number -w for matching the whole word -e is the pattern used for searching The command will output the file names and text containing the pattern. If the goal is simply to display the filenames themselves, add the -l flag.</description><content:encoded><![CDATA[<p>Searching for a specific text or pattern across multiple files can be completed using <code>grep</code>.</p>
<h2 id="using-grep-to-search-file-contents">Using <code>grep</code> to search file contents</h2>
<p><code>grep</code> provides searching functionality out-of-the-box:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">grep -rnw <span class="s1">&#39;/path/to/directory&#39;</span> -e <span class="s1">&#39;pattern&#39;</span></span></span></code></pre></div><p>Here are a breakdown of the <code>grep</code> options:</p>
<ul>
<li><code>-r</code> for recursiveness</li>
<li><code>-n</code> for line number</li>
<li><code>-w</code> for matching the whole word</li>
<li><code>-e</code> is the pattern used for searching</li>
</ul>
<p>The command will output the file names and text containing the pattern. If the goal is simply to display the filenames themselves, add the <code>-l</code> flag.:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">grep -rlnw <span class="s1">&#39;/path/to/directory&#39;</span> -e <span class="s1">&#39;pattern&#39;</span></span></span></code></pre></div><p>If binary files need to be omitted, add the <code>-I</code> flag.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">grep -rlnwI <span class="s1">&#39;/path/to/directory&#39;</span> -e <span class="s1">&#39;pattern&#39;</span></span></span></code></pre></div><p>In addition, the <code>--exclude</code>, <code>--include</code>, and <code>--exclude-dir</code> may be used in combination.</p>
<p><strong>Example:</strong> Excluding <code>dir1</code> and <code>dir2</code>, find all <code>html</code> or <code>javascript</code> files with the filter of <code>p</code> in them.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">grep <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --include<span class="o">=</span><span class="se">\*</span>.<span class="o">{</span>html,js<span class="o">}</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --exclude-dir<span class="o">={</span>dir1,dir2<span class="o">}</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>  -rlnwI <span class="s1">&#39;/path/to/directory&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>  -e <span class="s2">&#34;p&#34;</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Write jq output to a file</title><link>https://how.wtf/write-jq-output-to-a-file.html</link><pubDate>Tue, 25 Apr 2023 00:35:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/write-jq-output-to-a-file.html</guid><description>If a user wants to write jq output to a file, the solution is simple.
jq output to a file Extract all project ids from the following json payload to a text file:
1{ 2 &amp;#34;projects&amp;#34;: [ 3 { 4 &amp;#34;id&amp;#34;: 1 5 }, 6 { 7 &amp;#34;id&amp;#34;: 2 8 } 9 ] 10} 1echo &amp;#39;{&amp;#34;projects&amp;#34;: [{&amp;#34;id&amp;#34;: 1}, {&amp;#34;id&amp;#34;: 2}]}&amp;#39; | jq &amp;#39;.projects[].id&amp;#39; &amp;gt; ids.txtOutput: ids.txt:
11 22Using the redirection operator (&amp;gt;), the jq results are written to a file.</description><content:encoded><![CDATA[<p>If a user wants to write <code>jq</code> output to a file, the solution is simple.</p>
<h2 id="jq-output-to-a-file"><code>jq</code> output to a file</h2>
<p>Extract all project ids from the following <code>json</code> payload to a text file:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;projects&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="p">{</span> 
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">      <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span> 
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="p">{</span> 
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">      <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">2</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;{&#34;projects&#34;: [{&#34;id&#34;: 1}, {&#34;id&#34;: 2}]}&#39;</span> <span class="p">|</span> jq <span class="s1">&#39;.projects[].id&#39;</span> &gt; ids.txt</span></span></code></pre></div><p>Output: <code>ids.txt</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">1
</span></span><span class="line"><span class="ln">2</span><span class="cl">2</span></span></code></pre></div><p>Using the redirection operator (<code>&gt;</code>), the <code>jq</code> results are written to a file.</p>
]]></content:encoded></item><item><title>Python title method in JavaScript</title><link>https://how.wtf/python-title-method-in-javascript.html</link><pubDate>Sun, 23 Apr 2023 23:25:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/python-title-method-in-javascript.html</guid><description>What is the equivalent for the Python string title method in JavaScript? Python&amp;rsquo;s native str.title() method returns a string with title-casing— i.e. the first letter of each word is capitalized.
str.title() method in JavaScript Unfortunately, JavaScript does not contain a standardized str.title() method; however, a function can be created that implements equivalent behavior.
In Python, here are a few examples of the str.title() method:
1print(&amp;#34;WeIrD cAsInG&amp;#34;.title()) # Weird Casing 2print(&amp;#34;HELLO WORLD&amp;#34;.</description><content:encoded><![CDATA[<p>What is the equivalent for the Python string <code>title</code> method in JavaScript? Python&rsquo;s native <code>str.title()</code> method returns a string with title-casing— i.e. the first letter of each word is capitalized.</p>
<h2 id="strtitle-method-in-javascript"><code>str.title()</code> method in JavaScript</h2>
<p>Unfortunately, JavaScript does not contain a standardized <code>str.title()</code> method; however, a function can be created that implements equivalent behavior.</p>
<p>In Python, here are a few examples of the <code>str.title()</code> method:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;WeIrD cAsInG&#34;</span><span class="o">.</span><span class="n">title</span><span class="p">())</span> <span class="c1"># Weird Casing</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;HELLO WORLD&#34;</span><span class="o">.</span><span class="n">title</span><span class="p">())</span> <span class="c1"># Hello World</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;nospaceHERE&#34;</span><span class="o">.</span><span class="n">title</span><span class="p">())</span> <span class="c1"># Nospacehere</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;there&#39;s a snake in my boot&#34;</span><span class="o">.</span><span class="n">title</span><span class="p">())</span> <span class="c1"># There&#39;S A Snake In My Boot</span></span></span></code></pre></div><p>This is an equivalent JavaScript implementation:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="kd">function</span> <span class="nx">title</span><span class="p">(</span><span class="nx">str</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="k">return</span> <span class="nx">str</span><span class="p">.</span><span class="nx">toLowerCase</span><span class="p">().</span><span class="nx">split</span><span class="p">(</span><span class="s1">&#39; &#39;</span><span class="p">).</span><span class="nx">map</span><span class="p">(</span><span class="nx">w</span> <span class="p">=&gt;</span> <span class="nx">w</span><span class="p">.</span><span class="nx">charAt</span><span class="p">(</span><span class="mi">0</span><span class="p">).</span><span class="nx">toUpperCase</span><span class="p">()</span> <span class="o">+</span> <span class="nx">w</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">1</span><span class="p">)).</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39; &#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">title</span><span class="p">(</span><span class="s2">&#34;WeIrD cAsInG&#34;</span><span class="p">));</span> <span class="c1">// Weird Casing
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">title</span><span class="p">(</span><span class="s2">&#34;HELLO WORLD&#34;</span><span class="p">));</span> <span class="c1">// Hello World
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">title</span><span class="p">(</span><span class="s2">&#34;nospaceHERE&#34;</span><span class="p">));</span> <span class="c1">// Nospacehere
</span></span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">title</span><span class="p">(</span><span class="s2">&#34;there&#39;s a snake in my boot&#34;</span><span class="p">));</span> <span class="c1">// There&#39;S A Snake In My Boot
</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Deep clone an object in JavaScript</title><link>https://how.wtf/deep-clone-an-object-in-javascript.html</link><pubDate>Sat, 22 Apr 2023 22:15:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/deep-clone-an-object-in-javascript.html</guid><description>Deep cloning an object in JavaScript was natively added in Node 17.
Deep clone an object using structuredClone Deepling cloning an object is completed using structuredClone.
1const a = { 2 col1: &amp;#39;val1&amp;#39;, 3 col2: { 4 nestedObjected: { 5 col1: &amp;#39;val1&amp;#39; 6 } 7 } 8} 9 10const b = structuredClone(a); 11console.log(b); 12// {&amp;#34;col1&amp;#34;:&amp;#34;val1&amp;#34;,&amp;#34;col2&amp;#34;:{&amp;#34;nestedObjected&amp;#34;:{&amp;#34;col1&amp;#34;:&amp;#34;val1&amp;#34;}}} Deep clone an object using JSON If the structuredClone method is not available and the user does not want to add an external library, using JSON may satisfy the requirement.</description><content:encoded><![CDATA[<p>Deep cloning an object in JavaScript was natively added in <a href="https://developer.mozilla.org/en-US/docs/Web/API/structuredClone#browser_compatibility">Node 17</a>.</p>
<h2 id="deep-clone-an-object-using-structuredclone">Deep clone an object using <code>structuredClone</code></h2>
<p>Deepling cloning an object is completed using <code>structuredClone</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kr">const</span> <span class="nx">a</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nx">col1</span><span class="o">:</span> <span class="s1">&#39;val1&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  <span class="nx">col2</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">      <span class="nx">nestedObjected</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">          <span class="nx">col1</span><span class="o">:</span> <span class="s1">&#39;val1&#39;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="kr">const</span> <span class="nx">b</span> <span class="o">=</span> <span class="nx">structuredClone</span><span class="p">(</span><span class="nx">a</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">b</span><span class="p">);</span> 
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1">// {&#34;col1&#34;:&#34;val1&#34;,&#34;col2&#34;:{&#34;nestedObjected&#34;:{&#34;col1&#34;:&#34;val1&#34;}}}
</span></span></span></code></pre></div><h2 id="deep-clone-an-object-using-json">Deep clone an object using <code>JSON</code></h2>
<p>If the <code>structuredClone</code> method is not available and the user does <em>not</em> want to add an external library, using <code>JSON</code> may satisfy the requirement. If the following types are not used:</p>
<ul>
<li><code>Date</code></li>
<li><code>undefined</code></li>
<li><code>Infinity</code></li>
<li>Regular expressions</li>
<li>Maps</li>
<li>Sets</li>
<li>Blobs</li>
<li>other compex types within an object</li>
</ul>
<p>a simple one liner may be sufficient.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kr">const</span> <span class="nx">a</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nx">col1</span><span class="o">:</span> <span class="s1">&#39;val1&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  <span class="nx">col2</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">      <span class="nx">nestedObjected</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">          <span class="nx">col1</span><span class="o">:</span> <span class="s1">&#39;val1&#39;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="kr">const</span> <span class="nx">b</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">a</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">b</span><span class="p">);</span> 
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1">// {&#34;col1&#34;:&#34;val1&#34;,&#34;col2&#34;:{&#34;nestedObjected&#34;:{&#34;col1&#34;:&#34;val1&#34;}}}
</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Search across all object values in an array in JavaScript</title><link>https://how.wtf/search-across-all-object-values-in-an-array-in-javascript.html</link><pubDate>Sat, 22 Apr 2023 11:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/search-across-all-object-values-in-an-array-in-javascript.html</guid><description>If there is a need to search across all object values in an array in JavaScript, a combination of filter, entries, and some can be used.
How to search across object values In a frontend data table, rows may contain information about people:
1const people = [ 2 { 3 &amp;#34;id&amp;#34;: 5, 4 &amp;#34;firstName&amp;#34;: &amp;#34;Buzz&amp;#34;, 5 &amp;#34;lastName&amp;#34;: &amp;#34;Lightyear2&amp;#34; 6 }, 7 { 8 &amp;#34;id&amp;#34;: 2, 9 &amp;#34;firstName&amp;#34;: &amp;#34;Buzz&amp;#34;, 10 &amp;#34;lastName&amp;#34;: &amp;#34;Lightyear&amp;#34; 11 }, 12 { 13 &amp;#34;id&amp;#34;: 1, 14 &amp;#34;firstName&amp;#34;: &amp;#34;Woody&amp;#34;, 15 &amp;#34;lastName&amp;#34;: &amp;#34;Pride&amp;#34; 16 }, 17 { 18 &amp;#34;id&amp;#34;: 3, 19 &amp;#34;firstName&amp;#34;: &amp;#34;Potato&amp;#34;, 20 &amp;#34;lastName&amp;#34;: &amp;#34;Head&amp;#34; 21 }, 22 { 23 &amp;#34;id&amp;#34;: 4, 24 &amp;#34;firstName&amp;#34;: &amp;#34;Slinky&amp;#34;, 25 &amp;#34;lastName&amp;#34;: &amp;#34;Dog&amp;#34; 26 } 27];To provide a &amp;ldquo;search&amp;rdquo; across all of the values, use the following:</description><content:encoded><![CDATA[<p>If there is a need to search across all object values in an array in JavaScript, a combination of <code>filter</code>, <code>entries</code>, and <code>some</code> can be used.</p>
<h2 id="how-to-search-across-object-values">How to search across object values</h2>
<p>In a frontend data table, rows may contain information about people:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kr">const</span> <span class="nx">people</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="s2">&#34;id&#34;</span><span class="o">:</span> <span class="mi">5</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="s2">&#34;firstName&#34;</span><span class="o">:</span> <span class="s2">&#34;Buzz&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="s2">&#34;lastName&#34;</span><span class="o">:</span> <span class="s2">&#34;Lightyear2&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="s2">&#34;id&#34;</span><span class="o">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="s2">&#34;firstName&#34;</span><span class="o">:</span> <span class="s2">&#34;Buzz&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="s2">&#34;lastName&#34;</span><span class="o">:</span> <span class="s2">&#34;Lightyear&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="s2">&#34;id&#34;</span><span class="o">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="s2">&#34;firstName&#34;</span><span class="o">:</span> <span class="s2">&#34;Woody&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="s2">&#34;lastName&#34;</span><span class="o">:</span> <span class="s2">&#34;Pride&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="s2">&#34;id&#34;</span><span class="o">:</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="s2">&#34;firstName&#34;</span><span class="o">:</span> <span class="s2">&#34;Potato&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="s2">&#34;lastName&#34;</span><span class="o">:</span> <span class="s2">&#34;Head&#34;</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">    <span class="s2">&#34;id&#34;</span><span class="o">:</span> <span class="mi">4</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">    <span class="s2">&#34;firstName&#34;</span><span class="o">:</span> <span class="s2">&#34;Slinky&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="s2">&#34;lastName&#34;</span><span class="o">:</span> <span class="s2">&#34;Dog&#34;</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="p">];</span></span></span></code></pre></div><p>To provide a &ldquo;search&rdquo; across all of the values, use the following:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="kr">const</span> <span class="nx">query</span> <span class="o">=</span> <span class="s2">&#34;Slinky&#34;</span><span class="p">.</span><span class="nx">toLowerCase</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kr">const</span> <span class="nx">results</span> <span class="o">=</span> <span class="nx">people</span><span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="nx">o</span> <span class="p">=&gt;</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">entries</span><span class="p">(</span><span class="nx">o</span><span class="p">).</span><span class="nx">some</span><span class="p">(</span><span class="nx">e</span> <span class="p">=&gt;</span> <span class="nb">String</span><span class="p">(</span><span class="nx">e</span><span class="p">[</span><span class="mi">1</span><span class="p">]).</span><span class="nx">toLowerCase</span><span class="p">().</span><span class="nx">includes</span><span class="p">(</span><span class="nx">query</span><span class="p">)));</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">results</span><span class="p">);</span> <span class="c1">// [ { id: 4, firstName: &#39;Slinky&#39;, lastName: &#39;Dog&#39; } ]
</span></span></span></code></pre></div><p>If <code>id</code> or other fields are not preferable in the search, use the <code>rest</code> operator.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="kr">const</span> <span class="nx">query</span> <span class="o">=</span> <span class="s2">&#34;Slinky&#34;</span><span class="p">.</span><span class="nx">toLowerCase</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kr">const</span> <span class="nx">results</span> <span class="o">=</span> <span class="nx">people</span><span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="nx">o</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="kr">const</span> <span class="p">{</span> <span class="nx">id</span><span class="p">,</span> <span class="p">...</span><span class="nx">rest</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">o</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="k">return</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">entries</span><span class="p">(</span><span class="nx">rest</span><span class="p">).</span><span class="nx">some</span><span class="p">(</span><span class="nx">e</span> <span class="p">=&gt;</span> <span class="nb">String</span><span class="p">(</span><span class="nx">e</span><span class="p">[</span><span class="mi">1</span><span class="p">]).</span><span class="nx">toLowerCase</span><span class="p">().</span><span class="nx">includes</span><span class="p">(</span><span class="nx">query</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">results</span><span class="p">);</span> <span class="c1">// [ { id: 4, firstName: &#39;Slinky&#39;, lastName: &#39;Dog&#39; } ]
</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Sort array of objects by single or multiple keys in JavaScript</title><link>https://how.wtf/sort-array-of-objects-by-single-or-multiple-keys-in-javascript.html</link><pubDate>Thu, 20 Apr 2023 23:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/sort-array-of-objects-by-single-or-multiple-keys-in-javascript.html</guid><description>In TypeScript or JavaScript, sorting an array of objects is made easy in ES6/ES2015.
Given an array of objects named people, sort them based on different criteria.
1const people = [ 2 { 3 &amp;#34;id&amp;#34;: 5, 4 &amp;#34;firstName&amp;#34;: &amp;#34;Buzz&amp;#34;, 5 &amp;#34;lastName&amp;#34;: &amp;#34;Lightyear2&amp;#34; 6 }, 7 { 8 &amp;#34;id&amp;#34;: 2, 9 &amp;#34;firstName&amp;#34;: &amp;#34;Buzz&amp;#34;, 10 &amp;#34;lastName&amp;#34;: &amp;#34;Lightyear&amp;#34; 11 }, 12 { 13 &amp;#34;id&amp;#34;: 1, 14 &amp;#34;firstName&amp;#34;: &amp;#34;Woody&amp;#34;, 15 &amp;#34;lastName&amp;#34;: &amp;#34;Pride&amp;#34; 16 }, 17 { 18 &amp;#34;id&amp;#34;: 3, 19 &amp;#34;firstName&amp;#34;: &amp;#34;Potato&amp;#34;, 20 &amp;#34;lastName&amp;#34;: &amp;#34;Head&amp;#34; 21 }, 22 { 23 &amp;#34;id&amp;#34;: 4, 24 &amp;#34;firstName&amp;#34;: &amp;#34;Slinky&amp;#34;, 25 &amp;#34;lastName&amp;#34;: &amp;#34;Dog&amp;#34; 26 } 27];Sorting an array of objects by a single key Sort ascending by number 1// sort ascending by id 2people.</description><content:encoded><![CDATA[<p>In TypeScript or JavaScript, sorting an array of objects is made easy in ES6/ES2015.</p>
<p>Given an array of objects named <code>people</code>, sort them based on different criteria.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kr">const</span> <span class="nx">people</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="s2">&#34;id&#34;</span><span class="o">:</span> <span class="mi">5</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="s2">&#34;firstName&#34;</span><span class="o">:</span> <span class="s2">&#34;Buzz&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="s2">&#34;lastName&#34;</span><span class="o">:</span> <span class="s2">&#34;Lightyear2&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="s2">&#34;id&#34;</span><span class="o">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="s2">&#34;firstName&#34;</span><span class="o">:</span> <span class="s2">&#34;Buzz&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="s2">&#34;lastName&#34;</span><span class="o">:</span> <span class="s2">&#34;Lightyear&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="s2">&#34;id&#34;</span><span class="o">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="s2">&#34;firstName&#34;</span><span class="o">:</span> <span class="s2">&#34;Woody&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="s2">&#34;lastName&#34;</span><span class="o">:</span> <span class="s2">&#34;Pride&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="s2">&#34;id&#34;</span><span class="o">:</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="s2">&#34;firstName&#34;</span><span class="o">:</span> <span class="s2">&#34;Potato&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="s2">&#34;lastName&#34;</span><span class="o">:</span> <span class="s2">&#34;Head&#34;</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">    <span class="s2">&#34;id&#34;</span><span class="o">:</span> <span class="mi">4</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">    <span class="s2">&#34;firstName&#34;</span><span class="o">:</span> <span class="s2">&#34;Slinky&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="s2">&#34;lastName&#34;</span><span class="o">:</span> <span class="s2">&#34;Dog&#34;</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="p">];</span></span></span></code></pre></div><h2 id="sorting-an-array-of-objects-by-a-single-key">Sorting an array of objects by a single key</h2>
<h3 id="sort-ascending-by-number">Sort ascending by number</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// sort ascending by id
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="nx">people</span><span class="p">.</span><span class="nx">sort</span><span class="p">((</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">a</span><span class="p">.</span><span class="nx">id</span> <span class="o">-</span> <span class="nx">b</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span></span></span></code></pre></div><h3 id="sort-ascending-by-string">Sort ascending by string</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// sort ascending by firstName
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="nx">people</span><span class="p">.</span><span class="nx">sort</span><span class="p">((</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">a</span><span class="p">.</span><span class="nx">firstName</span><span class="p">.</span><span class="nx">localeCompare</span><span class="p">(</span><span class="nx">b</span><span class="p">.</span><span class="nx">firstName</span><span class="p">))</span></span></span></code></pre></div><h3 id="sort-descending-by-number">Sort descending by number</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// sort descending by id
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="nx">people</span><span class="p">.</span><span class="nx">sort</span><span class="p">((</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">b</span><span class="p">.</span><span class="nx">id</span> <span class="o">-</span> <span class="nx">a</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span></span></span></code></pre></div><h3 id="sort-descending-by-string">Sort descending by string</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// sort descending by firstName
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="nx">people</span><span class="p">.</span><span class="nx">sort</span><span class="p">((</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">b</span><span class="p">.</span><span class="nx">firstName</span><span class="p">.</span><span class="nx">localeCompare</span><span class="p">(</span><span class="nx">a</span><span class="p">.</span><span class="nx">firstName</span><span class="p">))</span></span></span></code></pre></div><h2 id="sorting-array-of-objects-by-multiple-keys">Sorting array of objects by multiple keys</h2>
<p>If a secondary key is needed for additional sorting, the same <code>sort</code> method can be used.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="nx">people</span><span class="p">.</span><span class="nx">sort</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">a</span><span class="p">.</span><span class="nx">firstName</span><span class="p">.</span><span class="nx">localeCompare</span><span class="p">(</span><span class="nx">b</span><span class="p">.</span><span class="nx">firstName</span><span class="p">)</span> <span class="o">||</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nx">a</span><span class="p">.</span><span class="nx">lastName</span><span class="p">.</span><span class="nx">localeCompare</span><span class="p">(</span><span class="nx">b</span><span class="p">.</span><span class="nx">lastName</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">);</span></span></span></code></pre></div><p>the or logical operator <code>||</code> chains multiple sort options.</p>
]]></content:encoded></item><item><title>Function and method overloading in TypeScript</title><link>https://how.wtf/function-and-method-overloading-in-typescript.html</link><pubDate>Wed, 19 Apr 2023 23:55:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/function-and-method-overloading-in-typescript.html</guid><description>In Typescript, the declaration of an overload is defined by writing overload signatures.
To do this, write some number of function signatures (usually two or more), followed by the body of the function
Be aware that the implementation signature type should be generic enough to include the overload signatures.
For example, an improper implementation signature:
1function fn(x: string): string; 2// Return type isn&amp;#39;t right 3function fn(x: number): boolean; 4// This overload signature is not compatible with its implementation signature.</description><content:encoded><![CDATA[<p>In Typescript, the declaration of an  <code>overload</code>  is defined by writing <a href="https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads">overload signatures</a>.</p>
<blockquote>
<p>To do this, write some number of function signatures (usually two or more), followed by the body of the function</p>
</blockquote>
<p>Be aware that the implementation signature type should be generic enough to include the overload signatures.</p>
<p>For example, an improper implementation signature:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="ln">1</span><span class="cl"><span class="kd">function</span> <span class="nx">fn</span><span class="p">(</span><span class="nx">x</span>: <span class="kt">string</span><span class="p">)</span><span class="o">:</span> <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1">// Return type isn&#39;t right
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"></span><span class="kd">function</span> <span class="nx">fn</span><span class="p">(</span><span class="nx">x</span>: <span class="kt">number</span><span class="p">)</span><span class="o">:</span> <span class="kr">boolean</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1">// This overload signature is not compatible with its implementation signature.
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1"></span><span class="kd">function</span> <span class="nx">fn</span><span class="p">(</span><span class="nx">x</span>: <span class="kt">string</span> <span class="o">|</span> <span class="kt">number</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">  <span class="k">return</span>  <span class="s2">&#34;oops&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="function-overloading">Function overloading</h2>
<p>Define a <code>speak</code> function that accepts a <code>string</code> or a <code>number</code> in the signature.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kd">function</span> <span class="nx">speak</span><span class="p">(</span><span class="nx">message</span>: <span class="kt">string</span><span class="p">)</span><span class="o">:</span> <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kd">function</span> <span class="nx">speak</span><span class="p">(</span><span class="nx">num</span>: <span class="kt">number</span><span class="p">)</span><span class="o">:</span> <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kd">function</span> <span class="nx">speak</span><span class="p">(</span><span class="nx">m</span>: <span class="kt">unknown</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">m</span> <span class="o">===</span> <span class="s1">&#39;string&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="k">return</span> <span class="nx">m</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">  <span class="p">}</span> <span class="k">else</span>  <span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">m</span> <span class="o">===</span> <span class="s1">&#39;number&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="k">return</span>  <span class="sb">`</span><span class="si">${</span><span class="nx">m</span><span class="si">}</span><span class="sb">`</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">  <span class="k">throw</span>  <span class="k">new</span>  <span class="nb">Error</span><span class="p">(</span><span class="s1">&#39;Unable to greet&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">speak</span><span class="p">(</span><span class="mi">15</span><span class="p">));</span> <span class="c1">// &#34;15&#34;
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">speak</span><span class="p">(</span><span class="s2">&#34;a message&#34;</span><span class="p">));</span> <span class="c1">// &#34;a message&#34;
</span></span></span></code></pre></div><p>In the implementation signature, <code>m</code> is of value <code>unknown</code> and covers <em>both</em> overloaded signatures.</p>
<h2 id="method-overloading">Method overloading</h2>
<p>Using the same technique as before, the <code>speak</code> method can be included in a class.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kr">class</span>  <span class="nx">Speaker</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nx">speak</span><span class="p">(</span><span class="nx">message</span>: <span class="kt">string</span><span class="p">)</span><span class="o">:</span> <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  <span class="nx">speak</span><span class="p">(</span><span class="nx">num</span>: <span class="kt">number</span><span class="p">)</span><span class="o">:</span> <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="nx">speak</span><span class="p">(</span><span class="nx">m</span>: <span class="kt">unknown</span><span class="p">)</span><span class="o">:</span> <span class="kt">unknown</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">m</span> <span class="o">===</span> <span class="s1">&#39;string&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">      <span class="k">return</span> <span class="nx">m</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="p">}</span> <span class="k">else</span>  <span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">m</span> <span class="o">===</span> <span class="s1">&#39;number&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">      <span class="k">return</span>  <span class="sb">`</span><span class="si">${</span><span class="nx">m</span><span class="si">}</span><span class="sb">`</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="k">throw</span>  <span class="k">new</span>  <span class="nb">Error</span><span class="p">(</span><span class="s1">&#39;Unable to greet&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">new</span>  <span class="nx">Speaker</span><span class="p">().</span><span class="nx">speak</span><span class="p">(</span><span class="mi">15</span><span class="p">));</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">new</span>  <span class="nx">Speaker</span><span class="p">().</span><span class="nx">speak</span><span class="p">(</span><span class="s2">&#34;a message&#34;</span><span class="p">));</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Dynamic variable names in Bash</title><link>https://how.wtf/dynamic-variable-names-in-bash.html</link><pubDate>Tue, 18 Apr 2023 23:50:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/dynamic-variable-names-in-bash.html</guid><description>In Bash, dynamic variables can be created using indirect expansion.
How to create a dynamic variable name In a CI container, there may be a need to delineate between different environment variable values using a prefix for a variable name.
1#!/bin/sh 2# In the container at runtime: 3# export PROD_TOKEN=&amp;#34;123&amp;#34; 4env=&amp;#34;PROD&amp;#34; 5secret=&amp;#34;${env}_TOKEN&amp;#34; 6echo ${!secret}Output:
1123In the example above, the secret value is PROD_TOKEN after expansion. Using indirect expansion, ${!secret} references 123.</description><content:encoded><![CDATA[<p>In Bash, dynamic variables can be created using indirect <a href="https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Parameter-Expansion">expansion</a>.</p>
<h2 id="how-to-create-a-dynamic-variable-name">How to create a dynamic variable name</h2>
<p>In a CI container, there may be a need to delineate between different environment variable values using a prefix for a variable name.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="cp">#!/bin/sh
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="cp"></span><span class="c1"># In the container at runtime:</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"># export PROD_TOKEN=&#34;123&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nv">env</span><span class="o">=</span><span class="s2">&#34;PROD&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="nv">secret</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">env</span><span class="si">}</span><span class="s2">_TOKEN&#34;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="p">!secret</span><span class="si">}</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">123</span></span></code></pre></div><p>In the example above, the <code>secret</code> value is <code>PROD_TOKEN</code> after expansion. Using indirect expansion, <code>${!secret}</code> references <code>123</code>.</p>
]]></content:encoded></item><item><title>Parallel commands in Bash</title><link>https://how.wtf/parallel-commands-in-bash.html</link><pubDate>Mon, 17 Apr 2023 23:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/parallel-commands-in-bash.html</guid><description>Bash natively supports a wait command.
Run parallel processes Using default wait behavior By default, wait will wait for all child processes to complete before continuing an execution. For most cases, this is sufficient.
1sleep 2 &amp;amp;&amp;amp; echo &amp;#34;hi&amp;#34; &amp;amp; 2sleep 2 &amp;amp;&amp;amp; echo &amp;#34;hi2&amp;#34; &amp;amp; 3 4# Wait for child processes to finish 5waitUsing the &amp;amp; character at the ending of a line sends the process to the background to complete.</description><content:encoded><![CDATA[<p>Bash natively supports a <code>wait</code> command.</p>
<h2 id="run-parallel-processes">Run parallel processes</h2>
<h3 id="using-default-wait-behavior">Using default <code>wait</code> behavior</h3>
<p>By default, <code>wait</code> will wait for all child processes to complete before continuing an execution. For most cases, this is sufficient.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">sleep <span class="m">2</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;hi&#34;</span> <span class="p">&amp;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">sleep <span class="m">2</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;hi2&#34;</span> <span class="p">&amp;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># Wait for child processes to finish</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">wait</span></span></code></pre></div><p>Using the <code>&amp;</code> character at the ending of a line sends the process to the background to complete. Without <code>wait</code>, the the script would end.</p>
<p>The script will complete in 2 seconds.</p>
<p>Output variation 1:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">hi
</span></span><span class="line"><span class="ln">2</span><span class="cl">hi2</span></span></code></pre></div><p>Output variation 2:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">hi2
</span></span><span class="line"><span class="ln">2</span><span class="cl">hi</span></span></code></pre></div><h3 id="using-wait-with-process-ids">Using <code>wait</code> with process ids</h3>
<p><code>wait</code> allows for a process id argument value. This may be useful for establishing chained <code>wait</code>s.</p>
<p>In the example below, the &ldquo;hi3&rdquo; task depends on &ldquo;hi&rdquo;; however &ldquo;hi2&rdquo; may run in parallel with &ldquo;hi&rdquo;.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl">sleep <span class="m">2</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;hi&#34;</span> <span class="p">&amp;</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nv">hi_pid</span><span class="o">=</span><span class="nv">$!</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># &#34;hi2&#34; does not require &#34;hi&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">sleep <span class="m">2</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;hi2&#34;</span> <span class="p">&amp;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nb">wait</span> <span class="nv">$hi_pid</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"># &#34;hi3&#34; requires &#34;hi&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">sleep <span class="m">2</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;hi3&#34;</span> <span class="p">&amp;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl">wait</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">hi2
</span></span><span class="line"><span class="ln">2</span><span class="cl">hi
</span></span><span class="line"><span class="ln">3</span><span class="cl">hi3</span></span></code></pre></div><p>The process id of the last execution is returned using <code>$!</code>.</p>
]]></content:encoded></item><item><title>Return a string from a function in Bash</title><link>https://how.wtf/return-a-string-from-a-function-in-bash.html</link><pubDate>Sun, 16 Apr 2023 23:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/return-a-string-from-a-function-in-bash.html</guid><description>Bash allows returning status codes (integers) from functions; however, how can a string be returned?
Returning a string from a function In Bash, command substitution can be used to capture the stdout of a function.
1f(){ 2 local var=&amp;#34;test&amp;#34; 3 echo $var 4} 5 6result=$(f) 7echo &amp;#34;f returned $result&amp;#34;Output
1f returned testReturning a string and status from a function If the standard output and status code need capturing, the example above can be modified to include a return status.</description><content:encoded><![CDATA[<p>Bash allows returning status codes (integers) from functions; however, how can a string be returned?</p>
<h2 id="returning-a-string-from-a-function">Returning a string from a function</h2>
<p>In Bash, command substitution can be used to capture the stdout of a function.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">f<span class="o">(){</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nb">local</span> <span class="nv">var</span><span class="o">=</span><span class="s2">&#34;test&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nb">echo</span> <span class="nv">$var</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nv">result</span><span class="o">=</span><span class="k">$(</span>f<span class="k">)</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;f returned </span><span class="nv">$result</span><span class="s2">&#34;</span></span></span></code></pre></div><p>Output</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">f returned test</span></span></code></pre></div><h2 id="returning-a-string-and-status-from-a-function">Returning a string and status from a function</h2>
<p>If the standard output and status code need capturing, the example above can be modified to include a return status.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">f<span class="o">(){</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nb">local</span> <span class="nv">var</span><span class="o">=</span><span class="s2">&#34;test&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nb">echo</span> <span class="nv">$var</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="k">return</span> <span class="m">10</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="nv">result</span><span class="o">=</span><span class="k">$(</span>f<span class="k">)</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="nv">status</span><span class="o">=</span><span class="nv">$?</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;f returned </span><span class="nv">$result</span><span class="s2"> with status code </span><span class="nv">$status</span><span class="s2">&#34;</span></span></span></code></pre></div><p>Output</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">f returned test with status code 10</span></span></code></pre></div>]]></content:encoded></item><item><title>jq starts with query</title><link>https://how.wtf/jq-starts-with-query.html</link><pubDate>Sat, 15 Apr 2023 23:58:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/jq-starts-with-query.html</guid><description>If a user wants to search a json payload using a starts_with or “begins with” or “has prefix” query, jq natively supports it.
How to query using startswith Given a json array, searching for a specific string that startswith a prefix is easy.
1{ 2 &amp;#34;people&amp;#34;: [ 3 { 4 &amp;#34;firstName&amp;#34;: &amp;#34;thomas&amp;#34;, 5 &amp;#34;age&amp;#34;: 25 6 }, 7 { 8 &amp;#34;firstName&amp;#34;: &amp;#34;sally&amp;#34;, 9 &amp;#34;age&amp;#34;: 28 10 } 11 ] 12}Find each person if their name begins with sal.</description><content:encoded><![CDATA[<p>If a user wants to search a <code>json</code> payload using a <code>starts_with</code> or “begins with” or “has prefix” query, <code>jq</code> natively supports it.</p>
<h2 id="how-to-query-using--startswith">How to query using  <code>startswith</code></h2>
<p>Given a <code>json</code> array, searching for a specific string that <code>startswith</code> a prefix is easy.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;people&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">      <span class="nt">&#34;firstName&#34;</span><span class="p">:</span> <span class="s2">&#34;thomas&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">      <span class="nt">&#34;age&#34;</span><span class="p">:</span> <span class="mi">25</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">      <span class="nt">&#34;firstName&#34;</span><span class="p">:</span> <span class="s2">&#34;sally&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">      <span class="nt">&#34;age&#34;</span><span class="p">:</span> <span class="mi">28</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Find each person if their name begins with <code>sal</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">jq -r <span class="s1">&#39;.people[]|select(.firstName | startswith(&#34;sal&#34;))&#39;</span> people.json</span></span></code></pre></div><p>Output</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;firstName&#34;</span><span class="p">:</span> <span class="s2">&#34;sally&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nt">&#34;age&#34;</span><span class="p">:</span> <span class="mi">28</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Getters and setters in Python</title><link>https://how.wtf/getters-and-setters-in-python.html</link><pubDate>Fri, 14 Apr 2023 23:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/getters-and-setters-in-python.html</guid><description>Writing getter and setter methods in Python is seamless using the @property decorator.
Using the @property decorator for getter and setter methods Directly from the documentation:
1class C(object): 2 def __init__(self): 3 self._x = None 4 5 @property 6 def x(self): 7 &amp;#34;&amp;#34;&amp;#34;I&amp;#39;m the &amp;#39;x&amp;#39; property.&amp;#34;&amp;#34;&amp;#34; 8 print(&amp;#34;getter of x called&amp;#34;) 9 return self._x 10 11 @x.setter 12 def x(self, value): 13 print(&amp;#34;setter of x called&amp;#34;) 14 self._x = value 15 16 @x.</description><content:encoded><![CDATA[<p>Writing getter and setter methods in Python is seamless using the <a href="https://docs.python.org/3/library/functions.html#property"><code>@property</code> decorator</a>.</p>
<h2 id="using-the-property-decorator-for-getter-and-setter-methods">Using the <code>@property</code> decorator for getter and setter methods</h2>
<p>Directly from the documentation:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">_x</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="nd">@property</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="k">def</span> <span class="nf">x</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="s2">&#34;&#34;&#34;I&#39;m the &#39;x&#39; property.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;getter of x called&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_x</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="nd">@x.setter</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="k">def</span> <span class="nf">x</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;setter of x called&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">_x</span> <span class="o">=</span> <span class="n">value</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="nd">@x.deleter</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="k">def</span> <span class="nf">x</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;deleter of x called&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">        <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">_x</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="n">c</span> <span class="o">=</span> <span class="n">C</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="n">c</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="s1">&#39;foo&#39;</span>  <span class="c1"># setter called</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="n">foo</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">x</span>    <span class="c1"># getter called</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="k">del</span> <span class="n">c</span><span class="o">.</span><span class="n">x</span>      <span class="c1"># deleter called</span></span></span></code></pre></div><p>An implementation of this method could be a product where a user can set a price <em>after</em> its instantiation.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">class</span> <span class="nc">Product</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">_name</span> <span class="o">=</span> <span class="n">name</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="nd">@property</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="k">def</span> <span class="nf">price</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_price</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="nd">@price.setter</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="k">def</span> <span class="nf">price</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">new_price</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="k">if</span> <span class="n">new_price</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">new_price</span><span class="p">,</span> <span class="nb">float</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">            <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s2">&#34;price must be greater than 0 and a float&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">_price</span> <span class="o">=</span> <span class="n">new_price</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="nd">@price.deleter</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="k">def</span> <span class="nf">price</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">_price</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="n">p1</span> <span class="o">=</span> <span class="n">Product</span><span class="p">(</span><span class="s2">&#34;one&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="n">p1</span><span class="o">.</span><span class="n">price</span> <span class="o">=</span> <span class="mf">5.5</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Difference between is and equal in Python</title><link>https://how.wtf/difference-between-is-and-equal-in-python.html</link><pubDate>Thu, 13 Apr 2023 23:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/difference-between-is-and-equal-in-python.html</guid><description>In Python, there are two operators for determining equality: is and ==; however, what are the differences between them and when should one be used over the other?
What is the difference between the is and == The is operator checks for object identity The == operator checks for equality Here is an example demonstrating the differences:
1foo = [1, 2, 3] 2bar = foo 3print(foo is bar) # True 4print(foo == bar) # TrueIn the example above, bar points to the same object reference as foo.</description><content:encoded><![CDATA[<p>In Python, there are two operators for determining equality: <code>is</code> and <code>==</code>; however, what are the differences between them and when should one be used over the other?</p>
<h2 id="what-is-the-difference-between-the-is-and-">What is the difference between the <code>is</code> and <code>==</code></h2>
<ol>
<li>The <code>is</code> operator checks for <strong>object identity</strong></li>
<li>The <code>==</code> operator checks for <strong>equality</strong></li>
</ol>
<p>Here is an example demonstrating the differences:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">foo</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">bar</span> <span class="o">=</span> <span class="n">foo</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">foo</span> <span class="ow">is</span> <span class="n">bar</span><span class="p">)</span> <span class="c1"># True</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">foo</span> <span class="o">==</span> <span class="n">bar</span><span class="p">)</span> <span class="c1"># True</span></span></span></code></pre></div><p>In the example above, <code>bar</code> points to the same object reference as <code>foo</code>. Because <code>foo</code> and <code>bar</code> point to the same object, <code>is</code> reports true.</p>
<p>If a <em>copy</em> of <code>foo</code>&rsquo;s list is assigned to <code>bar</code>,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">bar</span> <span class="o">=</span> <span class="n">foo</span><span class="p">[:]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">foo</span> <span class="ow">is</span> <span class="n">bar</span><span class="p">)</span> <span class="c1"># False</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">foo</span> <span class="o">==</span> <span class="n">bar</span><span class="p">)</span> <span class="c1"># True</span></span></span></code></pre></div><p><code>is</code> reports <code>False</code> since the two variables do <em>not</em> point to the same object.</p>
<h2 id="when-to-use-which">When to use which?</h2>
<p>As a general rule of thumb, use the <code>is</code> operator for the following use-cases:</p>
<ol>
<li>Verify if two objects are the same object (not just the value)</li>
<li>Comparison against constants: <code>None</code>.</li>
</ol>
<p>As stated in the <a href="https://peps.python.org/pep-0008/#programming-recommendations">PEP 8 style guide</a>,</p>
<blockquote>
<p>Comparisons to singletons like None should always be done with <code>is</code> or <code>is  not</code>, never the equality operators.</p>
</blockquote>
<p>Outside of those two use cases, <strong>default to using the <code>==</code> or <code>!=</code> operators</strong>.</p>
]]></content:encoded></item><item><title>Promise all in Python</title><link>https://how.wtf/promise-all-in-python.html</link><pubDate>Wed, 12 Apr 2023 23:55:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/promise-all-in-python.html</guid><description>In JavaScript, promise.all() returns a single promise given an iterable of promises. The returned promise is fulfilled when all the iterable promises are fulfilled. If one promise is rejected, the resulting promise is also rejected.
1try { 2 const values = await Promise.all([promise1, promise2]); 3 console.log(values); // [resolvedValue1, resolvedValue2] 4} catch (err) { 5 console.log(error); // rejectReason of any first rejected promise 6}How to use promise.all() in Python Python natively supports similar functionality to promise.</description><content:encoded><![CDATA[<p>In JavaScript, <code>promise.all()</code> returns a single promise given an iterable of promises. The returned promise is fulfilled when all the iterable promises are fulfilled. If one promise is rejected, the resulting promise is also rejected.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="kr">const</span> <span class="nx">values</span> <span class="o">=</span> <span class="kr">await</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">all</span><span class="p">([</span><span class="nx">promise1</span><span class="p">,</span> <span class="nx">promise2</span><span class="p">]);</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">values</span><span class="p">);</span> <span class="c1">// [resolvedValue1, resolvedValue2]
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"></span><span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">error</span><span class="p">);</span> <span class="c1">// rejectReason of any first rejected promise
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c1"></span><span class="p">}</span></span></span></code></pre></div><h2 id="how-to-use-promiseall-in-python">How to use <code>promise.all()</code> in Python</h2>
<p>Python natively supports similar functionality to <code>promise.all()</code>. The method is named <code>asyncio.gather()</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">asyncio</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">some_function</span><span class="p">():</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">	<span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">	<span class="k">return</span> <span class="mi">1</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">values</span> <span class="o">=</span> <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">gather</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="n">some_function</span><span class="p">(),</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="n">some_function</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">values</span><span class="p">)</span> <span class="c1"># [1, 1]</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Enums in Python</title><link>https://how.wtf/enums-in-python.html</link><pubDate>Tue, 11 Apr 2023 23:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/enums-in-python.html</guid><description>In Python 3.4, Enum support was added.
How to implement an Enum Implementing an Enum in Python is trivial.
1from enum import Enum 2 3 4class PizzaSize(Enum): 5 SMALL = 0 6 MEDIUM = 1 7 LARGE = 2 8 9 10print(PizzaSize.SMALL) # PizzaSize.SMALL 11print(PizzaSize.SMALL.value) # 0 12print(PizzaSize.SMALL.name) # SMALLAs a shortcut, a range value may be applied:
1from enum import Enum 2 3 4class PizzaSize(Enum): 5 SMALL, MEDIUM, LARGE = range(3) 6 7 8print(PizzaSize.</description><content:encoded><![CDATA[<p>In Python 3.4, <code>Enum</code> support was added.</p>
<h2 id="how-to-implement-an-enum">How to implement an <code>Enum</code></h2>
<p>Implementing an <code>Enum</code> in Python is trivial.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">enum</span> <span class="kn">import</span> <span class="n">Enum</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="k">class</span> <span class="nc">PizzaSize</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="n">SMALL</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">MEDIUM</span> <span class="o">=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">LARGE</span> <span class="o">=</span> <span class="mi">2</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">PizzaSize</span><span class="o">.</span><span class="n">SMALL</span><span class="p">)</span> <span class="c1"># PizzaSize.SMALL</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">PizzaSize</span><span class="o">.</span><span class="n">SMALL</span><span class="o">.</span><span class="n">value</span><span class="p">)</span> <span class="c1"># 0</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">PizzaSize</span><span class="o">.</span><span class="n">SMALL</span><span class="o">.</span><span class="n">name</span><span class="p">)</span> <span class="c1"># SMALL</span></span></span></code></pre></div><p>As a shortcut, a <code>range</code> value may be applied:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">enum</span> <span class="kn">import</span> <span class="n">Enum</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="k">class</span> <span class="nc">PizzaSize</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="n">SMALL</span><span class="p">,</span> <span class="n">MEDIUM</span><span class="p">,</span> <span class="n">LARGE</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">PizzaSize</span><span class="o">.</span><span class="n">SMALL</span><span class="p">)</span>  <span class="c1"># PizzaSize.SMALL</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">PizzaSize</span><span class="o">.</span><span class="n">SMALL</span><span class="o">.</span><span class="n">value</span><span class="p">)</span>  <span class="c1"># 0</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">PizzaSize</span><span class="o">.</span><span class="n">SMALL</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>  <span class="c1"># SMALL</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Enums in Golang</title><link>https://how.wtf/enums-in-golang.html</link><pubDate>Mon, 10 Apr 2023 23:50:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/enums-in-golang.html</guid><description>GO does not natively support an enum keyword; however, an enum-like syntax can be implemented using the help of iota.
What is iota? iota is an identifier that auto increments constants.
In the following code, the constant number is manually incremented:
1const ( 2 ZERO = 0 3 ONE = 1 4 TWO = 2 5)however, it can be simplified to:
1const ( 2 ZERO = iota // 0 3 ONE // 1 4 TWO // 2 5)If desired, the iota keyword can be used on each line:</description><content:encoded><![CDATA[<p>GO does not natively support an <code>enum</code> keyword; however, an enum-like syntax can be implemented using the help of <code>iota</code>.</p>
<h2 id="what-is-iota">What is <code>iota</code>?</h2>
<p><code>iota</code> is an identifier that auto increments constants.</p>
<p>In the following code, the constant number is manually incremented:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="ln">1</span><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nx">ZERO</span> <span class="p">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nx">ONE</span> <span class="p">=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nx">TWO</span> <span class="p">=</span> <span class="mi">2</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">)</span></span></span></code></pre></div><p>however, it can be simplified to:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="ln">1</span><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">	<span class="nx">ZERO</span> <span class="p">=</span> <span class="kc">iota</span> <span class="c1">// 0
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"></span>	<span class="nx">ONE</span>         <span class="c1">// 1
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"></span>	<span class="nx">TWO</span>         <span class="c1">// 2
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1"></span><span class="p">)</span></span></span></code></pre></div><p>If desired, the <code>iota</code> keyword can be used on each line:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="ln">1</span><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">	<span class="nx">ZERO</span> <span class="p">=</span> <span class="kc">iota</span> <span class="c1">// 0
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"></span>	<span class="nx">ONE</span>  <span class="p">=</span> <span class="kc">iota</span> <span class="c1">// 1
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"></span>	<span class="nx">TWO</span>  <span class="p">=</span> <span class="kc">iota</span> <span class="c1">// 2
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1"></span><span class="p">)</span></span></span></code></pre></div><p>If a <code>const</code> keyword is used again, the <code>iota</code> will reset to 0.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">	<span class="nx">ZERO</span> <span class="p">=</span> <span class="kc">iota</span> <span class="c1">// 0
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="c1"></span>	<span class="nx">ONE</span>         <span class="c1">// 1
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"></span>	<span class="nx">TWO</span>         <span class="c1">// 2
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"></span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">	<span class="nx">ZEROAGAIN</span> <span class="p">=</span> <span class="kc">iota</span> <span class="c1">// 0
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"></span>	<span class="nx">ONEAGAIN</span>         <span class="c1">// 1
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"></span>	<span class="nx">TWOAGAIN</span>         <span class="c1">// 2
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"></span><span class="p">)</span></span></span></code></pre></div><h2 id="implementing-an-enum-in-go">Implementing an enum in GO</h2>
<p>Using a combination of <code>iota</code>, <code>int</code> and <code>const</code>, the concept of an <code>enum</code> can be applied.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="s">&#34;fmt&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="kd">type</span> <span class="nx">PizzaSize</span> <span class="kt">int</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">	<span class="nx">SMALL</span>  <span class="nx">PizzaSize</span> <span class="p">=</span> <span class="kc">iota</span> <span class="o">+</span> <span class="mi">1</span> <span class="c1">// 1
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"></span>	<span class="nx">MEDIUM</span>                      <span class="c1">// 2
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"></span>	<span class="nx">LARGE</span>                       <span class="c1">// 3
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"></span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">s</span> <span class="nx">PizzaSize</span><span class="p">)</span> <span class="nf">String</span><span class="p">()</span> <span class="kt">string</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">	<span class="k">return</span> <span class="p">[</span><span class="o">...</span><span class="p">]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;Small&#34;</span><span class="p">,</span> <span class="s">&#34;Medium&#34;</span><span class="p">,</span> <span class="s">&#34;Large&#34;</span><span class="p">}[</span><span class="nx">s</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">s</span> <span class="nx">PizzaSize</span><span class="p">)</span> <span class="nf">Index</span><span class="p">()</span> <span class="kt">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">	<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="nx">s</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">	<span class="nx">size</span> <span class="o">:=</span> <span class="nx">SMALL</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">	<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">size</span><span class="p">)</span>          <span class="c1">// Print : Small
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="c1"></span>	<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">size</span><span class="p">.</span><span class="nf">String</span><span class="p">())</span> <span class="c1">// Print : Small
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="c1"></span>	<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">size</span><span class="p">.</span><span class="nf">Index</span><span class="p">())</span>  <span class="c1">// Print : 1
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="c1"></span><span class="p">}</span></span></span></code></pre></div>]]></content:encoded></item><item><title>AWS CLI starts with query</title><link>https://how.wtf/aws-cli-starts-with-query.html</link><pubDate>Sun, 09 Apr 2023 19:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/aws-cli-starts-with-query.html</guid><description>If a user wants to search AWS resources using a starts_with or &amp;ldquo;begins with&amp;rdquo; or &amp;ldquo;has prefix&amp;rdquo; query, the AWS CLI natively supports it.
How to query using starts_with Using AWS CloudFormation as an example, the AWS CLI allows for the following query syntax:
1export prefix=&amp;#34;&amp;lt;prefix&amp;gt;&amp;#34; 2aws cloudformation describe-stacks \ 3 --query &amp;#34;Stacks[?starts_with(StackName, `$prefix`) == `true`].StackName&amp;#34;This outputs all of the CloudFormation stack names that start with a particular prefix.
starts_with The starts_with syntax is included in the JMESPath specification.</description><content:encoded><![CDATA[<p>If a user wants to search AWS resources using a <code>starts_with</code> or &ldquo;begins with&rdquo; or &ldquo;has prefix&rdquo; query, the AWS CLI natively supports it.</p>
<h2 id="how-to-query-using-starts_with">How to query using <code>starts_with</code></h2>
<p>Using AWS CloudFormation as an example, the AWS CLI allows for the following query syntax:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">export</span> <span class="nv">prefix</span><span class="o">=</span><span class="s2">&#34;&lt;prefix&gt;&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">aws cloudformation describe-stacks <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	--query <span class="s2">&#34;Stacks[?starts_with(StackName, `</span><span class="nv">$prefix</span><span class="s2">`) == `true`].StackName&#34;</span></span></span></code></pre></div><p>This outputs all of the CloudFormation stack names that start with a particular prefix.</p>
<h3 id="starts_with"><code>starts_with</code></h3>
<p>The <code>starts_with</code> syntax is included in the JMESPath <a href="https://jmespath.org/specification.html#starts-with">specification</a>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">boolean starts_with(string $subject, string $prefix)</span></span></code></pre></div><blockquote>
<p>Returns  <code>true</code>  if the  <code>$subject</code>  starts with the  <code>$prefix</code>, otherwise this function returns  <code>false</code>.</p>
</blockquote>
]]></content:encoded></item><item><title>Executing Python scripts with a shebang</title><link>https://how.wtf/executing-python-scripts-with-a-shebang.html</link><pubDate>Sat, 08 Apr 2023 10:50:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/executing-python-scripts-with-a-shebang.html</guid><description>The shebang line informs the operating system&amp;rsquo;s shell where to find the interpreter. The program loader will execute the specified interpreter with the same arguments that were initially passed.
Add a shebang (#!) to a Python script How to add a shebang (#!) to a Python 3 file:
1#!/usr/bin/env python3 2 3print(&amp;#34;hello world&amp;#34;)In addition to the normal execution by calling the interpreter directly:
1python3 ./hello.pythe file can be called like this:</description><content:encoded><![CDATA[<p>The shebang line informs the operating system&rsquo;s shell where to find the interpreter. The program loader will execute the specified interpreter with the same arguments that were initially passed.</p>
<h2 id="add-a-shebang--to-a-python-script">Add a shebang (<code>#!</code>) to a Python script</h2>
<p>How to add a shebang (<code>#!</code>) to a Python 3 file:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="ch">#!/usr/bin/env python3</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;hello world&#34;</span><span class="p">)</span></span></span></code></pre></div><p>In addition to the normal execution by calling the interpreter directly:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">python3 ./hello.py</span></span></code></pre></div><p>the file can be called like this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">./hello.py</span></span></code></pre></div><p><strong>Note</strong>: The executable may not have executable permissions by the user. To enable for this, simply run:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">chmod +x ./hello.py</span></span></code></pre></div>]]></content:encoded></item><item><title>gyp no xcode or clt version detected</title><link>https://how.wtf/gyp-no-xcode-or-clt-version-detected.html</link><pubDate>Fri, 07 Apr 2023 22:25:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/gyp-no-xcode-or-clt-version-detected.html</guid><description>On a fresh update of MacOS, an error may occur:
1gyp: No Xcode or CLT version detected! 2gyp ERR! configure errorSolution 1: Reset xcode Try simply running the following command:
1sudo xcode-select --resetSolution 2: Reinstall xcode If the prior solution does not work, a complete reinstall of xcode may be necessary.
Find the xcode path: 1xcode-select --print-path Delete the xcode directory 1sudo rm -rf &amp;lt;result from last command&amp;gt; Install xcode 1xcode-select --install</description><content:encoded><![CDATA[<p>On a fresh update of MacOS, an error may occur:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">gyp: No Xcode or CLT version detected!  
</span></span><span class="line"><span class="ln">2</span><span class="cl">gyp ERR! configure error</span></span></code></pre></div><h2 id="solution-1-reset-xcode">Solution 1: Reset xcode</h2>
<p>Try simply running the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo xcode-select --reset</span></span></code></pre></div><h2 id="solution-2-reinstall-xcode">Solution 2: Reinstall xcode</h2>
<p>If the prior solution does not work, a complete reinstall of xcode may be necessary.</p>
<ol>
<li>Find the xcode path:</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">xcode-select --print-path</span></span></code></pre></div><ol start="2">
<li>Delete the xcode directory</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo rm -rf &lt;result from last command&gt;</span></span></code></pre></div><ol start="3">
<li>Install xcode</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">xcode-select --install</span></span></code></pre></div>]]></content:encoded></item><item><title>Check for valid json string or file with jq</title><link>https://how.wtf/check-for-valid-json-string-or-file-with-jq.html</link><pubDate>Thu, 06 Apr 2023 21:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/check-for-valid-json-string-or-file-with-jq.html</guid><description>Verifying if a string or file is valid json is easy with jq.
Check if a string is valid json Using the -e argument, jq will return a 0 if the last output was neither false nor null.
1if jq -e . &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;lt;&amp;lt;&amp;lt;&amp;#39;{&amp;#34;test&amp;#34;: &amp;#34;value&amp;#34;}&amp;#39;; then 2 echo &amp;#34;parsed successfully&amp;#34; 3else 4 echo &amp;#34;could not parse json string&amp;#34; 5fiIn addition, negating the above condition may increase readability:
1if ! jq -e .</description><content:encoded><![CDATA[<p>Verifying if a string or file is valid json is easy with <code>jq</code>.</p>
<h2 id="check-if-a-string-is-valid-json">Check if a string is valid <code>json</code></h2>
<p>Using the <code>-e</code> argument, <code>jq</code> will return a 0 if the last output was neither <code>false</code> nor <code>null</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">if</span> jq -e . &gt;/dev/null 2&gt;<span class="p">&amp;</span><span class="m">1</span> <span class="o">&lt;&lt;&lt;</span><span class="s1">&#39;{&#34;test&#34;: &#34;value&#34;}&#39;</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;parsed successfully&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;could not parse json string&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p>In addition, negating the above condition may increase readability:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">if</span> ! jq -e . &gt;/dev/null 2&gt;<span class="p">&amp;</span><span class="m">1</span> <span class="o">&lt;&lt;&lt;</span><span class="s1">&#39;{&#34;test&#34;: &#34;value&#34;}&#39;</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;could not parse json string&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nb">exit</span> <span class="m">1</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p>Using a variable:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">if</span> ! jq -e . &gt;/dev/null 2&gt;<span class="p">&amp;</span><span class="m">1</span> <span class="o">&lt;&lt;&lt;</span><span class="s2">&#34;</span><span class="nv">$json</span><span class="s2">&#34;</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;could not parse json string&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nb">exit</span> <span class="m">1</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><h2 id="check-if-a-file-is-valid-json">Check if a file is valid <code>json</code></h2>
<p>Using the same technique from above:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">if</span> ! jq -e . &gt;/dev/null 2&gt;<span class="p">&amp;</span><span class="m">1</span> <span class="o">&lt;&lt;&lt;</span><span class="k">$(</span>cat invalid.json<span class="k">)</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;could not parse json file&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nb">exit</span> <span class="m">1</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p>the <code>invalid.json</code> file:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span> <span class="nt">&#34;invalid&#34;</span></span></span></code></pre></div><p>will output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">could not parse json file</span></span></code></pre></div>]]></content:encoded></item><item><title>Patch operations for updating api resources with the AWS CLI</title><link>https://how.wtf/patch-operations-for-updating-api-resources-with-the-aws-cli.html</link><pubDate>Wed, 05 Apr 2023 23:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/patch-operations-for-updating-api-resources-with-the-aws-cli.html</guid><description>When updating API Gateway resources using the AWS CLI, some commands include a --patch-operations argument.
For example, the update-base-path-mapping allows an optional --patch-operations. For more information about which resources are supported via patch operations, the AWS documentation is here.
How to use the --patch-operations argument In the case for updating a base path mapping, a user may need to supply a restapiId and stage value.
The JSON array:
1[ 2 { 3 &amp;#34;op&amp;#34;: &amp;#34;replace&amp;#34;, 4 &amp;#34;path&amp;#34;: &amp;#34;/restapiId&amp;#34;, 5 &amp;#34;value&amp;#34;: &amp;#34;id&amp;#34; 6 }, 7 { 8 &amp;#34;op&amp;#34;: &amp;#34;replace&amp;#34;, 9 &amp;#34;path&amp;#34;: &amp;#34;/stage&amp;#34;, 10 &amp;#34;value&amp;#34;: &amp;#34;prod&amp;#34; 11 } 12]The aws apigateway update-base-path-mapping allows for a stringified json array value for the --patch-operations argument:</description><content:encoded><![CDATA[<p>When updating API Gateway resources using the AWS CLI, some commands include a <code>--patch-operations</code> argument.</p>
<p>For example, the <a href="https://docs.aws.amazon.com/cli/latest/reference/apigateway/update-base-path-mapping.html"><code>update-base-path-mapping</code></a> allows an optional <code>--patch-operations</code>. For more information about which resources are supported via patch operations, the AWS documentation is <a href="https://docs.aws.amazon.com/apigateway/latest/api/patch-operations.html">here</a>.</p>
<h2 id="how-to-use-the---patch-operations-argument">How to use the <code>--patch-operations</code> argument</h2>
<p>In the case for updating a base path mapping, a user may need to supply a <code>restapiId</code> and <code>stage</code> value.</p>
<p>The JSON array:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="nt">&#34;op&#34;</span><span class="p">:</span> <span class="s2">&#34;replace&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="nt">&#34;path&#34;</span><span class="p">:</span> <span class="s2">&#34;/restapiId&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="nt">&#34;value&#34;</span><span class="p">:</span> <span class="s2">&#34;id&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="nt">&#34;op&#34;</span><span class="p">:</span> <span class="s2">&#34;replace&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="nt">&#34;path&#34;</span><span class="p">:</span> <span class="s2">&#34;/stage&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="nt">&#34;value&#34;</span><span class="p">:</span> <span class="s2">&#34;prod&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">]</span></span></span></code></pre></div><p>The <code>aws apigateway update-base-path-mapping</code> allows for a stringified <code>json</code> array value for the <code>--patch-operations</code> argument:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">domain_name</span><span class="o">=</span><span class="s2">&#34;example.com&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nv">base_path</span><span class="o">=</span><span class="s2">&#34;some-path&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nv">api_id</span><span class="o">=</span><span class="s2">&#34;id&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nv">stage</span><span class="o">=</span><span class="s2">&#34;prod&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">aws apigateway update-base-path-mapping <span class="se">\
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="se"></span>	--domain-name <span class="nv">$domain_name</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="se"></span>	--base-path <span class="nv">$base_path</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="se"></span>	--patch-operations <span class="s2">&#34;[{\&#34;op\&#34;:\&#34;replace\&#34;,\&#34;path\&#34;:\&#34;/restapiId\&#34;,\&#34;value\&#34;:\&#34;</span><span class="nv">$api_id</span><span class="s2">\&#34;},{\&#34;op\&#34;:\&#34;replace\&#34;,\&#34;path\&#34;:\&#34;/stage\&#34;,\&#34;value\&#34;:\&#34;</span><span class="nv">$stage</span><span class="s2">\&#34;}]&#34;</span></span></span></code></pre></div><p>The same <code>--patch-operations</code> argument format applies to the other API Gateway commands as well.</p>
]]></content:encoded></item><item><title>AWS Lambda caching in Python</title><link>https://how.wtf/aws-lambda-caching-in-python.html</link><pubDate>Tue, 04 Apr 2023 23:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/aws-lambda-caching-in-python.html</guid><description>Caching between lambda invocations may be useful for certain scenarios:
Authentication Rate limits with external services Speed How to cache between lambda invocations In Python, it&amp;rsquo;s as simple as modifying a global variable.
1obj = None 2 3def lambda_handler(event): 4 global obj 5 if not obj: 6 obj = YourClass(event)Upon initial run of a lambda function, obj will be set to the output of YourClass(event). On subsequent warm starts, the lambda function will reuse the global obj from the previous lambda run.</description><content:encoded><![CDATA[<p>Caching between lambda invocations may be useful for certain scenarios:</p>
<ul>
<li>Authentication</li>
<li>Rate limits with external services</li>
<li>Speed</li>
</ul>
<h2 id="how-to-cache-between-lambda-invocations">How to cache between lambda invocations</h2>
<p>In Python, it&rsquo;s as simple as modifying a global variable.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">obj</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">def</span> <span class="nf">lambda_handler</span><span class="p">(</span><span class="n">event</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="k">global</span> <span class="n">obj</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">        <span class="n">obj</span> <span class="o">=</span> <span class="n">YourClass</span><span class="p">(</span><span class="n">event</span><span class="p">)</span></span></span></code></pre></div><p>Upon initial run of a lambda function, <code>obj</code> will be set to the output of <code>YourClass(event)</code>. On subsequent <em>warm</em> starts, the lambda function will reuse the global <code>obj</code> from the previous lambda run. More information regarding warm vs cold starts can be found <a href="https://aws.amazon.com/blogs/compute/container-reuse-in-lambda/">here</a>.</p>
]]></content:encoded></item><item><title>Calculate the middle between two dates in JavaScript</title><link>https://how.wtf/calculate-the-middle-between-two-dates-in-javascript.html</link><pubDate>Mon, 03 Apr 2023 23:35:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/calculate-the-middle-between-two-dates-in-javascript.html</guid><description>In TypeScript or JavaScript, determining the midpoint between two dates is easy using the native Date library.
Determine the middle between two dates 1const startDate = new Date(&amp;#39;Mar 10 2023&amp;#39;); 2const endDate = new Date(&amp;#39;Mar 15 2023&amp;#39;); 3 4const midDate = new Date((startDate.getTime() + endDate.getTime()) / 2); 5console.log(midDate) // 2023-03-12T12:00:00.000Z In the example above, getTime() returns the number of seconds since epoch. Adding the seconds and dividing by two gives the midpoint.</description><content:encoded><![CDATA[<p>In TypeScript or JavaScript, determining the midpoint between two dates is easy using the native <code>Date</code> library.</p>
<h2 id="determine-the-middle-between-two-dates">Determine the middle between two dates</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="kr">const</span> <span class="nx">startDate</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">(</span><span class="s1">&#39;Mar 10 2023&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kr">const</span> <span class="nx">endDate</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">(</span><span class="s1">&#39;Mar 15 2023&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="kr">const</span> <span class="nx">midDate</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">((</span><span class="nx">startDate</span><span class="p">.</span><span class="nx">getTime</span><span class="p">()</span> <span class="o">+</span> <span class="nx">endDate</span><span class="p">.</span><span class="nx">getTime</span><span class="p">())</span> <span class="o">/</span> <span class="mi">2</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">midDate</span><span class="p">)</span> <span class="c1">// 2023-03-12T12:00:00.000Z
</span></span></span></code></pre></div><p>In the example above, <code>getTime()</code> returns the number of seconds since epoch. Adding the seconds and dividing by two gives the midpoint.</p>
]]></content:encoded></item><item><title>Python dataclass validation</title><link>https://how.wtf/python-dataclass-validation.html</link><pubDate>Sun, 02 Apr 2023 23:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/python-dataclass-validation.html</guid><description>Creating dataclasses in Python is simplistic; however, what if additional validation needs to be completed during initialization?
Creating a dataclass The following example has a class named Person that models information about an individual:
1from dataclasses import dataclass 2 3@dataclass 4class Person: 5 first_name: str 6 last_name: str 7 age: intThis class can be instantiated in several ways:
1john = Person(first_name=&amp;#34;john&amp;#34;, last_name=&amp;#34;doe&amp;#34;, age=35) 2sally = Person(first_name=&amp;#34;sally&amp;#34;, last_name=&amp;#34;may&amp;#34;, age=-20) 3zachary = Person(first_name=&amp;#34;zachary&amp;#34;, last_name=&amp;#34;taylor&amp;#34;, age=12.</description><content:encoded><![CDATA[<p>Creating dataclasses in Python is simplistic; however, what if additional validation needs to be completed during initialization?</p>
<h2 id="creating-a-dataclass">Creating a dataclass</h2>
<p>The following example has a class named <code>Person</code> that models information about an individual:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nd">@dataclass</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">class</span> <span class="nc">Person</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="n">first_name</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="n">last_name</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="n">age</span><span class="p">:</span> <span class="nb">int</span></span></span></code></pre></div><p>This class can be instantiated in several ways:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">john</span> <span class="o">=</span> <span class="n">Person</span><span class="p">(</span><span class="n">first_name</span><span class="o">=</span><span class="s2">&#34;john&#34;</span><span class="p">,</span> <span class="n">last_name</span><span class="o">=</span><span class="s2">&#34;doe&#34;</span><span class="p">,</span> <span class="n">age</span><span class="o">=</span><span class="mi">35</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">sally</span> <span class="o">=</span> <span class="n">Person</span><span class="p">(</span><span class="n">first_name</span><span class="o">=</span><span class="s2">&#34;sally&#34;</span><span class="p">,</span> <span class="n">last_name</span><span class="o">=</span><span class="s2">&#34;may&#34;</span><span class="p">,</span> <span class="n">age</span><span class="o">=-</span><span class="mi">20</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">zachary</span> <span class="o">=</span> <span class="n">Person</span><span class="p">(</span><span class="n">first_name</span><span class="o">=</span><span class="s2">&#34;zachary&#34;</span><span class="p">,</span> <span class="n">last_name</span><span class="o">=</span><span class="s2">&#34;taylor&#34;</span><span class="p">,</span> <span class="n">age</span><span class="o">=</span><span class="mf">12.5</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">john</span><span class="p">)</span> <span class="c1"># Person(first_name=&#39;john&#39;, last_name=&#39;doe&#39;, age=35)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">sally</span><span class="p">)</span> <span class="c1"># Person(first_name=&#39;sally&#39;, last_name=&#39;may&#39;, age=-20)</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">zachary</span><span class="p">)</span> <span class="c1"># Person(first_name=&#39;zachary&#39;, last_name=&#39;taylor&#39;, age=12.5)</span></span></span></code></pre></div><h2 id="how-to-validate-inputs-for-dataclasses">How to validate inputs for dataclasses</h2>
<p>In the previous example, <code>sally</code>&rsquo;s age was a non-positive integer and <code>zachary</code>&rsquo;s <code>age</code> was a float value. To resolve erroneous input, a <code>__post_init__</code> method can be used:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nd">@dataclass</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="k">class</span> <span class="nc">Person</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="n">first_name</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">last_name</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">age</span><span class="p">:</span> <span class="nb">int</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="k">def</span> <span class="nf">__post_init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">age</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&#34;age is not an int&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">age</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&#34;age must be a positive integer greater than 0&#34;</span><span class="p">)</span></span></span></code></pre></div><p><code>sally</code>&rsquo;s error:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">ValueError: age must be a positive integer greater than 0</span></span></code></pre></div><p><code>zachary</code>&rsquo;s error:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">ValueError: age is not an int</span></span></code></pre></div>]]></content:encoded></item><item><title>Check if a variable is an array in JavaScript</title><link>https://how.wtf/check-if-a-variable-is-an-array-in-javascript.html</link><pubDate>Sat, 01 Apr 2023 23:20:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/check-if-a-variable-is-an-array-in-javascript.html</guid><description>In TypeScript or JavaScript, checking if a variable is an array can be completed in two ways.
Using the Array.isArray() Using the native Array.isArray() method, a boolean will be returned.
1const names = [&amp;#34;sally&amp;#34;, &amp;#34;billy&amp;#34;, &amp;#34;mary&amp;#34;]; 2const notAnArray = &amp;#39;str&amp;#39;; 3console.log(Array.isArray(names)); // true 4console.log(Array.isArray(notAnArray)); // false Using the instanceOf operator As an alternative option, instanceOf will yield the same results.
1const names = [&amp;#34;sally&amp;#34;, &amp;#34;billy&amp;#34;, &amp;#34;mary&amp;#34;]; 2const notAnArray = &amp;#39;str&amp;#39;; 3console.</description><content:encoded><![CDATA[<p>In TypeScript or JavaScript, checking if a variable is an array can be completed in two ways.</p>
<h2 id="using-the-arrayisarray">Using the <code>Array.isArray()</code></h2>
<p>Using the native <code>Array.isArray()</code> method, a boolean will be returned.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="kr">const</span> <span class="nx">names</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;sally&#34;</span><span class="p">,</span> <span class="s2">&#34;billy&#34;</span><span class="p">,</span> <span class="s2">&#34;mary&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kr">const</span> <span class="nx">notAnArray</span> <span class="o">=</span> <span class="s1">&#39;str&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nb">Array</span><span class="p">.</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">names</span><span class="p">));</span> <span class="c1">// true
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nb">Array</span><span class="p">.</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">notAnArray</span><span class="p">));</span> <span class="c1">// false
</span></span></span></code></pre></div><h2 id="using-the-instanceof-operator">Using the <code>instanceOf</code> operator</h2>
<p>As an alternative option, <code>instanceOf</code> will yield the same results.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="kr">const</span> <span class="nx">names</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;sally&#34;</span><span class="p">,</span> <span class="s2">&#34;billy&#34;</span><span class="p">,</span> <span class="s2">&#34;mary&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kr">const</span> <span class="nx">notAnArray</span> <span class="o">=</span> <span class="s1">&#39;str&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">names</span> <span class="k">instanceof</span> <span class="nb">Array</span><span class="p">);</span> <span class="c1">// true
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"></span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">notAnArray</span> <span class="k">instanceof</span> <span class="nb">Array</span><span class="p">);</span> <span class="c1">// false
</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Pull latest changes from submodules in Git</title><link>https://how.wtf/pull-latest-changes-from-submodules-in-git.html</link><pubDate>Fri, 31 Mar 2023 21:50:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/pull-latest-changes-from-submodules-in-git.html</guid><description>Pulling the latest changes for all submodules in a repository is made easy through Git.
Pull all submodules after checkout After an initial checkout, the the submodules can be updated using the following command:
1git submodule update --init --recursivePull all submodules changes In Git versions 1.8.2 and higher, a --remote option was added to pull the latest changes from remote branches.
1git submodule update --recursive --remoteIn addition, the following commands will work as well:</description><content:encoded><![CDATA[<p>Pulling the latest changes for all submodules in a repository is made easy through Git.</p>
<h2 id="pull-all-submodules-after-checkout">Pull all submodules after checkout</h2>
<p>After an initial checkout, the the submodules can be updated using the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">git submodule update --init --recursive</span></span></code></pre></div><h2 id="pull-all-submodules-changes">Pull all submodules changes</h2>
<p>In Git versions 1.8.2 and higher, a <code>--remote</code> option was added to pull the latest changes from remote branches.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">git submodule update --recursive --remote</span></span></code></pre></div><p>In addition, the following commands will work as well:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">git submodule update --recursive</span></span></code></pre></div><p><em>or</em></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">git pull --recurse-submodules</span></span></code></pre></div>]]></content:encoded></item><item><title>Reset a single file in Git</title><link>https://how.wtf/reset-a-single-file-in-git.html</link><pubDate>Thu, 30 Mar 2023 20:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/reset-a-single-file-in-git.html</guid><description>Resetting a single file is possible using Git.
How to restore a single file In Git versions 2.23 and higher, git restore natively supports resetting a single file.
1git restore path/to/file.txtThe above restores path/to/file.txt to the prior commit.
In addition, restoring from another branch is possible:
1git restore -s my-feature-branch pathTo/MyFileThe -s option specifies a source (my-feature-branch in this case).
How to reset a single file In Git versions that predate 2.</description><content:encoded><![CDATA[<p>Resetting a single file is possible using Git.</p>
<h2 id="how-to-restore-a-single-file">How to restore a single file</h2>
<p>In Git versions 2.23 and higher, <code>git restore</code> natively supports resetting a single file.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">git restore path/to/file.txt</span></span></code></pre></div><p>The above restores <code>path/to/file.txt</code> to the prior commit.</p>
<p>In addition, restoring from <em>another</em> branch is possible:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">git restore -s my-feature-branch pathTo/MyFile</span></span></code></pre></div><p>The <code>-s</code> option specifies a source (<code>my-feature-branch</code> in this case).</p>
<h2 id="how-to-reset-a-single-file">How to reset a single file</h2>
<p>In Git versions that predate 2.23, the following command will reset a single file:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">git checkout HEAD -- path/to/file.txt</span></span></code></pre></div><p>Anything after the <code>--</code> is treated as a filename in unix.</p>
]]></content:encoded></item><item><title>Match everything between two characters in Regex</title><link>https://how.wtf/match-everything-between-two-characters-in-regex.html</link><pubDate>Wed, 29 Mar 2023 12:50:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/match-everything-between-two-characters-in-regex.html</guid><description>Matching everything between two delimiters in Regex is supported. In the examples below, the [ and ] characters were used as example delimiters.
Match between characters using lookahead / lookbehind Using lookbehind and lookahead, the following patterns will match between two delimiters:
1(?&amp;lt;=\[)(.*?)(?=\])Using regex101, the explanation can summarized as:
Match the non-greedy capture group (.*?) that is preceded by a [ and is followed by ] but do not capture the delimiters.</description><content:encoded><![CDATA[<p>Matching everything between two delimiters in Regex is supported. In the examples below, the <code>[</code> and <code>]</code> characters were used as example delimiters.</p>
<h2 id="match-between-characters-using-lookahead--lookbehind">Match between characters using lookahead / lookbehind</h2>
<p>Using lookbehind and lookahead, the following patterns will match between two delimiters:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">(?&lt;=\[)(.*?)(?=\])</span></span></code></pre></div><p>Using <a href="https://regex101.com/r/RBo7NU/1">regex101</a>, the explanation can summarized as:</p>
<blockquote>
<p>Match the non-greedy capture group <code>(.*?)</code> that is preceded by a <code>[</code> and is followed by <code>]</code> but do not capture the delimiters.</p>
</blockquote>
<h2 id="match-between-characters-without-lookahead--lookbehind">Match between characters without lookahead / lookbehind</h2>
<p>Without using lookbehind or lookahead, the following pattern will match contents between two delimiters <em>including</em> the delimiters:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">\[(.*?)\]</span></span></code></pre></div><p>Here is the <a href="https://regex101.com/r/2BZJ4u/1">regex101</a> link.</p>
<p>To remove the delimiters, the first captured group of each match will need to be used.</p>
]]></content:encoded></item><item><title>JSON prettify in Python</title><link>https://how.wtf/json-prettify-in-python.html</link><pubDate>Tue, 28 Mar 2023 00:20:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/json-prettify-in-python.html</guid><description>Using the native json Python module, JSON data can be pretty-printed.
Pretty print JSON string in Python 1import json 2data = &amp;#39;{&amp;#34;users&amp;#34;: [{&amp;#34;id&amp;#34;:1,&amp;#34;name&amp;#34;:&amp;#34;Thomas&amp;#34;},{&amp;#34;id&amp;#34;:2,&amp;#34;name&amp;#34;:&amp;#34;Sally&amp;#34;}]}&amp;#39; 3obj = json.loads(data) 4print(json.dumps(obj, indent=2))Output:
1{ 2 &amp;#34;users&amp;#34;: [ 3 { 4 &amp;#34;id&amp;#34;: 1, 5 &amp;#34;name&amp;#34;: &amp;#34;Thomas&amp;#34; 6 }, 7 { 8 &amp;#34;id&amp;#34;: 2, 9 &amp;#34;name&amp;#34;: &amp;#34;Sally&amp;#34; 10 } 11 ] 12} The json.loads() method creates a Python dictionary from a given json string. The json.dumps() method outputs a json string from a given Python dictionary.</description><content:encoded><![CDATA[<p>Using the native <code>json</code> Python module, JSON data can be pretty-printed.</p>
<h2 id="pretty-print-json-string-in-python">Pretty print JSON string in Python</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="s1">&#39;{&#34;users&#34;: [{&#34;id&#34;:1,&#34;name&#34;:&#34;Thomas&#34;},{&#34;id&#34;:2,&#34;name&#34;:&#34;Sally&#34;}]}&#39;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">obj</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">))</span></span></span></code></pre></div><p><strong>Output</strong>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;users&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">      <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">      <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Thomas&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">      <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">      <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Sally&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><ol>
<li>The <code>json.loads()</code> method creates a Python dictionary from a given <code>json</code> string.</li>
<li>The <code>json.dumps()</code> method outputs a <code>json</code> string from a given Python dictionary. In addition, the <code>indent</code> parameter defines the level of the indent in the resulting string.</li>
</ol>
<h2 id="pretty-print-json-file-data-in-python">Pretty print JSON file data in Python</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;users.json&#34;</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">json_file</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="n">obj</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">json_file</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">))</span></span></span></code></pre></div><p><strong>Output</strong>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;users&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">      <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">      <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Thomas&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">      <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">      <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Sally&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><ol>
<li>The <code>json.load()</code> method creates a Python dictionary from a given file.</li>
<li>The <code>json.dumps()</code> method outputs a <code>json</code> string from a given Python dictionary. In addition, the <code>indent</code> parameter defines the level of the indent in the resulting string.</li>
</ol>
]]></content:encoded></item><item><title>Specify a log group for a lambda function in AWS CloudFormation</title><link>https://how.wtf/specify-a-log-group-for-a-lambda-function-in-aws-cloudformation.html</link><pubDate>Mon, 27 Mar 2023 01:50:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/specify-a-log-group-for-a-lambda-function-in-aws-cloudformation.html</guid><description>By default, lambda functions will create their own log groups if they are given proper permissions.
Specifying a log group for a Lambda Function The following CloudFormation template creates two resources:
AWS::IAM::Role AWS::Lambda::Function 1AWSTemplateFormatVersion: &amp;#39;2010-09-09&amp;#39; 2Resources: 3 LambdaExecutionRole: 4 Type: &amp;#39;AWS::IAM::Role&amp;#39; 5 Properties: 6 AssumeRolePolicyDocument: 7 Version: &amp;#39;2012-10-17&amp;#39; 8 Statement: 9 - Effect: Allow 10 Principal: 11 Service: 12 - lambda.amazonaws.com 13 Action: 14 - sts:AssumeRole 15 Policies: 16 - PolicyName: logs 17 PolicyDocument: 18 Version: &amp;#39;2012-10-17&amp;#39; 19 Statement: 20 - Effect: Allow 21 Action: 22 - logs:CreateLogGroup 23 - logs:CreateLogStream 24 - logs:PutLogEvents 25 Resource: &amp;#39;*&amp;#39; 26 LambdaFunction: 27 Type: &amp;#39;AWS::Lambda::Function&amp;#39; 28 Properties: 29 FunctionName: &amp;#39;LambdaTest&amp;#39; 30 Handler: index.</description><content:encoded><![CDATA[<p>By default, lambda functions will create their own log groups if they are given proper permissions.</p>
<h2 id="specifying-a-log-group-for-a-lambda-function">Specifying a log group for a Lambda Function</h2>
<p>The following CloudFormation template creates two resources:</p>
<ol>
<li><code>AWS::IAM::Role</code></li>
<li><code>AWS::Lambda::Function</code></li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nt">AWSTemplateFormatVersion</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;2010-09-09&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="nt">Resources</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">  </span><span class="nt">LambdaExecutionRole</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">    </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;AWS::IAM::Role&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">      </span><span class="nt">AssumeRolePolicyDocument</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">        </span><span class="nt">Version</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;2012-10-17&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">        </span><span class="nt">Statement</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">        </span>- <span class="nt">Effect</span><span class="p">:</span><span class="w"> </span><span class="l">Allow</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">          </span><span class="nt">Principal</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">            </span><span class="nt">Service</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">            </span>- <span class="l">lambda.amazonaws.com</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">          </span><span class="nt">Action</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">          </span>- <span class="l">sts:AssumeRole</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">      </span><span class="nt">Policies</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">      </span>- <span class="nt">PolicyName</span><span class="p">:</span><span class="w"> </span><span class="l">logs</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">        </span><span class="nt">PolicyDocument</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">          </span><span class="nt">Version</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;2012-10-17&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">          </span><span class="nt">Statement</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">          </span>- <span class="nt">Effect</span><span class="p">:</span><span class="w"> </span><span class="l">Allow</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">            </span><span class="nt">Action</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">            </span>- <span class="l">logs:CreateLogGroup</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">            </span>- <span class="l">logs:CreateLogStream</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">            </span>- <span class="l">logs:PutLogEvents</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">            </span><span class="nt">Resource</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;*&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">  </span><span class="nt">LambdaFunction</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">    </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;AWS::Lambda::Function&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">    </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">      </span><span class="nt">FunctionName</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;LambdaTest&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">      </span><span class="nt">Handler</span><span class="p">:</span><span class="w"> </span><span class="l">index.handler</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">      </span><span class="nt">Runtime</span><span class="p">:</span><span class="w"> </span><span class="l">nodejs18.x</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">      </span><span class="nt">Role</span><span class="p">:</span><span class="w"> </span>!<span class="l">GetAtt LambdaExecutionRole.Arn</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">      </span><span class="nt">Code</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">        </span><span class="nt">ZipFile</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="sd">          exports.handler = async (event) =&gt; {
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="sd">            return &#39;Hello World!&#39;
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="sd">          }</span><span class="w">          </span></span></span></code></pre></div><p>The  <code>LambdaTest</code> function defaults to writing log events to a group named <code>/aws/lambda/LambdaTest</code> with a default retention of <code>Never expire</code>. To circumvent this behavior, a <code>AWS::Logs::LogGroup</code> resource can be explicitly created.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nt">AWSTemplateFormatVersion</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;2010-09-09&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="nt">Resources</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">  </span><span class="nt">LambdaFunctionLogGroup</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">      </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;AWS::Logs::LogGroup&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">      </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">        </span><span class="nt">LogGroupName</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;/aws/lambda/LambdaTest&#34;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">        </span><span class="nt">RetentionInDays</span><span class="p">:</span><span class="w"> </span><span class="m">1</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">  </span><span class="nt">LambdaFunction</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;AWS::Lambda::Function&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span><span class="nt">DependsOn</span><span class="p">:</span><span class="w"> </span><span class="l">LambdaFunctionLogGroup</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">    </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">      </span><span class="nt">FunctionName</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;LambdaTest&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">      </span><span class="nt">Handler</span><span class="p">:</span><span class="w"> </span><span class="l">index.handler</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">      </span><span class="nt">Runtime</span><span class="p">:</span><span class="w"> </span><span class="l">nodejs18.x</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">      </span><span class="nt">Role</span><span class="p">:</span><span class="w"> </span>!<span class="l">GetAtt LambdaExecutionRole.Arn</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">      </span><span class="nt">Code</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">        </span><span class="nt">ZipFile</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="sd">          exports.handler = async (event) =&gt; {
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="sd">            return &#39;Hello World!&#39;
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="sd">          }</span><span class="w">          
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">  </span><span class="nt">LambdaExecutionRole</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">    </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;AWS::IAM::Role&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">    </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">      </span><span class="nt">AssumeRolePolicyDocument</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">        </span><span class="nt">Version</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;2012-10-17&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">        </span><span class="nt">Statement</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">        </span>- <span class="nt">Effect</span><span class="p">:</span><span class="w"> </span><span class="l">Allow</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">          </span><span class="nt">Principal</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">            </span><span class="nt">Service</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">            </span>- <span class="l">lambda.amazonaws.com</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">          </span><span class="nt">Action</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">          </span>- <span class="l">sts:AssumeRole</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">      </span><span class="nt">Policies</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">      </span>- <span class="nt">PolicyName</span><span class="p">:</span><span class="w"> </span><span class="l">logs</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">        </span><span class="nt">PolicyDocument</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">          </span><span class="nt">Version</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;2012-10-17&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w">          </span><span class="nt">Statement</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="w">          </span>- <span class="nt">Effect</span><span class="p">:</span><span class="w"> </span><span class="l">Allow</span><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="w">            </span><span class="nt">Action</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="w">            </span>- <span class="l">logs:CreateLogGroup</span><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w">            </span>- <span class="l">logs:CreateLogStream</span><span class="w">
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="w">            </span>- <span class="l">logs:PutLogEvents</span><span class="w">
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="w">            </span><span class="nt">Resource</span><span class="p">:</span><span class="w"> </span>!<span class="l">GetAtt LambdaFunctionLogGroup.Arn</span></span></span></code></pre></div><p>A few aspects are different:</p>
<ol>
<li>A new <code>AWS::Logs::LogGroup</code> was created with a retention period of 1 day</li>
<li>The <code>LambdaTest</code> resource uses <code>DependsOn: LambdaFunctionLogGroup</code></li>
<li>The <code>LambdaExecutionRole</code> only allows writing logs to the <code>LambdaFunctionLogGroup.Arn</code> resource</li>
</ol>
<p><strong>Warning</strong>: If the log group already exists from a prior deployment, it will need to be deleted.</p>
]]></content:encoded></item><item><title>What does PHONY mean in a Makefile</title><link>https://how.wtf/what-does-phony-mean-in-a-makefile.html</link><pubDate>Sun, 26 Mar 2023 01:35:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/what-does-phony-mean-in-a-makefile.html</guid><description>What does .PHONY mean in a Makefile? The make manual describes the .PHONY target as,
A phony target is one that is not really the name of a file; rather it is just a name for a recipe to be executed when you make an explicit request.
However, what does this mean?
What is .PHONY in a makefile? By default, targets are &amp;ldquo;target files&amp;rdquo;. For the following rule,
1hello.txt: dependency.txt 2 echo &amp;#34;hello world&amp;#34; &amp;gt; hello.</description><content:encoded><![CDATA[<p>What does <code>.PHONY</code> mean in a Makefile? The <code>make</code> <a href="https://www.gnu.org/software/make/manual/make.html#Phony-Targets">manual</a> describes the <code>.PHONY</code> target as,</p>
<blockquote>
<p>A phony target is one that is not really the name of a file; rather it is just a name for a recipe to be executed when you make an explicit request.</p>
</blockquote>
<p>However, what does this mean?</p>
<h2 id="what-is-phony-in-a-makefile">What is <code>.PHONY</code> in a makefile?</h2>
<p>By default, targets are &ldquo;target files&rdquo;. For the following rule,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="ln">1</span><span class="cl"><span class="nf">hello.txt</span><span class="o">:</span> <span class="n">dependency</span>.<span class="n">txt</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">	<span class="nb">echo</span> <span class="s2">&#34;hello world&#34;</span> &gt; hello.txt
</span></span></code></pre></div><p><code>make</code> asks: &ldquo;Is <code>hello.txt</code> out of date?&rdquo; To determine if it is out of date, it follows the logic:</p>
<ol>
<li>If <code>hello.txt</code> exists, is <code>dependency.txt</code> more recent than <code>hello.txt</code>? If so, run the instructions.</li>
<li>If <code>hello.txt</code> does not exist, run the instructions.</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">&gt; touch dependency.txt
</span></span><span class="line"><span class="ln">2</span><span class="cl">&gt; make hello.txt
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;hello world&#34;</span> &gt; hello.txt
</span></span><span class="line"><span class="ln">4</span><span class="cl">&gt; make hello.txt
</span></span><span class="line"><span class="ln">5</span><span class="cl">make: <span class="s1">&#39;hello.txt&#39;</span> is up to date.
</span></span><span class="line"><span class="ln">6</span><span class="cl">&gt; <span class="nb">echo</span> <span class="s2">&#34;update&#34;</span> &gt; dependency.txt
</span></span><span class="line"><span class="ln">7</span><span class="cl">&gt; make hello.txt
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;hello world&#34;</span> &gt; hello.txt</span></span></code></pre></div><p>However, for targets that do not output files, a <code>.PHONY</code> label is used. In the following rule,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="ln">1</span><span class="cl"><span class="nf">.PHONY</span><span class="o">:</span> <span class="n">format</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nf">format</span><span class="o">:</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">	gofmt -s -w .
</span></span></code></pre></div><p>the <code>format</code> target formats <code>go</code> code. It does <em>not</em> produce a file.</p>
<h2 id="why-is-phony-important-in-a-makefile">Why is <code>.PHONY</code> important in a makefile?</h2>
<p>For some cases, <code>.PHONY</code> is not needed. For example,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="ln">1</span><span class="cl"><span class="nf">lint</span><span class="o">:</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">	golangci-lint run
</span></span></code></pre></div><p>the <code>lint</code> target surfaces various code issues. As long as a file named <code>lint</code> does not exist (or will not exist in the future), this command will continue working. From the <code>make</code> perspective, <code>lint</code> will always be out of date since the file will never exist.</p>
<p>The <code>.PHONY</code> is only important if a target&rsquo;s name can collide with a file name.</p>
]]></content:encoded></item><item><title>List public IP addresses of EC2 instances using AWS CLI</title><link>https://how.wtf/list-public-ip-addresses-of-ec2-instances-using-aws-cli.html</link><pubDate>Sat, 25 Mar 2023 00:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/list-public-ip-addresses-of-ec2-instances-using-aws-cli.html</guid><description>Listing all public IP addresses of EC2 instances can be completed using the --query argument.
1aws ec2 describe-instances \ 2 --query &amp;#34;Reservations[*].Instances[*].PublicIpAddress&amp;#34; \ 3 --output text</description><content:encoded><![CDATA[<p>Listing all public IP addresses of EC2 instances can be completed using the <code>--query</code> argument.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws ec2 describe-instances <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --query <span class="s2">&#34;Reservations[*].Instances[*].PublicIpAddress&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --output text</span></span></code></pre></div>]]></content:encoded></item><item><title>Turn off the pager for AWS CLI</title><link>https://how.wtf/turn-off-the-pager-for-aws-cli.html</link><pubDate>Fri, 24 Mar 2023 20:00:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/turn-off-the-pager-for-aws-cli.html</guid><description>Disabling the AWS CLI pager can be completed in three different ways.
Disable the pager via environment variable Setting the AWS_PAGER environment variable will disable the pager.
1export AWS_PAGER= 2aws s3 lsDisable the pager via configuration In AWS CLI V2, support for a cli_pager profile option was added. In the ~/.aws/config file, the cli_pager may be used.
1[default] 2cli_pager=Disable the pager via CLI argument A global argument named --no-cli-pager exists to disable the AWS CLI pager per command usage.</description><content:encoded><![CDATA[<p>Disabling the AWS CLI pager can be completed in three different ways.</p>
<h2 id="disable-the-pager-via-environment-variable">Disable the pager via environment variable</h2>
<p>Setting the <code>AWS_PAGER</code> environment variable will disable the pager.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">export</span> <span class="nv">AWS_PAGER</span><span class="o">=</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">aws s3 ls</span></span></code></pre></div><h2 id="disable-the-pager-via-configuration">Disable the pager via configuration</h2>
<p>In AWS CLI V2, support for a <code>cli_pager</code> profile option was added. In the  <code>~/.aws/config</code> file, the <code>cli_pager</code> may be used.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">[default]
</span></span><span class="line"><span class="ln">2</span><span class="cl">cli_pager=</span></span></code></pre></div><h2 id="disable-the-pager-via-cli-argument">Disable the pager via CLI argument</h2>
<p>A global argument named <code>--no-cli-pager</code> exists to disable the AWS CLI pager <em>per</em> command usage.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws s3 ls --no-cli-pager</span></span></code></pre></div>]]></content:encoded></item><item><title>Use multiple AWS accounts using AWS CLI</title><link>https://how.wtf/use-multiple-aws-accounts-using-aws-cli.html</link><pubDate>Thu, 23 Mar 2023 00:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/use-multiple-aws-accounts-using-aws-cli.html</guid><description>Using multiple AWS accounts from the command line is natively handled with profiles in the AWS CLI.
Using aws configure Using the aws configure command, multiple profiles can be configured.
1aws configure --profile account1 2AWS Access Key ID [None]: ... 3AWS Secret Access Key [None]: ... 4Default region name [None]: ... 5Default output format [None]: ...Then, the --profile account1 option may be used with future commands.
1aws s3 ls --profile account1Or an environment variable may be set.</description><content:encoded><![CDATA[<p>Using multiple AWS accounts from the command line is natively handled with profiles in the AWS CLI.</p>
<h2 id="using-aws-configure">Using <code>aws configure</code></h2>
<p>Using the <code>aws configure</code> command, multiple profiles can be configured.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws configure --profile account1
</span></span><span class="line"><span class="ln">2</span><span class="cl">AWS Access Key ID <span class="o">[</span>None<span class="o">]</span>: ...
</span></span><span class="line"><span class="ln">3</span><span class="cl">AWS Secret Access Key <span class="o">[</span>None<span class="o">]</span>: ...
</span></span><span class="line"><span class="ln">4</span><span class="cl">Default region name <span class="o">[</span>None<span class="o">]</span>: ...
</span></span><span class="line"><span class="ln">5</span><span class="cl">Default output format <span class="o">[</span>None<span class="o">]</span>: ...</span></span></code></pre></div><p>Then, the <code>--profile account1</code> option may be used with future commands.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws s3 ls --profile account1</span></span></code></pre></div><p>Or an environment variable may be set.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">export</span> <span class="nv">AWS_PROFILE</span><span class="o">=</span>account1
</span></span><span class="line"><span class="ln">2</span><span class="cl">aws s3 ls <span class="c1"># uses account1 credentials</span></span></span></code></pre></div><p>Note: If the profile is named <code>--profile default</code>, it will represent the default profile when no <code>--profile</code> argument is provided.</p>
<h2 id="manually-setting-credentials">Manually setting credentials</h2>
<p>The <code>~/.aws/credentials</code> and <code>~/.aws/config</code> files can be modified directly.</p>
<ol>
<li>Add the credentials to the <code>~/.aws/credentials</code> file</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">[default]
</span></span><span class="line"><span class="ln">2</span><span class="cl">aws_access_key_id=accesskey
</span></span><span class="line"><span class="ln">3</span><span class="cl">aws_secret_access_key=secretaccesskey
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl">[account1]
</span></span><span class="line"><span class="ln">6</span><span class="cl">aws_access_key_id=accesskey
</span></span><span class="line"><span class="ln">7</span><span class="cl">aws_secret_access_key=secretaccesskey</span></span></code></pre></div><ol start="2">
<li>Add the profile to the <code>~/.aws/config</code> file</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">[default]
</span></span><span class="line"><span class="ln">2</span><span class="cl">region=us-east-1
</span></span><span class="line"><span class="ln">3</span><span class="cl">output=json
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl">[profile account1]
</span></span><span class="line"><span class="ln">6</span><span class="cl">region=us-east-1
</span></span><span class="line"><span class="ln">7</span><span class="cl">output=json</span></span></code></pre></div><ol start="3">
<li>Use the <code>--profile</code> argument <em>or</em> set the <code>AWS_PROFILE</code> environment variable.</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws s3 ls --profile account1</span></span></code></pre></div><p>OR</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">export</span> <span class="nv">AWS_PROFILE</span><span class="o">=</span>account1
</span></span><span class="line"><span class="ln">2</span><span class="cl">aws s3 ls <span class="c1"># uses account1 credentials</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Filter S3 files in bucket by pattern using AWS CLI</title><link>https://how.wtf/filter-s3-files-in-bucket-by-pattern-using-aws-cli.html</link><pubDate>Wed, 22 Mar 2023 00:25:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/filter-s3-files-in-bucket-by-pattern-using-aws-cli.html</guid><description>Filtering S3 files using a pattern, or finding all files in an S3 bucket that contain a substring can be completed using the AWS CLI.
Filter by S3 object prefix If the S3 object prefix is predictable, a quick solution is using the native --prefix argument.
1aws s3api list-objects-v2 \ 2 --bucket BUCKET_NAME \ 3 --prefix PREFIX_STRINGOutput:
1{ 2 &amp;#34;Contents&amp;#34;:[ 3 { 4 &amp;#34;Key&amp;#34;:&amp;#34;prefix/&amp;#34;, 5 &amp;#34;LastModified&amp;#34;:&amp;#34;2021-11-22T07:51:03+00:00&amp;#34;, 6 &amp;#34;ETag&amp;#34;:&amp;#34;...&amp;#34;, 7 &amp;#34;Size&amp;#34;:0, 8 &amp;#34;StorageClass&amp;#34;:&amp;#34;STANDARD&amp;#34; 9 }, 10 { 11 &amp;#34;Key&amp;#34;:&amp;#34;prefix/example.</description><content:encoded><![CDATA[<p>Filtering S3 files using a pattern, or finding all files in an S3 bucket that contain a substring can be completed using the AWS CLI.</p>
<h2 id="filter-by-s3-object-prefix">Filter by S3 object prefix</h2>
<p>If the S3 object prefix is predictable, a quick solution is using the native <code>--prefix</code> argument.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws s3api list-objects-v2 <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	--bucket BUCKET_NAME <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	--prefix PREFIX_STRING</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">	<span class="nt">&#34;Contents&#34;</span><span class="p">:[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">		<span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">			<span class="nt">&#34;Key&#34;</span><span class="p">:</span><span class="s2">&#34;prefix/&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">			<span class="nt">&#34;LastModified&#34;</span><span class="p">:</span><span class="s2">&#34;2021-11-22T07:51:03+00:00&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">			<span class="nt">&#34;ETag&#34;</span><span class="p">:</span><span class="s2">&#34;...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">			<span class="nt">&#34;Size&#34;</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">			<span class="nt">&#34;StorageClass&#34;</span><span class="p">:</span><span class="s2">&#34;STANDARD&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">		<span class="p">},</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">		<span class="p">{</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">			<span class="nt">&#34;Key&#34;</span><span class="p">:</span><span class="s2">&#34;prefix/example.txt&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">			<span class="nt">&#34;LastModified&#34;</span><span class="p">:</span><span class="s2">&#34;2021-12-12T17:18:32+00:00&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">			<span class="nt">&#34;ETag&#34;</span><span class="p">:</span><span class="s2">&#34;...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">			<span class="nt">&#34;Size&#34;</span><span class="p">:</span><span class="mi">1646</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">			<span class="nt">&#34;StorageClass&#34;</span><span class="p">:</span><span class="s2">&#34;STANDARD&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">	<span class="p">]</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="find-s3-objects-containing-keywordsubstring">Find S3 objects containing keyword/substring</h2>
<p>To find all S3 object keys that contain a certain substring, the <code>--query</code> argument can be utilized.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws s3api list-objects-v2 <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	--bucket BUCKET_NAME <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	--query <span class="s2">&#34;Contents[?contains(Key, `SEARCH_PATTERN`)]&#34;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">	<span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">		<span class="nt">&#34;Key&#34;</span><span class="p">:</span><span class="s2">&#34;name-with-substring&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">		<span class="nt">&#34;LastModified&#34;</span><span class="p">:</span><span class="s2">&#34;2021-12-12T17:18:32+00:00&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">		<span class="nt">&#34;ETag&#34;</span><span class="p">:</span><span class="s2">&#34;...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">		<span class="nt">&#34;Size&#34;</span><span class="p">:</span><span class="mi">1646</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">		<span class="nt">&#34;StorageClass&#34;</span><span class="p">:</span><span class="s2">&#34;STANDARD&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">	<span class="p">},</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">	<span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">		<span class="nt">&#34;Key&#34;</span><span class="p">:</span><span class="s2">&#34;another-name-with-substring&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">		<span class="nt">&#34;LastModified&#34;</span><span class="p">:</span><span class="s2">&#34;2021-11-22T07:52:45+00:00&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">		<span class="nt">&#34;ETag&#34;</span><span class="p">:</span><span class="s2">&#34;...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">		<span class="nt">&#34;Size&#34;</span><span class="p">:</span><span class="mi">1645</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">		<span class="nt">&#34;StorageClass&#34;</span><span class="p">:</span><span class="s2">&#34;STANDARD&#34;</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="p">]</span></span></span></code></pre></div>]]></content:encoded></item><item><title>STS assume role in one command using AWS CLI</title><link>https://how.wtf/sts-assume-role-in-one-command-using-aws-cli.html</link><pubDate>Tue, 21 Mar 2023 00:00:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/sts-assume-role-in-one-command-using-aws-cli.html</guid><description>In order to assume a role, two actions must normally be completed.
How to assume role with STS 1aws sts assume-role \ 2 --role-arn ROLE \ 3 --role-session-name testOutput:
1{ 2 &amp;#34;Credentials&amp;#34;: { 3 &amp;#34;AccessKeyId&amp;#34;: &amp;#34;...&amp;#34;, 4 &amp;#34;SecretAccessKey&amp;#34;: &amp;#34;...&amp;#34;, 5 &amp;#34;SessionToken&amp;#34;: &amp;#34;...&amp;#34;, 6 &amp;#34;Expiration&amp;#34;: &amp;#34;2023-03-21T11:32:58+00:00&amp;#34; 7 }, 8 &amp;#34;AssumedRoleUser&amp;#34;: { 9 &amp;#34;AssumedRoleId&amp;#34;: &amp;#34;...&amp;#34;, 10 &amp;#34;Arn&amp;#34;: &amp;#34;...&amp;#34; 11 } 12}then, export the credentials in the next step
1export AWS_ACCESS_KEY_ID=&amp;#34;...&amp;#34; 2export AWS_SECRET_ACCESS_KEY=&amp;#34;...&amp;#34; 3export AWS_SESSION_TOKEN=&amp;#34;.</description><content:encoded><![CDATA[<p>In order to assume a role, two actions must normally be completed.</p>
<h2 id="how-to-assume-role-with-sts">How to assume role with STS</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws sts assume-role <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>	--role-arn ROLE <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	--role-session-name test</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">	<span class="nt">&#34;Credentials&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">		<span class="nt">&#34;AccessKeyId&#34;</span><span class="p">:</span> <span class="s2">&#34;...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">		<span class="nt">&#34;SecretAccessKey&#34;</span><span class="p">:</span> <span class="s2">&#34;...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">		<span class="nt">&#34;SessionToken&#34;</span><span class="p">:</span> <span class="s2">&#34;...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">		<span class="nt">&#34;Expiration&#34;</span><span class="p">:</span> <span class="s2">&#34;2023-03-21T11:32:58+00:00&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">	<span class="p">},</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">	<span class="nt">&#34;AssumedRoleUser&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">		<span class="nt">&#34;AssumedRoleId&#34;</span><span class="p">:</span> <span class="s2">&#34;...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">		<span class="nt">&#34;Arn&#34;</span><span class="p">:</span> <span class="s2">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>then, export the credentials in the next step</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">export</span> <span class="nv">AWS_ACCESS_KEY_ID</span><span class="o">=</span><span class="s2">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">export</span> <span class="nv">AWS_SECRET_ACCESS_KEY</span><span class="o">=</span><span class="s2">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">export</span> <span class="nv">AWS_SESSION_TOKEN</span><span class="o">=</span><span class="s2">&#34;...&#34;</span></span></span></code></pre></div><h2 id="how-to-assume-role-in-one-command">How to assume role in one command</h2>
<p>Manually exporting the credentials is a tedious process; however, the command can be simplified to export in <em>one</em> line.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">export</span> <span class="k">$(</span><span class="nb">printf</span> <span class="s2">&#34;AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s AWS_SESSION_TOKEN=%s&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span><span class="k">$(</span>aws sts assume-role <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	--role-arn arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>	--role-session-name SESSION_NAME <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>	--query <span class="s2">&#34;Credentials.[AccessKeyId,SecretAccessKey,SessionToken]&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="se"></span>	--output text<span class="k">))</span></span></span></code></pre></div><p>This solution uses the <code>printf</code> built-in.</p>
]]></content:encoded></item><item><title>Invalid base64 error Lambda AWS CLI</title><link>https://how.wtf/invalid-base64-error-lambda-aws-cli.html</link><pubDate>Mon, 20 Mar 2023 01:20:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/invalid-base64-error-lambda-aws-cli.html</guid><description>The Invalid base64 error occurs when invoking a lambda from the AWS CLI because the default --payload parameter expects base64 encoding.
1aws lambda invoke --function-name test --payload &amp;#39;{&amp;#34;movie&amp;#34;: &amp;#34;John Wick&amp;#34;}&amp;#39; response.jsonError output:
1Invalid base64: &amp;#34;{&amp;#34;movie&amp;#34;: &amp;#34;John Wick&amp;#34;}&amp;#34;Solve Invalid base64 lambda invoke error To solve the Invalid base64 error, supply the --cli-binary-format parameter with the value raw-in-base64-out:
1aws lambda invoke --function-name test --cli-binary-format raw-in-base64-out --payload &amp;#39;{&amp;#34;movie&amp;#34;: &amp;#34;John Wick&amp;#34;}&amp;#39; response.jsonOutput:
1{ 2 &amp;#34;StatusCode&amp;#34;: 200, 3 &amp;#34;ExecutedVersion&amp;#34;: &amp;#34;$LATEST&amp;#34; 4}Invoke a lambda using a file A user may opt to supply a .</description><content:encoded><![CDATA[<p>The <strong>Invalid base64</strong> error occurs when invoking a lambda from the AWS CLI because the default <code>--payload</code> parameter expects <code>base64</code> encoding.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws lambda invoke --function-name <span class="nb">test</span> --payload <span class="s1">&#39;{&#34;movie&#34;: &#34;John Wick&#34;}&#39;</span> response.json</span></span></code></pre></div><p>Error output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">Invalid base64: <span class="s2">&#34;{&#34;</span>movie<span class="s2">&#34;: &#34;</span>John Wick<span class="s2">&#34;}&#34;</span></span></span></code></pre></div><h2 id="solve-invalid-base64-lambda-invoke-error">Solve <code>Invalid base64</code> lambda invoke error</h2>
<p>To solve the <strong>Invalid base64</strong> error, supply the <code>--cli-binary-format</code> parameter with the value <code>raw-in-base64-out</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws lambda invoke --function-name <span class="nb">test</span> --cli-binary-format raw-in-base64-out --payload <span class="s1">&#39;{&#34;movie&#34;: &#34;John Wick&#34;}&#39;</span> response.json</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">	<span class="nt">&#34;StatusCode&#34;</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">	<span class="nt">&#34;ExecutedVersion&#34;</span><span class="p">:</span> <span class="s2">&#34;$LATEST&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="invoke-a-lambda-using-a-file">Invoke a lambda using a file</h2>
<p>A user may opt to supply a <code>.json</code> file:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">	<span class="nt">&#34;movie&#34;</span><span class="p">:</span> <span class="s2">&#34;John Wick&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws lambda invoke --function-name <span class="nb">test</span> --cli-binary-format raw-in-base64-out --payload file://request.json response.json</span></span></code></pre></div>]]></content:encoded></item><item><title>Add new element to JSON array with jq</title><link>https://how.wtf/add-new-element-to-json-array-with-jq.html</link><pubDate>Sun, 19 Mar 2023 01:15:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/add-new-element-to-json-array-with-jq.html</guid><description>Adding a new element to an existing JSON array can be completed using jq.
Add element to existing array of objects using jq This is a generic projects.json file:
1{ 2 &amp;#34;projects&amp;#34;: [ 3 { 4 &amp;#34;id&amp;#34;: 1, 5 &amp;#34;version&amp;#34;: &amp;#34;2.3.0&amp;#34; 6 }, 7 { 8 &amp;#34;id&amp;#34;: 2, 9 &amp;#34;version&amp;#34;: &amp;#34;1.54.0&amp;#34; 10 } 11 ] 12}Appending a new element to the array can be completed in two ways:
1. += []</description><content:encoded><![CDATA[<p>Adding a new element to an existing JSON array can be completed using <code>jq</code>.</p>
<h2 id="add-element-to-existing-array-of-objects-using-jq">Add element to existing array of objects using <code>jq</code></h2>
<p>This is a generic <code>projects.json</code> file:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">	<span class="nt">&#34;projects&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">		<span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">			<span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">			<span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;2.3.0&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">		<span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">		<span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">			<span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">			<span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;1.54.0&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">	<span class="p">]</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Appending a new element to the array can be completed in two ways:</p>
<p><strong>1. <code>+= []</code></strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">cat projects.json <span class="p">|</span> jq <span class="s1">&#39;.projects += [{
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s1">	&#34;id&#34;: 3,
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="s1">	&#34;version&#34;: &#34;5.4.1&#34;
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="s1">}]&#39;</span></span></span></code></pre></div><p><strong>2. <code>|=</code></strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">jq <span class="s1">&#39;.projects[.projects | length] = {
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s1">	&#34;id&#34;: 3,
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="s1">	&#34;version&#34;: &#34;5.4.1&#34;
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="s1">}&#39;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">	<span class="nt">&#34;projects&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">		<span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">			<span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">			<span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;2.3.0&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">		<span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">		<span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">			<span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">			<span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;1.54.0&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">		<span class="p">},</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">		<span class="p">{</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">			<span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">			<span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;5.4.1&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">	<span class="p">]</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="add-element-to-existing-array-of-strings-using-jq">Add element to existing array of strings using <code>jq</code></h2>
<p>Similarly with strings:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;[&#34;id1&#34;]&#39;</span> <span class="p">|</span> jq <span class="s1">&#39;. += [&#34;id2&#34;]&#39;</span></span></span></code></pre></div><p><em>or</em></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;[&#34;id1&#34;]&#39;</span> <span class="p">|</span> jq <span class="s1">&#39;.[. | length] = &#34;id2&#34;&#39;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">	<span class="s2">&#34;id1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">	<span class="s2">&#34;id2&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">]</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Passing variables to jq</title><link>https://how.wtf/passing-variables-to-jq.html</link><pubDate>Sat, 18 Mar 2023 01:40:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/passing-variables-to-jq.html</guid><description>Passing a shell / bash variable / environment variable to jq is simple using the native functionality of:
--arg name value or --argjson name value.
How to pass variable to jq filters This is a generic projects.json file:
1{ 2 &amp;#34;projects&amp;#34;: [ 3 { 4 &amp;#34;name&amp;#34;: &amp;#34;project 1&amp;#34;, 5 &amp;#34;owner&amp;#34;: &amp;#34;owner 1&amp;#34;, 6 &amp;#34;id&amp;#34;: 1, 7 &amp;#34;version&amp;#34;: &amp;#34;2.3.0&amp;#34; 8 }, 9 { 10 &amp;#34;name&amp;#34;: &amp;#34;project 2&amp;#34;, 11 &amp;#34;owner&amp;#34;: &amp;#34;owner 1&amp;#34;, 12 &amp;#34;id&amp;#34;: 2, 13 &amp;#34;version&amp;#34;: &amp;#34;1.</description><content:encoded><![CDATA[<p>Passing a shell / bash variable / environment variable to <code>jq</code> is simple using the native functionality of:</p>
<p><code>--arg name value</code> <em>or</em> <code>--argjson name value</code>.</p>
<h2 id="how-to-pass-variable-to-jq-filters">How to pass variable to <code>jq</code> filters</h2>
<p>This is a generic <code>projects.json</code> file:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">	<span class="nt">&#34;projects&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">		<span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">			<span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;project 1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">			<span class="nt">&#34;owner&#34;</span><span class="p">:</span> <span class="s2">&#34;owner 1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">			<span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">			<span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;2.3.0&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">		<span class="p">},</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">		<span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">			<span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;project 2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">			<span class="nt">&#34;owner&#34;</span><span class="p">:</span> <span class="s2">&#34;owner 1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">			<span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">			<span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;1.54.0&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">		<span class="p">},</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">		<span class="p">{</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">			<span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;project 3&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">			<span class="nt">&#34;owner&#34;</span><span class="p">:</span> <span class="s2">&#34;owner 2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">			<span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">			<span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;4.9.2&#34;</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">	<span class="p">]</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h3 id="string-variables">String variables</h3>
<p>Retrieve project information via a name supplied by a user.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Enter name: &#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">read</span> name
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl">cat projects.json <span class="p">|</span> 
</span></span><span class="line"><span class="ln">5</span><span class="cl">	jq -r --arg n <span class="s2">&#34;</span><span class="nv">$name</span><span class="s2">&#34;</span> <span class="s1">&#39;.projects[]|select(.name == $n)&#39;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">Enter name: 
</span></span><span class="line"><span class="ln">2</span><span class="cl">project <span class="m">1</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="o">{</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="s2">&#34;name&#34;</span>: <span class="s2">&#34;project 1&#34;</span>,
</span></span><span class="line"><span class="ln">5</span><span class="cl">  <span class="s2">&#34;owner&#34;</span>: <span class="s2">&#34;owner 1&#34;</span>,
</span></span><span class="line"><span class="ln">6</span><span class="cl">  <span class="s2">&#34;id&#34;</span>: 1,
</span></span><span class="line"><span class="ln">7</span><span class="cl">  <span class="s2">&#34;version&#34;</span>: <span class="s2">&#34;2.3.0&#34;</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="o">}</span></span></span></code></pre></div><p><code>--arg name value</code>: <code>value</code> is automatically interpreted as a string.</p>
<h3 id="number-variables">Number variables</h3>
<p>Retrieve project information via an id supplied by a user.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Enter id: &#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">read</span> id
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl">cat projects.json <span class="p">|</span> 
</span></span><span class="line"><span class="ln">5</span><span class="cl">    jq -r --arg id <span class="s2">&#34;</span><span class="nv">$id</span><span class="s2">&#34;</span> <span class="s1">&#39;.projects[]|select(.id == ($id|tonumber))&#39;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">Enter id: 
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="m">2</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="o">{</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="s2">&#34;name&#34;</span>: <span class="s2">&#34;project 2&#34;</span>,
</span></span><span class="line"><span class="ln">5</span><span class="cl">  <span class="s2">&#34;owner&#34;</span>: <span class="s2">&#34;owner 1&#34;</span>,
</span></span><span class="line"><span class="ln">6</span><span class="cl">  <span class="s2">&#34;id&#34;</span>: 2,
</span></span><span class="line"><span class="ln">7</span><span class="cl">  <span class="s2">&#34;version&#34;</span>: <span class="s2">&#34;1.54.0&#34;</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="o">}</span></span></span></code></pre></div><p><code>--arg name value</code>: <code>value</code> must be explicitly converted to a number using the native <code>tonumber</code> function.</p>
<p>Optionally, <code>--argjson name value</code> may be used in <code>jq</code> versions 1.5 or higher. <code>--argjson</code> respects the value <em>type</em>. Following the same example as before,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Enter id: &#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">read</span> id
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl">cat projects.json <span class="p">|</span> 
</span></span><span class="line"><span class="ln">5</span><span class="cl">    jq -r --argjson id <span class="s2">&#34;</span><span class="nv">$id</span><span class="s2">&#34;</span> <span class="s1">&#39;.projects[]|select(.id == $id)&#39;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">Enter id: 
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="m">2</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="o">{</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="s2">&#34;name&#34;</span>: <span class="s2">&#34;project 2&#34;</span>,
</span></span><span class="line"><span class="ln">5</span><span class="cl">  <span class="s2">&#34;owner&#34;</span>: <span class="s2">&#34;owner 1&#34;</span>,
</span></span><span class="line"><span class="ln">6</span><span class="cl">  <span class="s2">&#34;id&#34;</span>: 2,
</span></span><span class="line"><span class="ln">7</span><span class="cl">  <span class="s2">&#34;version&#34;</span>: <span class="s2">&#34;1.54.0&#34;</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="o">}</span></span></span></code></pre></div>]]></content:encoded></item><item><title>How to source shell scripts in Fish</title><link>https://how.wtf/how-to-source-shell-scripts-in-fish.html</link><pubDate>Fri, 17 Mar 2023 01:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-source-shell-scripts-in-fish.html</guid><description>There may be a use case to source a general sh or bash script in fish. For example, if a function is present in a script file that needs to be sourced, fish cannot execute the script because sh functions are not natively supported.
How to source general scripts in fish Sourcing general scripts in fish is trivial with a plugin named bass. Using a preferred package manager, bass can be installed and used to source scripts.</description><content:encoded><![CDATA[<p>There may be a use case to <code>source</code> a general <code>sh</code> or <code>bash</code> script in <code>fish</code>. For example, if a function is present in a script file that needs to be sourced, <code>fish</code> cannot execute the script because <code>sh</code> functions are not <em>natively</em> supported.</p>
<h2 id="how-to-source-general-scripts-in-fish">How to source general scripts in <code>fish</code></h2>
<p>Sourcing general scripts in <code>fish</code> is trivial with a plugin named <code>bass</code>. Using a preferred package manager, <code>bass</code> can be <a href="https://github.com/edc/bass#installation">installed</a> and used to source scripts.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># variables.sh</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl">example<span class="o">(){</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="nb">export</span> <span class="nv">VAR_NAME</span><span class="o">=</span><span class="nb">test</span>	
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">example</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">source</span> ./variables.sh</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">from sourcing file ./variables.sh
</span></span><span class="line"><span class="ln">2</span><span class="cl">source: Error while reading file “./variables.sh”</span></span></code></pre></div><p>Using <code>bass</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">bass <span class="nb">source</span> ./variables.sh
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">echo</span> <span class="nv">$VAR_NAME</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">test</span></span></code></pre></div>]]></content:encoded></item><item><title>Executing a script with dot vs source in Bash</title><link>https://how.wtf/executing-a-script-with-dot-vs-source-in-bash.html</link><pubDate>Thu, 16 Mar 2023 01:25:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/executing-a-script-with-dot-vs-source-in-bash.html</guid><description>What are the differences between source scriptname.sh, . scriptname.sh and ./scriptname.sh when executing scripts?
Running a program in Bash Executing a script is simple in Bash and many other shells.
1scriptname.shOR
1./scriptname.shThe shell commands above will execute the scriptname.sh script as a separate program from the command line. It may be any type of script.
Sourcing a script in Bash When a file is sourced, it runs in the current user&amp;rsquo;s shell as if the commands were typed out.</description><content:encoded><![CDATA[<p>What are the differences between <code>source scriptname.sh</code>, <code>. scriptname.sh</code> and <code>./scriptname.sh</code> when executing scripts?</p>
<h2 id="running-a-program-in-bash">Running a program in Bash</h2>
<p>Executing a script is simple in Bash <em>and</em> many other shells.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">scriptname.sh</span></span></code></pre></div><p>OR</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">./scriptname.sh</span></span></code></pre></div><p>The shell commands above will execute the <code>scriptname.sh</code> script as a separate program from the command line. It may be any type of script.</p>
<h2 id="sourcing-a-script-in-bash">Sourcing a script in Bash</h2>
<p>When a file is sourced, it runs in the current user&rsquo;s shell as if the commands were typed out.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">. scriptname.sh</span></span></code></pre></div><p>OR</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">source</span> scriptname.sh</span></span></code></pre></div><p>The most common use case is when scripts export environment variables.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">export</span> <span class="nv">ENV_VAR</span><span class="o">=</span>test</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">source</span> test.sh
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">echo</span> <span class="nv">$ENV_VAR</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">test</span></span></code></pre></div>]]></content:encoded></item><item><title>Ternary operator in Python</title><link>https://how.wtf/ternary-operator-in-python.html</link><pubDate>Wed, 15 Mar 2023 01:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/ternary-operator-in-python.html</guid><description>The ternary operator is an in-line if/else statement that many languages support natively; however, Python does not have a specific operator. Instead, it uses conditional expression resolution which was added in Python 2.5.
In-line if/else statement An in-line if/else statement in Python looks like the following:
1&amp;#39;true&amp;#39; if True else &amp;#39;false&amp;#39;Output:
1&amp;#39;true&amp;#39;Breaking down the syntax,
1true_value if condition else false_valueReturn the value of the &amp;ldquo;idle&amp;rdquo; stage for a blue/green deployment.</description><content:encoded><![CDATA[<p>The ternary operator is an in-line if/else statement that many languages support natively; however, Python does not have a specific operator. Instead, it uses <a href="https://mail.python.org/pipermail/python-dev/2005-September/056846.html">conditional expression resolution</a> which was added in Python 2.5.</p>
<h2 id="in-line-ifelse-statement">In-line if/else statement</h2>
<p>An in-line if/else statement in Python looks like the following:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="s1">&#39;true&#39;</span> <span class="k">if</span> <span class="kc">True</span> <span class="k">else</span> <span class="s1">&#39;false&#39;</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">&#39;true&#39;</span></span></code></pre></div><p>Breaking down the syntax,</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">true_value</span> <span class="k">if</span> <span class="n">condition</span> <span class="k">else</span> <span class="n">false_value</span></span></span></code></pre></div><p>Return the value of the &ldquo;idle&rdquo; stage for a blue/green deployment.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">def</span> <span class="nf">get_active_stage</span><span class="p">():</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="c1"># logic to get the active stage</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="k">return</span> <span class="s2">&#34;blue&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">idle_stage</span> <span class="o">=</span> <span class="s2">&#34;green&#34;</span> <span class="k">if</span> <span class="n">get_active_stage</span><span class="p">()</span> <span class="o">==</span> <span class="s2">&#34;blue&#34;</span> <span class="k">else</span> <span class="s2">&#34;blue&#34;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">stage</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">green</span></span></code></pre></div>]]></content:encoded></item><item><title>Grep for contents after pattern match</title><link>https://how.wtf/grep-for-contents-after-pattern-match.html</link><pubDate>Tue, 14 Mar 2023 01:00:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/grep-for-contents-after-pattern-match.html</guid><description>There may be a need to grep for a specific pattern but only capture / echo the contents after the match.
grep will match on any pattern you supply; however, what if a user wants to capture the status of a particular host in the following file?
1hostname1: bad 2hostname2: good 3hostname3: good 4hostname4: badGet contents after grep match using sed Using a combination of grep and sed, this can be accomplished:</description><content:encoded><![CDATA[<p>There may be a need to grep for a specific pattern but only capture / echo the contents <em>after</em> the match.</p>
<p><code>grep</code> will match on any pattern you supply; however, what if a user wants to capture the status of a particular host in the following file?</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">hostname1: bad
</span></span><span class="line"><span class="ln">2</span><span class="cl">hostname2: good
</span></span><span class="line"><span class="ln">3</span><span class="cl">hostname3: good
</span></span><span class="line"><span class="ln">4</span><span class="cl">hostname4: bad</span></span></code></pre></div><h2 id="get-contents-after-grep-match-using-sed">Get contents after <code>grep</code> match using <code>sed</code></h2>
<p>Using a combination of <code>grep</code> and <code>sed</code>, this can be accomplished:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">grep <span class="s1">&#39;hostname1&#39;</span> file.txt <span class="p">|</span> sed <span class="s1">&#39;s/^.*: //&#39;</span></span></span></code></pre></div><p>Evaluation:</p>
<ol>
<li><code>grep</code> matches <em>any</em> line that contains <code>hostname2</code></li>
<li><code>sed</code> replaces (<code>s///</code> substitute) any character (<code>.*</code>) from the beginning of the line (<code>^</code>) until the last occurrence of the sequence <code>:</code> with the empty string of <code> </code>.</li>
</ol>
<p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">bad</span></span></code></pre></div><h2 id="get-contents-after-grep-match-using-awk">Get contents after <code>grep</code> match using <code>awk</code></h2>
<p>If the delimiter is known ahead of time, <code>awk</code> is a simpler approach.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">grep <span class="s1">&#39;hostname2&#39;</span> file.txt <span class="p">|</span> awk <span class="s1">&#39;{print $2}&#39;</span></span></span></code></pre></div><p>Evaluation:</p>
<ol>
<li><code>grep</code> matches <em>any</em> line that contains <code>hostname2</code></li>
<li><code>awk</code> prints the second field after the delimiter (which is space by default)
<ol>
<li>use the <code>-F</code> option to switch delimiters: ex. <code>awk -F &quot;,&quot;</code> for commas</li>
</ol>
</li>
</ol>
<p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">good</span></span></code></pre></div><h2 id="get-contents-using-awk-only">Get contents using <code>awk</code> only</h2>
<p><code>awk</code> may optionally be used by itself to extract the value.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">awk <span class="s1">&#39;/hostname4:/ {print $2}&#39;</span> file.txt</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">bad</span></span></code></pre></div>]]></content:encoded></item><item><title>How to pass variables to Makefiles</title><link>https://how.wtf/how-to-pass-variables-to-makefiles.html</link><pubDate>Mon, 13 Mar 2023 01:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-pass-variables-to-makefiles.html</guid><description>Passing variables, exported variables, or .env (dot env) file variables from outside of a Makefile can be completed in a few ways.
Pass variables to Makefile using environment variables Exported environment variables are referenced by name in the Makefile:
1test: 2 @echo $(TEST) 1export TEST=value 2make testOutput:
1valuePass variables to Makefile using command line Similarly, variables may be explicitly passed to make prior to command executions.
1test: 2 @echo $(TEST) 1TEST=value make testOutput:</description><content:encoded><![CDATA[<p>Passing variables, exported variables, or <code>.env</code> (dot env) file variables from outside of a Makefile can be completed in a few ways.</p>
<h2 id="pass-variables-to-makefile-using-environment-variables">Pass variables to Makefile using environment variables</h2>
<p>Exported environment variables are referenced by name in the Makefile:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="ln">1</span><span class="cl"><span class="nf">test</span><span class="o">:</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">	@echo <span class="k">$(</span>TEST<span class="k">)</span>
</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">export</span> <span class="nv">TEST</span><span class="o">=</span>value
</span></span><span class="line"><span class="ln">2</span><span class="cl">make test</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">value</span></span></code></pre></div><h2 id="pass-variables-to-makefile-using-command-line">Pass variables to Makefile using command line</h2>
<p>Similarly, variables may be explicitly passed to <code>make</code> prior to command executions.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="ln">1</span><span class="cl"><span class="nf">test</span><span class="o">:</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">	@echo <span class="k">$(</span>TEST<span class="k">)</span>
</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">TEST</span><span class="o">=</span>value make test</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">value</span></span></code></pre></div><h2 id="pass-variables-using-env-dot-env-files">Pass variables using <code>.env</code> (dot env) files</h2>
<p>Makefiles can contain an <code>include</code> <a href="https://www.gnu.org/software/make/manual/html_node/Include.html">directive</a> which reads one or more files before executing.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="ln">1</span><span class="cl"><span class="err">ifneq</span> <span class="err">(,</span><span class="k">$(</span><span class="nv">wildcard</span> ./.<span class="nv">env</span><span class="k">)</span><span class="err">)</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">	<span class="err">include</span> <span class="err">.env</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">	<span class="k">export</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nv">endif</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nf">test</span><span class="o">:</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">	@echo <span class="k">$(</span>TEST<span class="k">)</span>
</span></span></code></pre></div><p><code>.env</code> file:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">TEST=dotenv</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">dotenv</span></span></code></pre></div>]]></content:encoded></item><item><title>Write a multi-line command in a Makefile</title><link>https://how.wtf/write-a-multi-line-command-in-a-makefile.html</link><pubDate>Sun, 12 Mar 2023 09:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/write-a-multi-line-command-in-a-makefile.html</guid><description>Occasionally, there is a need for adding multiple continuous lines for one target in a Makefile.
Writing multiple lines for a target Executing multiple commands in a target is trivial:
1test: 2 @echo 1 3 @echo 2 Output:
11 22However, each line is executed in its own shell. If a continuous line is needed, the following rules must be applied:
Use $$ instead of $ Terminate each line using a semicolon ; Add a trailing backslash at the ending of the line \ 1test: 2 var1=test; \ 3 echo $$var1 Output:</description><content:encoded><![CDATA[<p>Occasionally, there is a need for adding multiple continuous lines for one target in a Makefile.</p>
<h2 id="writing-multiple-lines-for-a-target">Writing multiple lines for a target</h2>
<p>Executing multiple commands in a target is trivial:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="ln">1</span><span class="cl"><span class="nf">test</span><span class="o">:</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">	@echo <span class="m">1</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">	@echo <span class="m">2</span>
</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">1
</span></span><span class="line"><span class="ln">2</span><span class="cl">2</span></span></code></pre></div><p>However, each line is executed in its own shell. If a continuous line is needed, the following rules must be applied:</p>
<ol>
<li>Use <code>$$</code> instead of <code>$</code></li>
<li>Terminate each line using a semicolon <code>;</code></li>
<li>Add a trailing backslash at the ending of the line <code>\</code></li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="ln">1</span><span class="cl"><span class="nf">test</span><span class="o">:</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">	<span class="nv">var1</span><span class="o">=</span>test<span class="p">;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>	<span class="nb">echo</span> <span class="nv">$$</span>var1
</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">var1=test; \
</span></span><span class="line"><span class="ln">2</span><span class="cl">echo $var1
</span></span><span class="line"><span class="ln">3</span><span class="cl">test</span></span></code></pre></div><h3 id="a-real-use-case-using-multi-line-targets">A real use case using multi-line targets</h3>
<p>For <code>how.wtf</code>, the CI/CD process invalidates a CloudFront distribution via id.</p>
<p>For context, the <code>aws</code> dependency verifies that <code>aws</code> is executable prior to the command execution. More information on that <a href="https://how.wtf/check-if-a-program-exists-from-a-makefile.html">here</a>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="ln">1</span><span class="cl"><span class="nf">.PHONY</span><span class="o">:</span> <span class="n">invalidate</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nf">invalidate</span><span class="o">:</span> <span class="n">aws</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">	<span class="nv">distribution_id</span><span class="o">=</span><span class="nv">$$</span><span class="o">(</span>aws cloudfront list-distributions --query <span class="s2">&#34;DistributionList.Items[?starts_with(Origins.Items[0].DomainName, &#39;</span><span class="k">$(</span>BUCKET<span class="k">)</span><span class="s2">&#39;)].Id&#34;</span> --output text<span class="o">)</span><span class="p">;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>	aws cloudfront create-invalidation <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>		--distribution-id <span class="nv">$$</span>distribution_id <span class="se">\
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="se"></span>		--paths <span class="s2">&#34;/*&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="se"></span>		--query <span class="s2">&#34;Invalidation.Id&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="se"></span>		--output text
</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">distribution_id=$(aws cloudfront list-distributions --query &#34;DistributionList.Items[?starts_with(Origins.Items[0].DomainName, &#39;how.wtf&#39;)].Id&#34; --output text); \
</span></span><span class="line"><span class="ln">2</span><span class="cl">aws cloudfront create-invalidation \
</span></span><span class="line"><span class="ln">3</span><span class="cl">	--distribution-id $distribution_id \
</span></span><span class="line"><span class="ln">4</span><span class="cl">	--paths &#34;/*&#34; \
</span></span><span class="line"><span class="ln">5</span><span class="cl">	--query &#34;Invalidation.Id&#34; \
</span></span><span class="line"><span class="ln">6</span><span class="cl">	--output text
</span></span><span class="line"><span class="ln">7</span><span class="cl">ID6WOFMWKLCYDYRUA6AGPXXXXX</span></span></code></pre></div><h3 id="writing-multiple-lines-using-oneshell">Writing multiple lines using <code>ONESHELL</code></h3>
<p>The <code>ONESHELL</code> <a href="https://www.gnu.org/software/make/manual/html_node/One-Shell.html">directive</a> allows multiple lines to executed in the same shell; however, special characters like <code>@</code>, <code>-</code>, and <code>+</code> are interpreted differently.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="ln">1</span><span class="cl"><span class="nf">.ONESHELL</span><span class="o">:</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nf">test</span><span class="o">:</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">	<span class="nv">var1</span><span class="o">=</span><span class="nb">test</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">	<span class="nb">echo</span> <span class="nv">$$</span>var1
</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">var1=test
</span></span><span class="line"><span class="ln">2</span><span class="cl">echo $var1
</span></span><span class="line"><span class="ln">3</span><span class="cl">test</span></span></code></pre></div>]]></content:encoded></item><item><title>Check if a program exists from a Makefile</title><link>https://how.wtf/check-if-a-program-exists-from-a-makefile.html</link><pubDate>Sat, 11 Mar 2023 00:50:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/check-if-a-program-exists-from-a-makefile.html</guid><description>A Makefile can check if a shell program or executable exists before running recipes.
Check if all programs exist 1REQUIRED_BINS := hugo terraform aws exiftool jpegoptim optipng mogrify 2$(foreach bin,$(REQUIRED_BINS),\ 3 $(if $(shell command -v $(bin) 2&amp;gt; /dev/null),,$(error Please install `$(bin)`)))This method will run before any make &amp;lt;command&amp;gt; is completed. It ensures that each program listed in REQUIRED_BINS is executable. If not, it will output an error quickly.
Check if a specific program exists If it&amp;rsquo;s preferred to check a shell program before running a specific command, the syntax below will enable for that use-case:</description><content:encoded><![CDATA[<p>A Makefile can check if a shell program or executable exists before running recipes.</p>
<h2 id="check-if-all-programs-exist">Check if all programs exist</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">REQUIRED_BINS</span> <span class="o">:=</span> hugo terraform aws exiftool jpegoptim optipng mogrify
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">$(</span><span class="nv">foreach</span> <span class="nv">bin</span>,<span class="k">$(</span><span class="nv">REQUIRED_BINS</span><span class="k">)</span>,\
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="k">$(</span><span class="nv">if</span> <span class="k">$(</span><span class="nv">shell</span> <span class="nv">command</span> -<span class="nv">v</span> <span class="k">$(</span><span class="nv">bin</span><span class="k">)</span> 2&gt; /<span class="nv">dev</span>/<span class="nv">null</span><span class="k">)</span>,,<span class="k">$(</span><span class="nv">error</span> <span class="nv">Please</span> <span class="nv">install</span> `<span class="k">$(</span><span class="nv">bin</span><span class="k">)</span>`<span class="k">)))</span></span></span></code></pre></div><p>This method will run before <em>any</em> <code>make &lt;command&gt;</code> is completed. It ensures that each program listed in <code>REQUIRED_BINS</code> is executable. If not, it will output an error quickly.</p>
<h2 id="check-if-a-specific-program-exists">Check if a specific program exists</h2>
<p>If it&rsquo;s preferred to check a shell program before running a specific command, the syntax below will enable for that use-case:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nv">tools</span> <span class="o">:=</span> hugo terraform aws exiftool jpegoptim optipng mogrify
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nf">$(tools)</span><span class="o">:</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">	@which <span class="nv">$@</span> &gt; /dev/null
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">	
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="nf">.PHONY</span><span class="o">:</span> <span class="n">serve</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nf">serve</span><span class="o">:</span> <span class="n">hugo</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">	<span class="k">$(</span>HUGO<span class="k">)</span> server -D
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nf">.PHONY</span><span class="o">:</span> <span class="n">validate</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nf">validate</span><span class="o">:</span> <span class="n">terraform</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">	<span class="k">$(</span>TERRAFORM<span class="k">)</span> validate
</span></span></code></pre></div><p>This works by using <a href="https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html">automatic variables</a> with <a href="https://www.gnu.org/savannah-checkouts/gnu/make/manual/html_node/Static-Usage.html">static patterns</a>. All items in <code>tools</code> will become targets. The <code>$@</code> in the recipe will be be substituted with the target&rsquo;s name.</p>
<p>In the example above, <code>make serve</code> will first check if the <code>hugo</code> target is completed. That target runs <code>@which hugo &gt; /dev/null</code>.</p>
]]></content:encoded></item><item><title>Convert OrderedDict to dict in Python</title><link>https://how.wtf/convert-ordereddict-to-dict-in-python.html</link><pubDate>Fri, 10 Mar 2023 00:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/convert-ordereddict-to-dict-in-python.html</guid><description>Upon first glance, converting an OrderedDict seems intuitive.
Convert OrderedDict to dict 1from collections import OrderedDict 2 3od1 = OrderedDict([(&amp;#34;key1&amp;#34;, &amp;#34;value1&amp;#34;), (&amp;#34;key2&amp;#34;, &amp;#34;value2&amp;#34;)]) 4 5d1 = dict(od1) 6print(d1)Output:
1{&amp;#39;key1&amp;#39;: &amp;#39;value1&amp;#39;, &amp;#39;key2&amp;#39;: &amp;#39;value2&amp;#39;}Convert nested OrderedDicts to dict However, if an OrderedDict has nested types of OrderedDicts, this method will not convert the nested OrderedDict types to dictionaries:
1from collections import OrderedDict 2 3od1 = OrderedDict( 4 [ 5 (&amp;#34;key1&amp;#34;, &amp;#34;value1&amp;#34;), 6 (&amp;#34;key2&amp;#34;, &amp;#34;value2&amp;#34;), 7 (&amp;#34;key3&amp;#34;, OrderedDict([(&amp;#34;key3&amp;#34;, &amp;#34;value3&amp;#34;)])), 8 ] 9) 10 11d1 = dict(od1) 12print(d1)Output:</description><content:encoded><![CDATA[<p>Upon first glance, converting an <code>OrderedDict</code> seems intuitive.</p>
<h2 id="convert-ordereddict-to-dict">Convert <code>OrderedDict</code> to <code>dict</code></h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">OrderedDict</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">od1</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">([(</span><span class="s2">&#34;key1&#34;</span><span class="p">,</span> <span class="s2">&#34;value1&#34;</span><span class="p">),</span> <span class="p">(</span><span class="s2">&#34;key2&#34;</span><span class="p">,</span> <span class="s2">&#34;value2&#34;</span><span class="p">)])</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">d1</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">od1</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">d1</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{&#39;key1&#39;: &#39;value1&#39;, &#39;key2&#39;: &#39;value2&#39;}</span></span></code></pre></div><h2 id="convert-nested-ordereddicts-to-dict">Convert nested <code>OrderedDict</code>s to <code>dict</code></h2>
<p>However, if an <code>OrderedDict</code> has nested types of <code>OrderedDict</code>s, this method will not convert the nested <code>OrderedDict</code> types to dictionaries:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">OrderedDict</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">od1</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="p">(</span><span class="s2">&#34;key1&#34;</span><span class="p">,</span> <span class="s2">&#34;value1&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="p">(</span><span class="s2">&#34;key2&#34;</span><span class="p">,</span> <span class="s2">&#34;value2&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="p">(</span><span class="s2">&#34;key3&#34;</span><span class="p">,</span> <span class="n">OrderedDict</span><span class="p">([(</span><span class="s2">&#34;key3&#34;</span><span class="p">,</span> <span class="s2">&#34;value3&#34;</span><span class="p">)])),</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">d1</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">od1</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">d1</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{&#39;key1&#39;: &#39;value1&#39;, &#39;key2&#39;: &#39;value2&#39;, &#39;key3&#39;: OrderedDict([(&#39;key3&#39;, &#39;value3&#39;)])}</span></span></code></pre></div><p>Instead, a combination of <code>json.loads()</code> and <code>json.dumps()</code> can be used.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">OrderedDict</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">od1</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="p">(</span><span class="s2">&#34;key1&#34;</span><span class="p">,</span> <span class="s2">&#34;value1&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="p">(</span><span class="s2">&#34;key2&#34;</span><span class="p">,</span> <span class="s2">&#34;value2&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="p">(</span><span class="s2">&#34;key3&#34;</span><span class="p">,</span> <span class="n">OrderedDict</span><span class="p">([(</span><span class="s2">&#34;key3&#34;</span><span class="p">,</span> <span class="s2">&#34;value3&#34;</span><span class="p">)])),</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">d1</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">od1</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">d1</span><span class="p">)</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{&#39;key1&#39;: &#39;value1&#39;, &#39;key2&#39;: &#39;value2&#39;, &#39;key3&#39;: {&#39;key3&#39;: &#39;value3&#39;}}</span></span></code></pre></div>]]></content:encoded></item><item><title>Set cache control on S3 objects using the AWS CLI</title><link>https://how.wtf/set-cache-control-on-s3-objects-using-the-aws-cli.html</link><pubDate>Thu, 09 Mar 2023 08:20:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/set-cache-control-on-s3-objects-using-the-aws-cli.html</guid><description>Cache-control can be set on S3 bucket objects.
Setting cache control using aws s3 cp An object&amp;rsquo;s metadata may only be changed by overwriting it using the metadata-directive flag.
Single file:
1aws s3 cp s3://bucket/example.txt s3://s3-bucket/file.txt \ 2 --metadata-directive REPLACE \ 3 --cache-control max-age=86400All files:
1aws s3 cp s3://bucket/ s3://bucket/ \ 2 --metadata-directive REPLACE \ 3 --cache-control max-age=86400 \ 4 --recursiveAll image files / specific file extensions
1aws s3 cp s3://bucket/ s3://bucket/ \ 2 --metadata-directive REPLACE \ 3 --cache-control max-age=86400 \ 4 --exclude &amp;#34;*&amp;#34; \ 5 --include &amp;#34;*.</description><content:encoded><![CDATA[<p>Cache-control can be set on S3 bucket objects.</p>
<h2 id="setting-cache-control-using-aws-s3-cp">Setting cache control using <code>aws s3 cp</code></h2>
<p>An object&rsquo;s metadata may only be changed by overwriting it using the <code>metadata-directive</code> flag.</p>
<p>Single file:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws s3 cp s3://bucket/example.txt s3://s3-bucket/file.txt <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --metadata-directive REPLACE <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --cache-control max-age<span class="o">=</span><span class="m">86400</span></span></span></code></pre></div><p>All files:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws s3 cp s3://bucket/ s3://bucket/ <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --metadata-directive REPLACE <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --cache-control max-age<span class="o">=</span><span class="m">86400</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>  --recursive</span></span></code></pre></div><p>All image files / specific file extensions</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws s3 cp s3://bucket/ s3://bucket/ <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --metadata-directive REPLACE <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --cache-control max-age<span class="o">=</span><span class="m">86400</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>  --exclude <span class="s2">&#34;*&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>  --include <span class="s2">&#34;*.jpg&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="se"></span>  --include <span class="s2">&#34;*.gif&#34;</span> <span class="se">\ </span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">  --include <span class="s2">&#34;*.webp&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="se"></span>  --recursive </span></span></code></pre></div><h2 id="setting-cache-control-for-websites-served-by-aws-cloudfront">Setting cache control for websites served by AWS CloudFront</h2>
<p>CloudFront is a CDN service provided by AWS. The <code>max-age</code> directive sets the <strong>browser</strong> caching age in seconds while another directive named <code>s-maxage</code> sets the <strong>CloudFront</strong> caching in seconds.</p>
<p>Choosing from the examples above, add <code>s-maxage=86400</code> to the <code>--cache-control</code> flag for <em>all</em> objects in a bucket.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws s3 cp s3://bucket/ s3://bucket/ <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --metadata-directive REPLACE <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --cache-control max-age<span class="o">=</span>86400,s-maxage<span class="o">=</span><span class="m">86400</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>  --recursive</span></span></code></pre></div><h2 id="setting-cache-control-using-aws-s3-sync">Setting cache control using <code>aws s3 sync</code></h2>
<p><strong>Warning</strong>: Using this option only sets cache headers upon initial sync. The cp command will need to be used to replace headers on existing S3 objects.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws s3 sync /path s3://bucket/ <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --cache-control max-age<span class="o">=</span>86400,s-maxage<span class="o">=</span><span class="m">86400</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Conditionally add properties to an object in JavaScript</title><link>https://how.wtf/conditionally-add-properties-to-an-object-in-javascript.html</link><pubDate>Wed, 08 Mar 2023 08:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/conditionally-add-properties-to-an-object-in-javascript.html</guid><description>Conditionally adding properties/fields/members to an object in JavaScript or TypeScript can be completed using a combination of the logical and spread operators or simply an if statement.
Add conditional properties using if A simple technique is using an if statement to conditionally add members:
1let obj = {} 2if (condition) 3 obj.field = 5;There are no thrills to this technique, but it&amp;rsquo;s straight forward.
Add conditional properties using logical and spread operators For a shorter syntax, ES5 introduced the ability to do this:</description><content:encoded><![CDATA[<p>Conditionally adding properties/fields/members to an object in JavaScript or TypeScript can be completed using a combination of the logical and spread operators or simply an <code>if</code> statement.</p>
<h2 id="add-conditional-properties-using-if">Add conditional properties using <code>if</code></h2>
<p>A simple technique is using an if statement to conditionally add members:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="kd">let</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nx">condition</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nx">obj</span><span class="p">.</span><span class="nx">field</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span></span></span></code></pre></div><p>There are no thrills to this technique, but it&rsquo;s straight forward.</p>
<h2 id="add-conditional-properties-using-logical-and-spread-operators">Add conditional properties using logical and spread operators</h2>
<p>For a shorter syntax, ES5 introduced the ability to do this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="kr">const</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="p">...(</span><span class="nx">condition</span> <span class="o">&amp;&amp;</span> <span class="p">{</span><span class="nx">field</span><span class="o">:</span> <span class="mi">5</span><span class="p">})</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>This technique works due to how logical operators function in JavaScript.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="kc">true</span> <span class="o">&amp;&amp;</span> <span class="p">{</span><span class="nx">field</span><span class="o">:</span> <span class="mi">5</span><span class="p">})</span></span></span></code></pre></div><p>The snippet above is processed as follows: starting from left and traversing right, the first operand that is evaluated as <code>falsy</code> is returned. In the expression above, there are no <code>falsy</code> operands so the right-most is returned.</p>
<p>The output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{field: 5}</span></span></code></pre></div><p>Additionally, the <code>spread</code> operator has a lower precedence than the <code>&amp;&amp;</code> operator because the underlying implementation uses <code>Object.assign()</code></p>
<p>If the condition is false:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="kr">const</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nx">val</span><span class="o">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="p">...(</span><span class="kc">false</span> <span class="o">&amp;&amp;</span> <span class="p">{</span><span class="nx">field</span><span class="o">:</span> <span class="mi">5</span><span class="p">})</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span></span></span></code></pre></div><p>The spread operation will be result in nothing being added.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">{val:2}</span></span></code></pre></div>]]></content:encoded></item><item><title>Run workflow, step, or job based on file changes GitHub Actions</title><link>https://how.wtf/run-workflow-step-or-job-based-on-file-changes-github-actions.html</link><pubDate>Tue, 07 Mar 2023 08:50:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/run-workflow-step-or-job-based-on-file-changes-github-actions.html</guid><description>There are options for conditionally running GitHub actions at the workflow, job, or step level based on file changes.
Trigger GitHub Action workflow on file changes GitHub actions natively support triggering workflows based on file changes:
1on: 2 push: 3 paths: 4 - &amp;#39;src/**&amp;#39; 5 6jobs: 7 job1: 8 steps: 9 - uses: actions/checkout@v3 10 - name: tests 11 run: ...On a push to any file within the src/** directory, this workflow will execute job1 and its steps.</description><content:encoded><![CDATA[<p>There are options for conditionally running GitHub actions at the workflow, job, or step level based on file changes.</p>
<h2 id="trigger-github-action-workflow-on-file-changes">Trigger GitHub Action workflow on file changes</h2>
<p>GitHub actions natively support triggering workflows based on file changes:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">  </span><span class="nt">push</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">    </span><span class="nt">paths</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">    </span>- <span class="s1">&#39;src/**&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">  </span><span class="nt">job1</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v3</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">tests</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">      </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">...</span></span></span></code></pre></div><p>On a push to any file within the <code>src/**</code> directory, this workflow will execute job1 and its steps.</p>
<h2 id="run-job-based-on-file-changes-in-github-actions">Run job based on file changes in GitHub Actions</h2>
<p>GitHub actions do not natively support triggering jobs based on file changes; however, there is a marketplace action that supports this use-case named <a href="https://github.com/dorny/paths-filter">dorny/paths-filter</a>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">  </span><span class="nt">push</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">    </span>- <span class="l">main</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">  </span><span class="nt">changes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="nt">outputs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">      </span><span class="nt">src</span><span class="p">:</span><span class="w"> </span><span class="l">${{ steps.changes.outputs.src }}</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">      </span><span class="nt">infra</span><span class="p">:</span><span class="w"> </span><span class="l">${{ steps.changes.outputs.infra }}</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v3</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">    </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">dorny/paths-filter@v2</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">      </span><span class="nt">id</span><span class="p">:</span><span class="w"> </span><span class="l">changes</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">      </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">        </span><span class="nt">filters</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="sd">          src:
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="sd">            - &#39;src/**&#39;
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="sd">          infra:
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="sd">            - &#39;infra/**&#39;</span><span class="w">          
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">  </span><span class="nt">src</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">    </span><span class="nt">needs</span><span class="p">:</span><span class="w"> </span><span class="l">changes</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">    </span><span class="nt">if</span><span class="p">:</span><span class="w"> </span><span class="l">${{ needs.changes.outputs.src == &#39;true&#39; }}</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">    </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v3</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">    </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">...</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">  </span><span class="nt">infra</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">    </span><span class="nt">needs</span><span class="p">:</span><span class="w"> </span><span class="l">changes</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">    </span><span class="nt">if</span><span class="p">:</span><span class="w"> </span><span class="l">${{ needs.changes.outputs.infra == &#39;true&#39; }}</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">    </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v3</span><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w">    </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">...</span></span></span></code></pre></div><p>On a push to the <code>main</code> branch, this workflow will execute; however, the first action checks where changes occurred and outputs <code>true</code> or <code>false</code> for the specified filtered paths.</p>
<h2 id="run-step-based-on-file-changes-in-github-actions">Run step based on file changes in GitHub Actions</h2>
<p>Similarly to jobs, GitHub actions to not natively support triggering individual steps based on file changes. <a href="https://github.com/dorny/paths-filter">dorny/paths-filter</a> supports this use-case as well.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">  </span><span class="nt">push</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">    </span>- <span class="l">main</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">  </span><span class="nt">job1</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v3</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">dorny/paths-filter@v2</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">      </span><span class="nt">id</span><span class="p">:</span><span class="w"> </span><span class="l">changes</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">      </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">        </span><span class="nt">filters</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="sd">          src:
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="sd">            - &#39;src/**&#39;
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="sd">          infra:
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="sd">            - &#39;infra/**&#39;
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="sd">            </span><span class="w">          
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">    </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">src deploy</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">      </span><span class="nt">if</span><span class="p">:</span><span class="w"> </span><span class="l">steps.changes.outputs.src == &#39;true&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">      </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">...</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">      
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">    </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">infra deploy</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">      </span><span class="nt">if</span><span class="p">:</span><span class="w"> </span><span class="l">steps.changes.outputs.infra == &#39;true&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">      </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">...</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">    
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">    </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">e2e</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">      </span><span class="nt">if</span><span class="p">:</span><span class="w"> </span><span class="l">steps.changes.outputs.src == &#39;true&#39; || steps.changes.outputs.infra == &#39;true&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">      </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">...</span></span></span></code></pre></div><h2 id="pull-requests">Pull requests</h2>
<p>On a side note, <a href="https://github.com/dorny/paths-filter">dorny/paths-filter</a> does <em>not</em> need the checkout action for pull request triggered actions.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">  </span><span class="nt">pull_request</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">    </span>- <span class="l">main</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">  </span><span class="nt">build</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="c"># For pull requests, it&#39;s not necessary to checkout code</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span><span class="nt">permissions</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">      </span><span class="nt">pull-requests</span><span class="p">:</span><span class="w"> </span><span class="l">read</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">dorny/paths-filter@v2</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">      </span><span class="nt">id</span><span class="p">:</span><span class="w"> </span><span class="l">filter</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">      </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">        </span><span class="nt">filters</span><span class="p">:</span><span class="w"> </span><span class="l">...</span><span class="w"> </span><span class="c"># Configure your filters</span></span></span></code></pre></div>]]></content:encoded></item><item><title>How to unadd or uncommit files in Git</title><link>https://how.wtf/how-to-unadd-or-uncommit-files-in-git.html</link><pubDate>Mon, 06 Mar 2023 00:55:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-unadd-or-uncommit-files-in-git.html</guid><description>Occasionally, developers will mistakenly git add or git commit files before pushing to remote. Luckily, there are commands that remediate the situation.
How to unadd a file Unadding a specific file before a commit:
1git reset &amp;lt;file&amp;gt;How to unadd all files Unadding all files before a commit:
1git resetHow to uncommit the last commit If the last commit needs to be uncommitted:
1git reset --soft HEAD~1The command reads as &amp;ldquo;undo the last committed changes and preserve the files&amp;rdquo;.</description><content:encoded><![CDATA[<p>Occasionally, developers will mistakenly <code>git add</code> or <code>git commit</code> files before pushing to remote. Luckily, there are commands that remediate the situation.</p>
<h2 id="how-to-unadd-a-file">How to unadd a file</h2>
<p>Unadding a specific file before a commit:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">git reset &lt;file&gt;</span></span></code></pre></div><h2 id="how-to-unadd-all-files">How to unadd all files</h2>
<p>Unadding all files before a commit:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">git reset</span></span></code></pre></div><h2 id="how-to-uncommit-the-last-commit">How to uncommit the last commit</h2>
<p>If the last commit needs to be uncommitted:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">git reset --soft HEAD~1</span></span></code></pre></div><p>The command reads as &ldquo;undo the last committed changes and preserve the files&rdquo;. If the files do not need to be preserved, <code>--hard</code> may be used.</p>
<p>At this point, the files may be <a href="how-to-unadd-files">unadded if desired</a>.</p>
<h2 id="aliasing">Aliasing</h2>
<p>Aliases allow for ease-of-use in daily workflows:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">git config --global alias.unadd <span class="s1">&#39;reset HEAD --&#39;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">git config --global alias.uncommit <span class="s1">&#39;reset --soft HEAD~1&#39;</span></span></span></code></pre></div><p>Usage:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln"> 1</span><span class="cl">&gt; git add example.txt
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">&gt; git status
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">On branch main
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">Your branch is up to date with <span class="s1">&#39;origin/main&#39;</span>.
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">Changes to be committed:
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  <span class="o">(</span>use <span class="s2">&#34;git restore --staged &lt;file&gt;...&#34;</span> to unstage<span class="o">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">	modified:   example.txt
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl">&gt; git unadd
</span></span><span class="line"><span class="ln">11</span><span class="cl">Unstaged changes after reset:
</span></span><span class="line"><span class="ln">12</span><span class="cl">M	example.txt
</span></span><span class="line"><span class="ln">13</span><span class="cl">&gt; git add example.txt
</span></span><span class="line"><span class="ln">14</span><span class="cl">&gt; git commit -m <span class="s2">&#34;add example.txt&#34;</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="o">[</span>main 1eb1b2f<span class="o">]</span> add example.txt
</span></span><span class="line"><span class="ln">16</span><span class="cl"> <span class="m">1</span> file changed, <span class="m">2</span> insertions<span class="o">(</span>+<span class="o">)</span>, <span class="m">0</span> deletions<span class="o">(</span>-<span class="o">)</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"> create mode <span class="m">100644</span> example.txt
</span></span><span class="line"><span class="ln">18</span><span class="cl">&gt; git uncommit
</span></span><span class="line"><span class="ln">19</span><span class="cl">&gt; git unadd
</span></span><span class="line"><span class="ln">20</span><span class="cl">Unstaged changes after reset:
</span></span><span class="line"><span class="ln">21</span><span class="cl">M	example.txt</span></span></code></pre></div>]]></content:encoded></item><item><title>How to remove or delete a PPA in Ubuntu</title><link>https://how.wtf/how-to-remove-or-delete-a-ppa-in-ubuntu.html</link><pubDate>Sun, 05 Mar 2023 01:15:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-remove-or-delete-a-ppa-in-ubuntu.html</guid><description>PPAs (Personal Package Archive) are third-party collections of packages built and maintained by users.
How to list PPAs installed on the system 1ls /etc/apt/sources.list.d/ 2neovim-ppa-unstable-jammy.listHow to remove a PPA using terminal The recommended way to remove a PPA is to use the apt-add-repository command with the --remove (or -r) option.
1sudo apt-add-repository --remove ppa:PPA_REPOSITORY/PPAExample:
1sudo apt-add-repository -r ppa:neovim-ppa/unstable</description><content:encoded><![CDATA[<p>PPAs (Personal Package Archive) are third-party collections of packages built and maintained by users.</p>
<h2 id="how-to-list-ppas-installed-on-the-system">How to list PPAs installed on the system</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">ls /etc/apt/sources.list.d/
</span></span><span class="line"><span class="ln">2</span><span class="cl">neovim-ppa-unstable-jammy.list</span></span></code></pre></div><h2 id="how-to-remove-a-ppa-using-terminal">How to remove a PPA using terminal</h2>
<p>The recommended way to remove a PPA is to use the <code>apt-add-repository</code> command with the <code>--remove</code> (or <code>-r</code>) option.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo apt-add-repository --remove ppa:PPA_REPOSITORY/PPA</span></span></code></pre></div><p>Example:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo apt-add-repository -r ppa:neovim-ppa/unstable</span></span></code></pre></div>]]></content:encoded></item><item><title>How to catch Boto3 errors</title><link>https://how.wtf/how-to-catch-boto3-errors.html</link><pubDate>Sat, 04 Mar 2023 01:25:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-catch-boto3-errors.html</guid><description>Catching errors with the boto3 library is straightfoward.
Catching boto3 errors with ClientError 1import boto3 2import botocore 3 4s3 = boto3.client(&amp;#34;s3&amp;#34;) 5 6try: 7 s3.get_object(Bucket=&amp;#34;bucket&amp;#34;, Key=&amp;#34;key&amp;#34;) 8except botocore.exceptions.ClientError as e: 9 if e.response[&amp;#34;Error&amp;#34;][&amp;#34;Code&amp;#34;] == &amp;#34;AccessDenied&amp;#34;: 10 print(e.response[&amp;#34;Error&amp;#34;][&amp;#34;Message&amp;#34;]) 11 else: 12 raiseOther information in the e.response object may additionally be useful:
e.response[&amp;quot;Error&amp;quot;][&amp;quot;Code&amp;quot;] for the error code e.response[&amp;quot;Error&amp;quot;][&amp;quot;Message&amp;quot;] for the error message e.response[&amp;quot;ResponseMetadata&amp;quot;][&amp;quot;RequestId&amp;quot;] for the request id e.response[&amp;quot;ResponseMetadata&amp;quot;][&amp;quot;HTTPStatusCode&amp;quot;] for the status code e.</description><content:encoded><![CDATA[<p>Catching errors with the <code>boto3</code> library is straightfoward.</p>
<h2 id="catching-boto3-errors-with-clienterror">Catching <code>boto3</code> errors with <code>ClientError</code></h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">botocore</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">s3</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;s3&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">s3</span><span class="o">.</span><span class="n">get_object</span><span class="p">(</span><span class="n">Bucket</span><span class="o">=</span><span class="s2">&#34;bucket&#34;</span><span class="p">,</span> <span class="n">Key</span><span class="o">=</span><span class="s2">&#34;key&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="k">except</span> <span class="n">botocore</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">ClientError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="k">if</span> <span class="n">e</span><span class="o">.</span><span class="n">response</span><span class="p">[</span><span class="s2">&#34;Error&#34;</span><span class="p">][</span><span class="s2">&#34;Code&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;AccessDenied&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">response</span><span class="p">[</span><span class="s2">&#34;Error&#34;</span><span class="p">][</span><span class="s2">&#34;Message&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="k">raise</span></span></span></code></pre></div><p>Other information in the <code>e.response</code> object may additionally be useful:</p>
<ul>
<li><code>e.response[&quot;Error&quot;][&quot;Code&quot;]</code> for the error code</li>
<li><code>e.response[&quot;Error&quot;][&quot;Message&quot;]</code> for the error message</li>
<li><code>e.response[&quot;ResponseMetadata&quot;][&quot;RequestId&quot;]</code> for the request id</li>
<li><code>e.response[&quot;ResponseMetadata&quot;][&quot;HTTPStatusCode&quot;]</code> for the status code</li>
</ul>
<p><code>e.response</code>&rsquo;s full dictionary:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">{
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    &#39;Error&#39;: {
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        &#39;Code&#39;: &#39;AccessDenied&#39;,
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        &#39;Message&#39;: &#39;Access Denied&#39;
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    }, 
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    &#39;ResponseMetadata&#39;: {
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        &#39;RequestId&#39;: &#39;requestId&#39;,
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        &#39;HostId&#39;: &#39;hostId&#39;,
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        &#39;HTTPStatusCode&#39;: 403,
</span></span><span class="line"><span class="ln">10</span><span class="cl">        &#39;HTTPHeaders&#39;: {
</span></span><span class="line"><span class="ln">11</span><span class="cl">            &#39;x-amz-request-id&#39;: &#39;requestId&#39;,
</span></span><span class="line"><span class="ln">12</span><span class="cl">            &#39;x-amz-id-2&#39;: &#39;id-2&#39;,
</span></span><span class="line"><span class="ln">13</span><span class="cl">            &#39;content-type&#39;: &#39;application/xml&#39;,
</span></span><span class="line"><span class="ln">14</span><span class="cl">            &#39;transfer-encoding&#39;: &#39;chunked&#39;,
</span></span><span class="line"><span class="ln">15</span><span class="cl">            &#39;date&#39;: &#39;Sat, 04 Mar 2023 06:11:15 GMT&#39;,
</span></span><span class="line"><span class="ln">16</span><span class="cl">            &#39;server&#39;: &#39;AmazonS3&#39;
</span></span><span class="line"><span class="ln">17</span><span class="cl">        },
</span></span><span class="line"><span class="ln">18</span><span class="cl">        &#39;RetryAttempts&#39;: 0
</span></span><span class="line"><span class="ln">19</span><span class="cl">    }
</span></span><span class="line"><span class="ln">20</span><span class="cl">}</span></span></code></pre></div><h2 id="catching-boto3-errors-with-service-exceptions">Catching <code>boto3</code> errors with service exceptions</h2>
<p>For some clients, the AWS Python SDK has exposed service exceptions:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">botocore</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">s3</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;s3&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">s3</span><span class="o">.</span><span class="n">create_bucket</span><span class="p">(</span><span class="n">Bucket</span><span class="o">=</span><span class="s2">&#34;bucket&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="k">except</span> <span class="n">s3</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">BucketAlreadyExists</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;s3 bucket already exists&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="k">except</span> <span class="n">botocore</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">ClientError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">e</span><span class="p">)</span></span></span></code></pre></div>]]></content:encoded></item><item><title>How to install Microsoft fonts on Ubuntu</title><link>https://how.wtf/how-to-install-microsoft-fonts-on-ubuntu.html</link><pubDate>Fri, 03 Mar 2023 00:00:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-install-microsoft-fonts-on-ubuntu.html</guid><description>Installing Microsoft fonts is simple through the terminal on Debian-based distributions.
Why are Microsoft fonts not installed? Microsoft fonts like Times New Roman, Arial, etc. are not open source. Because of licensing issues, most linux distributions opt to exclude proprietary software.
Install Microsoft fonts using Terminal / CLI Add the multiverse repository.
1sudo add-apt-repository multiverseInstall ttf-mscorefonts-installer.
1sudo apt update &amp;amp;&amp;amp; sudo apt install ttf-mscorefonts-installerWhen the EULA agreement appears, press tab and enter on &amp;lt;OK&amp;gt; then &amp;lt;Yes&amp;gt; on the &amp;ldquo;Do you accept the EULA license terms?</description><content:encoded><![CDATA[<p>Installing Microsoft fonts is simple through the terminal on Debian-based distributions.</p>
<h2 id="why-are-microsoft-fonts-_not_-installed">Why are Microsoft fonts <em>not</em> installed?</h2>
<p>Microsoft fonts like Times New Roman, Arial, etc. are not open source. Because of licensing issues, most linux distributions opt to exclude proprietary software.</p>
<h2 id="install-microsoft-fonts-using-terminal--cli">Install Microsoft fonts using Terminal / CLI</h2>
<p>Add the <code>multiverse</code> repository.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo add-apt-repository multiverse</span></span></code></pre></div><p>Install <code>ttf-mscorefonts-installer</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo apt update <span class="o">&amp;&amp;</span> sudo apt install ttf-mscorefonts-installer</span></span></code></pre></div><p>When the EULA agreement appears, press tab and enter on <code>&lt;OK&gt;</code> then <code>&lt;Yes&gt;</code> on the &ldquo;Do you accept the EULA license terms?&rdquo; screen.</p>
<p>Refresh the font cache.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo fc-cache -f -v</span></span></code></pre></div><p>If the EULA is mistakenly rejected, reinstall.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo apt install -reinstall ttf-mscorefonts-installer</span></span></code></pre></div>]]></content:encoded></item><item><title>How to install Microsoft Edge on Ubuntu</title><link>https://how.wtf/how-to-install-microsoft-edge-on-ubuntu.html</link><pubDate>Thu, 02 Mar 2023 01:35:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-install-microsoft-edge-on-ubuntu.html</guid><description>Installing Microsoft Edge is simple through the terminal on any Debian-based distribution.
Install Microsoft Edge using Terminal / CLI Download the Microsoft repository GPG key.
1curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor &amp;gt; microsoft.gpgAdd the GPG key to the trusted keys.
1sudo install -o root -g root -m 644 microsoft.gpg /etc/apt/trusted.gpg.d/Add the edge repository.
1sudo sh -c &amp;#39;echo &amp;#34;deb [arch=amd64] https://packages.microsoft.com/repos/edge stable main&amp;#34; &amp;gt; /etc/apt/sources.list.d/microsoft-edge-stable.list&amp;#39;Remove the downloaded GPG key since it was added to the system.</description><content:encoded><![CDATA[<p>Installing Microsoft Edge is simple through the terminal on any Debian-based distribution.</p>
<h2 id="install-microsoft-edge-using-terminal--cli">Install Microsoft Edge using Terminal / CLI</h2>
<p>Download the Microsoft repository GPG key.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">curl https://packages.microsoft.com/keys/microsoft.asc <span class="p">|</span> gpg --dearmor &gt; microsoft.gpg</span></span></code></pre></div><p>Add the GPG key to the trusted keys.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo install -o root -g root -m <span class="m">644</span> microsoft.gpg /etc/apt/trusted.gpg.d/</span></span></code></pre></div><p>Add the edge repository.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo sh -c <span class="s1">&#39;echo &#34;deb [arch=amd64] https://packages.microsoft.com/repos/edge stable main&#34; &gt; /etc/apt/sources.list.d/microsoft-edge-stable.list&#39;</span></span></span></code></pre></div><p>Remove the downloaded GPG key since it was added to the system.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo rm microsoft.gpg</span></span></code></pre></div><p>Install Microsoft Edge.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo apt update <span class="o">&amp;&amp;</span> sudo apt install microsoft-edge-stable</span></span></code></pre></div>]]></content:encoded></item><item><title>Disable welcome message in Fish Shell</title><link>https://how.wtf/disable-welcome-message-in-fish-shell.html</link><pubDate>Wed, 01 Mar 2023 00:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/disable-welcome-message-in-fish-shell.html</guid><description>The default welcome message in Fish can be surpressed or customized.
Disable welcome message A frequently asked question is &amp;ldquo;How do I change the greeting message?&amp;rdquo;. It can be completed by editing the config.fish file:
1vim ~/.config/fish/config.fishUsing the g global flag, the fish_greeting variable can be set to empty.
1set -g fish_greetingCustomize welcome message In addition to disabling, the message can be customized.
1vim ~/.config/fish/functions/fish_greeting.fish 1function fish_greeting 2 echo &amp;#34;greetings!&amp;#34; 3end</description><content:encoded><![CDATA[<p>The default welcome message in Fish can be surpressed or customized.</p>
<h2 id="disable-welcome-message">Disable welcome message</h2>
<p>A frequently asked question is &ldquo;How do I change the greeting message?&rdquo;. It can be completed by editing the <code>config.fish</code> file:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">vim ~/.config/fish/config.fish</span></span></code></pre></div><p>Using the <code>g</code> global flag, the <code>fish_greeting</code> variable can be set to empty.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fish" data-lang="fish"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">set</span> <span class="na">-g</span> <span class="nb">fish_greeting</span></span></span></code></pre></div><h2 id="customize-welcome-message">Customize welcome message</h2>
<p>In addition to disabling, the message can be customized.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">vim ~/.config/fish/functions/fish_greeting.fish</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fish" data-lang="fish"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">function</span> <span class="nb">fish_greeting
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">    </span><span class="k">echo</span> <span class="s2">&#34;greetings!&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">end</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Get size of an S3 bucket with AWS CLI</title><link>https://how.wtf/get-size-of-an-s3-bucket-with-aws-cli.html</link><pubDate>Tue, 28 Feb 2023 01:15:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/get-size-of-an-s3-bucket-with-aws-cli.html</guid><description>Using the AWS CLI, S3 bucket sizes can retrieved.
Finding the S3 Bucket Size Use the s3 list command with the --summarize option.
1aws s3 ls --summarize --human-readable --recursive s3://bucket-name/Output:
12023-02-27 00:11:33 5.1 KiB object1name 22023-02-06 00:31:42 5.5 KiB object2name 3 4Total Objects: 2 5 Total Size: 10.6 KiBIf the output is too noisy, we can retrieve the last 2 lines of the output:
1aws s3 ls --summarize --human-readable --recursive s3://bucket-name/ | tail -2Output:</description><content:encoded><![CDATA[<p>Using the AWS CLI, S3 bucket sizes can retrieved.</p>
<h2 id="finding-the-s3-bucket-size">Finding the S3 Bucket Size</h2>
<p>Use the <code>s3</code> list command with the <code>--summarize</code> option.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws s3 ls --summarize --human-readable --recursive s3://bucket-name/</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">2023-02-27 00:11:33    5.1 KiB object1name
</span></span><span class="line"><span class="ln">2</span><span class="cl">2023-02-06 00:31:42    5.5 KiB object2name
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl">Total Objects: 2
</span></span><span class="line"><span class="ln">5</span><span class="cl">   Total Size: 10.6 KiB</span></span></code></pre></div><p>If the output is too noisy, we can retrieve the last 2 lines of the output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws s3 ls --summarize --human-readable --recursive s3://bucket-name/ <span class="p">|</span> tail -2</span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Total Objects: 2
</span></span><span class="line"><span class="ln">2</span><span class="cl">   Total Size: 10.6 KiB</span></span></code></pre></div>]]></content:encoded></item><item><title>Difference between init and new in Python</title><link>https://how.wtf/difference-between-init-and-new-in-python.html</link><pubDate>Mon, 27 Feb 2023 00:05:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/difference-between-init-and-new-in-python.html</guid><description>__init__ and __new__ are dunder methods invoked during the creation of an object instance.
What are the differences? __new__ is used to control the creation of a new instance __init__ is used to control the initialization of an instance __new__ __init__ Controls the creation of an instance Controls the initialization of an instance Invoked first before __init__ Invoked after __new__ Returns an instance of the class Returns nothing __new__ is the first step of an instance creation and is responsible for returning a new instance of the class.</description><content:encoded><![CDATA[<p><code>__init__</code> and <code>__new__</code> are dunder methods invoked during the creation of an object instance.</p>
<h2 id="what-are-the-differences">What are the differences?</h2>
<ol>
<li><code>__new__</code> is used to control the creation of a new instance</li>
<li><code>__init__</code> is used to control the initialization of an instance</li>
</ol>
<table>
<thead>
<tr>
<th><code>__new__</code></th>
<th><code>__init__</code></th>
</tr>
</thead>
<tbody>
<tr>
<td>Controls the creation of an instance</td>
<td>Controls the initialization of an instance</td>
</tr>
<tr>
<td>Invoked <em>first</em> before <code>__init__</code></td>
<td>Invoked <em>after</em> <code>__new__</code></td>
</tr>
<tr>
<td>Returns an instance of the class</td>
<td>Returns nothing</td>
</tr>
</tbody>
</table>
<p><code>__new__</code> is the first step of an instance creation and is responsible for returning a new instance of the class.</p>
<p>In contrast, the <code>__init__</code> function initializes the instance <em>after</em> its creation.</p>
<h2 id="code-example">Code example</h2>
<p>In the code snippet below, <code>__new__</code> contains the <code>cls</code> class argument while <code>__init__</code> contains the <code>self</code> reference to the instance.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">class</span> <span class="nc">Example</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="k">def</span> <span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;__new__&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;__init__&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">e</span> <span class="o">=</span> <span class="n">Example</span><span class="p">()</span></span></span></code></pre></div><p>Output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">__new__
</span></span><span class="line"><span class="ln">2</span><span class="cl">__init__</span></span></code></pre></div><p>Increment an <code>invoked_count</code> variable each time <code>__new__</code> is called:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">class</span> <span class="nc">Example</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="n">invoked_count</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="k">def</span> <span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="n">Example</span><span class="o">.</span><span class="n">invoked_count</span> <span class="o">+=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="n">Example</span><span class="o">.</span><span class="n">invoked_count</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">e1</span> <span class="o">=</span> <span class="n">Example</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">e2</span> <span class="o">=</span> <span class="n">Example</span><span class="p">()</span></span></span></code></pre></div><p>Output</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">1
</span></span><span class="line"><span class="ln">2</span><span class="cl">2</span></span></code></pre></div><h2 id="use-cases">Use cases</h2>
<p><code>__init__</code> is used as a class constructor for initializing new instances.</p>
<p>A common use case for <code>__new__</code> is implementing the <a href="/singleton-in-python.html">singleton pattern</a>.</p>
]]></content:encoded></item><item><title>Singleton in Python</title><link>https://how.wtf/singleton-in-python.html</link><pubDate>Sun, 26 Feb 2023 00:00:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/singleton-in-python.html</guid><description>The Singleton pattern enforces having one instance of a class. This tutorial will showcase how to implement the singleton pattern in Python.
Implementing the Singleton pattern Using the __new__ dunder method, the creation of the object can be controlled since __new__ is called before the __init__ method.
1class Singleton: 2 _instance = None 3 4 def __new__(cls): 5 if cls._instance is None: 6 cls._instance = super(Singleton, cls).__new__(cls) 7 return cls._instance 8 9s1 = Singleton() 10s2 = Singleton() 11print(s1 == s2) # outputs Trues1 and s2 are the same object in memory.</description><content:encoded><![CDATA[<p>The Singleton pattern enforces having one instance of a class. This tutorial will showcase how to implement the singleton pattern in Python.</p>
<h2 id="implementing-the-singleton-pattern">Implementing the Singleton pattern</h2>
<p>Using the <code>__new__</code> dunder method, the creation of the object can be controlled since <code>__new__</code> is called before the <code>__init__</code> method.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">class</span> <span class="nc">Singleton</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="n">_instance</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="k">def</span> <span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_instance</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">            <span class="bp">cls</span><span class="o">.</span><span class="n">_instance</span> <span class="o">=</span> <span class="nb">super</span><span class="p">(</span><span class="n">Singleton</span><span class="p">,</span> <span class="bp">cls</span><span class="p">)</span><span class="o">.</span><span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_instance</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="n">s1</span> <span class="o">=</span> <span class="n">Singleton</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">s2</span> <span class="o">=</span> <span class="n">Singleton</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">s1</span> <span class="o">==</span> <span class="n">s2</span><span class="p">)</span> <span class="c1"># outputs True</span></span></span></code></pre></div><p><code>s1</code> and <code>s2</code> are the same object in memory.</p>
<h2 id="why-is-this-beneficial">Why is this beneficial?</h2>
<p>The singleton pattern is useful for certain cases:</p>
<ol>
<li>Logger</li>
<li>Thread Pooling</li>
<li>Caching</li>
<li>Configuration</li>
</ol>
]]></content:encoded></item><item><title>Read environment variables from file in Python</title><link>https://how.wtf/read-environment-variables-from-file-in-python.html</link><pubDate>Sat, 25 Feb 2023 02:15:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/read-environment-variables-from-file-in-python.html</guid><description>A .env file is a text file containing key value pairs of environment variables. This file is normally included with a project, but not committed to source.
How to read .env files using Python Firstly, install the dotenv package.
1pip install python-dotenvInclude the folllowing lines:
1from dotenv import load_dotenv 2 3load_dotenv()Using load_dotenv(), the application will load the .env file and host environment variables. If this is the .env file for the application:</description><content:encoded><![CDATA[<p>A <code>.env</code> file is a text file containing key value pairs of environment variables. This file is normally included with a project, but not committed to source.</p>
<h2 id="how-to-read-env-files-using-python">How to read <code>.env</code> files using Python</h2>
<p>Firstly, install the <code>dotenv</code> package.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install python-dotenv</span></span></code></pre></div><p>Include the folllowing lines:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">dotenv</span> <span class="kn">import</span> <span class="n">load_dotenv</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">load_dotenv</span><span class="p">()</span></span></span></code></pre></div><p>Using <code>load_dotenv()</code>, the application will load the <code>.env</code> file <em>and</em> host environment variables. If this is the <code>.env</code> file for the application:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">VARIABLE1=test</span></span></code></pre></div><p>Then the output will be <code>test</code> for the following snippet:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">dotenv</span> <span class="kn">import</span> <span class="n">load_dotenv</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">load_dotenv</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;VARIABLE1&#34;</span><span class="p">))</span> <span class="c1"># outputs test</span></span></span></code></pre></div><p>However, if the host environment has a <code>VARIABLE1</code> defined:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">export</span> <span class="nv">VARIABLE1</span><span class="o">=</span>test2</span></span></code></pre></div><p>The output will change to <code>test2</code>.</p>
<p>If this is not desired behavior, the author may opt to use <code>dotenv_values</code> which returns a <code>dict</code> of values strictly parsed from the <code>.env</code> file:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">dotenv</span> <span class="kn">import</span> <span class="n">dotenv_values</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">config</span> <span class="o">=</span> <span class="n">dotenv_values</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">config</span><span class="p">)</span> <span class="c1"># outputs OrderedDict([(&#39;VARIABLE1&#39;, &#39;test&#39;)])</span></span></span></code></pre></div><p>If the <code>.env</code> file resides on a different path than the default root directy of the project, use the <code>dotenv_path</code> option:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">dotenv</span> <span class="kn">import</span> <span class="n">load_dotenv</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">load_dotenv</span><span class="p">(</span><span class="n">dotenv_path</span><span class="o">=</span><span class="n">Path</span><span class="p">(</span><span class="s2">&#34;path/to/file&#34;</span><span class="p">))</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Execute CLI commands in Python</title><link>https://how.wtf/execute-cli-commands-in-python.html</link><pubDate>Fri, 24 Feb 2023 23:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/execute-cli-commands-in-python.html</guid><description>Executing CLI commands / shell scripts / external programs in Python is easy.
Use subprocess.run Since Python 3.5 (subprocess.call for earlier versions), subprocess.run is the recommended way to execute external shell scripts.
1import subprocess 2 3output = subprocess.run([&amp;#34;echo&amp;#34;, &amp;#34;hello&amp;#34;, &amp;#34;world&amp;#34;], capture_output=True) 4print(output.returncode) # outputs 0 5print(output.stdout.decode(&amp;#34;utf-8&amp;#34;)) # outputs hello world</description><content:encoded><![CDATA[<p>Executing CLI commands / shell scripts / external programs in Python is easy.</p>
<h2 id="use-subprocessrun">Use <code>subprocess.run</code></h2>
<p>Since Python 3.5 (<code>subprocess.call</code> for earlier versions), <code>subprocess.run</code> is the recommended way to execute external shell scripts.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">subprocess</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">output</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">run</span><span class="p">([</span><span class="s2">&#34;echo&#34;</span><span class="p">,</span> <span class="s2">&#34;hello&#34;</span><span class="p">,</span> <span class="s2">&#34;world&#34;</span><span class="p">],</span> <span class="n">capture_output</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">output</span><span class="o">.</span><span class="n">returncode</span><span class="p">)</span> <span class="c1"># outputs 0</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">output</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">&#34;utf-8&#34;</span><span class="p">))</span> <span class="c1"># outputs hello world</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Play sounds or music from Linux terminal</title><link>https://how.wtf/play-sounds-or-music-from-linux-terminal.html</link><pubDate>Thu, 23 Feb 2023 23:15:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/play-sounds-or-music-from-linux-terminal.html</guid><description>Playing music or sounds from the command line is simple with Sound eXchange (SoX). It supports many audio file types: mp3, wav, ogg, etc.
What is SoX? As described by its man page, Sound eXchange is the Swiss Army knife of audio manipulation. It&amp;rsquo;s a cross platform command line utility used to convert, apply affects, record, or play audio files.
How to play audio from the terminal Install sox using your package manager with all the encoders.</description><content:encoded><![CDATA[<p>Playing music or sounds from the command line is simple with Sound eXchange (<code>SoX</code>). It supports many audio file types: <strong>mp3</strong>, <strong>wav</strong>, <strong>ogg</strong>, etc.</p>
<h2 id="what-is-sox">What is <code>SoX</code>?</h2>
<p>As described by its man page, Sound eXchange is the Swiss Army knife of audio manipulation. It&rsquo;s a cross platform command line utility used to convert, apply affects, record, or play audio files.</p>
<h2 id="how-to-play-audio-from-the-terminal">How to play audio from the terminal</h2>
<ol>
<li>
<p>Install <code>sox</code> using your package manager with all the encoders.</p>
<p>For Ubuntu:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo apt-get update</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">sudo apt-get install sox libsox-fmt-all</span></span></code></pre></div></li>
<li>
<p>After the installation is complete, use the <code>play</code> command to play an audio file.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">play filename.mp3</span></span></code></pre></div></li>
</ol>
]]></content:encoded></item><item><title>Difference between continue and pass in Python</title><link>https://how.wtf/difference-between-continue-and-pass-in-python.html</link><pubDate>Wed, 22 Feb 2023 00:10:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/difference-between-continue-and-pass-in-python.html</guid><description>Using the continue statement A continue statement is used within a for loop to skip the remainder of the current iteration. Essentially, the continue statement will simply skip to the next iteration.
A normal for loop that prints the current index i:
1for i in range(3): 2 print(i) 10 21 32The same for loop, with a conditional and a continue:
1for i in range(3): 2 if i == 1: 3 continue 4 print(i) 10 22On the second iteration of the for loop (when i = 1), the continue statement stopped the current iteration and &amp;ldquo;continued&amp;rdquo; to the next.</description><content:encoded><![CDATA[<h2 id="using-the-continue-statement">Using the <code>continue</code> statement</h2>
<p>A <code>continue</code> statement is used within a for loop to skip the remainder of the current iteration. Essentially, the <code>continue</code> statement will simply skip to the next iteration.</p>
<p>A normal <code>for</code> loop that prints the current index <code>i</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">0
</span></span><span class="line"><span class="ln">2</span><span class="cl">1
</span></span><span class="line"><span class="ln">3</span><span class="cl">2</span></span></code></pre></div><p>The same for loop, with a conditional and a <code>continue</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="k">if</span> <span class="n">i</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="k">continue</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">0
</span></span><span class="line"><span class="ln">2</span><span class="cl">2</span></span></code></pre></div><p>On the second iteration of the for loop (when <code>i = 1</code>), the <code>continue</code> statement stopped the current iteration and &ldquo;continued&rdquo; to the next.</p>
<h2 id="using-the-pass-statement">Using the <code>pass</code> statement</h2>
<p>As implied by the name, the <code>pass</code> state does nothing.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="k">if</span> <span class="n">i</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="k">pass</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">0
</span></span><span class="line"><span class="ln">2</span><span class="cl">1
</span></span><span class="line"><span class="ln">3</span><span class="cl">2</span></span></code></pre></div><p>This is most useful when defining placeholders for future code to satisfy the interpreter.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">def</span> <span class="nf">func</span><span class="p">():</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="k">pass</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Static methods in Python</title><link>https://how.wtf/static-methods-in-python.html</link><pubDate>Tue, 21 Feb 2023 00:40:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/static-methods-in-python.html</guid><description>Static methods are similar to instance methods (class-level methods), except static methods behave like regular functions bound to a class namespace. Unlike instance methods, static methods do not have access to cls or self.
Creating static methods A class named StringUtil contains a is_empty method for determining if a string is empty.
1class StringUtil: 2 @staticmethod 3 def is_empty(s): 4 return not s.strip() 5 6print(StringUtil.is_empty(&amp;#34;test&amp;#34;)) # False 7print(StringUtil.is_empty(&amp;#34; &amp;#34;)) # TrueWhen to use static methods Static methods are advantageous for:</description><content:encoded><![CDATA[<p>Static methods are similar to instance methods (class-level methods), except static methods behave like regular functions bound to a class namespace. Unlike instance methods, static methods do not have access to <code>cls</code> or <code>self</code>.</p>
<h2 id="creating-static-methods">Creating static methods</h2>
<p>A class named <code>StringUtil</code> contains a <code>is_empty</code> method for determining if a string is empty.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">class</span> <span class="nc">StringUtil</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nd">@staticmethod</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="k">def</span> <span class="nf">is_empty</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">        <span class="k">return</span> <span class="ow">not</span> <span class="n">s</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">StringUtil</span><span class="o">.</span><span class="n">is_empty</span><span class="p">(</span><span class="s2">&#34;test&#34;</span><span class="p">))</span> <span class="c1"># False</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">StringUtil</span><span class="o">.</span><span class="n">is_empty</span><span class="p">(</span><span class="s2">&#34; &#34;</span><span class="p">))</span> <span class="c1"># True</span></span></span></code></pre></div><h2 id="when-to-use-static-methods">When to use static methods</h2>
<p>Static methods are advantageous for:</p>
<ul>
<li>Singletons</li>
<li>Utility classes with similar grouped methods</li>
<li>Methods that belong in a class namespace, but do not require instance variables (<code>self</code>)</li>
</ul>
]]></content:encoded></item><item><title>How to delete files and directories in Python</title><link>https://how.wtf/how-to-delete-files-and-directories-in-python.html</link><pubDate>Mon, 20 Feb 2023 00:40:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-delete-files-and-directories-in-python.html</guid><description>How to delete a file or folder using Python?
Removing files Remove a file with os.remove() 1import os 2 3os.remove(&amp;#34;path/to/file&amp;#34;)Remove a file with pathlib.Path.unlink() 1from pathlib import Path 2 3p = Path(&amp;#34;path/to/file&amp;#34;) 4p.unlink()Removing directories Remove an empty directory with os.rmdir() 1import os 2 3os.rmdir(&amp;#34;path/to/folder&amp;#34;)Remove an empty directory with pathlib.Path.rmdir() 1from pathlib import Path 2 3p = Path(&amp;#34;path/to/folder&amp;#34;) 4p.rmdir()Remove an empty directory and its contents with shutil.rmtree() 1import shutil 2 3shutil.</description><content:encoded><![CDATA[<p>How to delete a file or folder using Python?</p>
<h2 id="removing-files">Removing files</h2>
<h3 id="remove-a-file-with-osremove">Remove a file with <code>os.remove()</code></h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">os</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="s2">&#34;path/to/file&#34;</span><span class="p">)</span></span></span></code></pre></div><h3 id="remove-a-file-with-pathlibpathunlink">Remove a file with <code>pathlib.Path.unlink()</code></h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">p</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="s2">&#34;path/to/file&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">p</span><span class="o">.</span><span class="n">unlink</span><span class="p">()</span></span></span></code></pre></div><h2 id="removing-directories">Removing directories</h2>
<h3 id="remove-an-empty-directory-with-osrmdir">Remove an empty directory with <code>os.rmdir()</code></h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">os</span><span class="o">.</span><span class="n">rmdir</span><span class="p">(</span><span class="s2">&#34;path/to/folder&#34;</span><span class="p">)</span></span></span></code></pre></div><h3 id="remove-an-empty-directory-with-pathlibpathrmdir">Remove an empty directory with <code>pathlib.Path.rmdir()</code></h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">p</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="s2">&#34;path/to/folder&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">p</span><span class="o">.</span><span class="n">rmdir</span><span class="p">()</span></span></span></code></pre></div><h3 id="remove-an-empty-directory-and-its-contents-with-shutilrmtree">Remove an empty directory and its contents with <code>shutil.rmtree()</code></h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">shutil</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">shutil</span><span class="o">.</span><span class="n">rmtree</span><span class="p">(</span><span class="s2">&#34;path/to/folder&#34;</span><span class="p">)</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Python dataclasses with optional fields</title><link>https://how.wtf/python-dataclasses-with-optional-fields.html</link><pubDate>Sun, 19 Feb 2023 01:20:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/python-dataclasses-with-optional-fields.html</guid><description>How do I create dataclasses in Python with optional fields?
How does a dataclass work? Dataclasses generate dunder methods on the user&amp;rsquo;s behalf. Instead of defining __init__, __eq__, etc. manually, these methods are provided out of the box simply be defining fields and their respestive types.
1from dataclasses import dataclass 2 3@dataclass 4class Person 5 name: str 6 age: intBecause the methods and constructor are generated, the attributes are checked and hardcoded.</description><content:encoded><![CDATA[<p>How do I create dataclasses in Python with optional fields?</p>
<h2 id="how-does-a-dataclass-work">How does a dataclass work?</h2>
<p>Dataclasses generate dunder methods on the user&rsquo;s behalf. Instead of defining <code>__init__</code>, <code>__eq__</code>, etc. manually, these methods are provided out of the box simply be defining fields and their respestive types.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nd">@dataclass</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">class</span> <span class="nc">Person</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="n">age</span><span class="p">:</span> <span class="nb">int</span></span></span></code></pre></div><p>Because the methods and constructor are generated, the attributes are checked and hardcoded.</p>
<h2 id="optional-fields-in-dataclasses">Optional fields in dataclasses</h2>
<p>There are options for making an argument optional with dataclasses.</p>
<h3 id="using-optionalstr-and-a-default-value">Using <code>Optional[str]</code> and a default value</h3>
<p>It is possible to make an optional argument by using a default value for the attribute.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Optional</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nd">@dataclass</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">class</span> <span class="nc">Person</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">age</span><span class="p">:</span> <span class="nb">int</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">email</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">Person</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&#34;john&#34;</span><span class="p">,</span> <span class="n">age</span><span class="o">=</span><span class="mi">35</span><span class="p">))</span> <span class="c1"># Person(name=&#39;john&#39;, age=35, email=None)</span></span></span></code></pre></div><h3 id="using-initvar">Using <code>InitVar</code></h3>
<p><code>InitVar</code> is passed to the <code>__init__</code> and <code>__post_init__</code> methods, but is not stored as a class attribute. This can be valuable for some use-cases.</p>
<p>If a movie is not published, mark it as hidden.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span><span class="p">,</span> <span class="n">field</span><span class="p">,</span> <span class="n">InitVar</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Optional</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nd">@dataclass</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">class</span> <span class="nc">Movie</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">title</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">hidden</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="n">field</span><span class="p">(</span><span class="n">init</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">is_published</span><span class="p">:</span> <span class="n">InitVar</span><span class="p">[</span><span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="k">def</span> <span class="nf">__post_init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">is_published</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">hidden</span> <span class="o">=</span> <span class="ow">not</span><span class="p">(</span><span class="n">is_published</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">Movie</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">&#34;title&#34;</span><span class="p">,</span> <span class="n">is_published</span><span class="o">=</span><span class="kc">False</span><span class="p">))</span> <span class="c1"># Movie(title=&#39;title&#39;, hidden=True)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">Movie</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">&#34;title&#34;</span><span class="p">,</span> <span class="n">is_published</span><span class="o">=</span><span class="kc">True</span><span class="p">))</span> <span class="c1"># Movie(title=&#39;title&#39;, hidden=False)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">Movie</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">&#34;title&#34;</span><span class="p">))</span> <span class="c1"># Movie(title=&#39;title&#39;, hidden=False)</span></span></span></code></pre></div>]]></content:encoded></item><item><title>CloudFormation create stack vs deploy in AWS CLI</title><link>https://how.wtf/cloudformation-create-stack-vs-deploy-in-aws-cli.html</link><pubDate>Sat, 18 Feb 2023 02:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/cloudformation-create-stack-vs-deploy-in-aws-cli.html</guid><description>CloudFormation provides two options for deploying templates using the AWS CLI:
aws cloudformation create-stack aws cloudformation deploy What are the differences between the two?
create-stack Create stack is a specific API action for creating AWS CloudFormation stacks.
1aws cloudformation create-stack \ 2 --stack-name STACK_NAME \ 3 --template-body file://path/to/file.jsondeploy Deploy is an abstraction for managing AWS CloudFormation stacks and change sets. The list of API actions available for CloudFormation does not include deploy.</description><content:encoded><![CDATA[<p>CloudFormation provides two options for deploying templates using the AWS CLI:</p>
<ol>
<li><code>aws cloudformation create-stack</code></li>
<li><code>aws cloudformation deploy</code></li>
</ol>
<p>What are the differences between the two?</p>
<h2 id="create-stack"><code>create-stack</code></h2>
<p>Create stack is a specific API action for creating AWS CloudFormation stacks.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws cloudformation create-stack <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --stack-name STACK_NAME <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --template-body file://path/to/file.json</span></span></code></pre></div><h2 id="deploy"><code>deploy</code></h2>
<p>Deploy is an abstraction for managing AWS CloudFormation stacks and <em>change sets</em>. The <a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_Operations.html">list of API actions available</a> for CloudFormation does <em>not</em> include <code>deploy</code>.</p>
<p>Unlike <code>create-stack</code>, which is a direct API call, <code>deploy</code> combines <code>create-change-set</code> and <code>execute-change-set</code> in a single convenient command.</p>
<p>The following command will either create a new stack if one does not exist, or create a change set and execute the change set to update an existing stack.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws cloudformation deploy <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --stack-name STACK_NAME <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --template-body file://path/to/file.json</span></span></code></pre></div><p>If the author wants to review the change set before automatically applying, the flag <code>--no-execute-changeset</code> can be used:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws cloudformation deploy <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --stack-name STACK_NAME <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --template-body file://path/to/file.json <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>    --no-execute-changeset</span></span></code></pre></div><h2 id="should-i-use-create-stack-or-deploy">Should I use <code>create-stack</code> or <code>deploy</code>?</h2>
<p>In general, <code>aws cloudformation deploy</code> will be easiest to use. It automatically handles creating or updating change sets on the user&rsquo;s behalf.</p>
]]></content:encoded></item><item><title>How to view or tail AWS logs in real time</title><link>https://how.wtf/how-to-view-or-tail-aws-logs-in-real-time.html</link><pubDate>Fri, 17 Feb 2023 00:10:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-view-or-tail-aws-logs-in-real-time.html</guid><description>Since mid-2019, the AWS CLI natively supports real time viewing of aws logs.
View latest logs using --since View the latest 365 days worth of logs:
1aws logs tail $GROUP --since 365dView the latest 52 weeks worth of logs:
1aws logs tail $GROUP --since 52wView other supported units here.
Real time follow logs using --follow Continuously poll for new logs using --follow:
1aws logs tail $GROUP --followOther options with aws logs tail For other supported options with aws logs tail, view the full reference here.</description><content:encoded><![CDATA[<p>Since mid-2019, the AWS CLI natively supports real time viewing of aws logs.</p>
<h2 id="view-latest-logs-using---since">View latest logs using <code>--since</code></h2>
<p>View the latest 365 days worth of logs:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws logs tail <span class="nv">$GROUP</span> --since 365d</span></span></code></pre></div><p>View the latest 52 weeks worth of logs:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws logs tail <span class="nv">$GROUP</span> --since 52w</span></span></code></pre></div><p>View other supported units <a href="https://awscli.amazonaws.com/v2/documentation/api/latest/reference/logs/tail.html">here</a>.</p>
<h2 id="real-time-follow-logs-using---follow">Real time follow logs using <code>--follow</code></h2>
<p>Continuously poll for new logs using <code>--follow</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws logs tail <span class="nv">$GROUP</span> --follow</span></span></code></pre></div><h2 id="other-options-with-aws-logs-tail">Other options with <code>aws logs tail</code></h2>
<p>For other supported options with <code>aws logs tail</code>, view the full reference <a href="https://awscli.amazonaws.com/v2/documentation/api/latest/reference/logs/tail.html">here</a>.</p>
]]></content:encoded></item><item><title>How to copy files in Linux</title><link>https://how.wtf/how-to-copy-files-in-linux.html</link><pubDate>Thu, 16 Feb 2023 00:40:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-copy-files-in-linux.html</guid><description>Copying files and directories is an essential task in Linux.
The cp command The cp command is used to copy files and directories from one location to another.
Basic syntax:
1Usage: cp [OPTION]... [-T] SOURCE DEST 2 or: cp [OPTION]... SOURCE... DIRECTORY 3 or: cp [OPTION]... -t DIRECTORY SOURCE... 4Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.The SOURCE can be one or many files / directories, and the DEST can be a single file or directory.</description><content:encoded><![CDATA[<p>Copying files and directories is an essential task in Linux.</p>
<h2 id="the-cp-command">The <code>cp</code> command</h2>
<p>The <code>cp</code> command is used to copy files and directories from one location to another.</p>
<p>Basic syntax:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">Usage: cp <span class="o">[</span>OPTION<span class="o">]</span>... <span class="o">[</span>-T<span class="o">]</span> SOURCE DEST
</span></span><span class="line"><span class="ln">2</span><span class="cl">  or:  cp <span class="o">[</span>OPTION<span class="o">]</span>... SOURCE... DIRECTORY
</span></span><span class="line"><span class="ln">3</span><span class="cl">  or:  cp <span class="o">[</span>OPTION<span class="o">]</span>... -t DIRECTORY SOURCE...
</span></span><span class="line"><span class="ln">4</span><span class="cl">Copy SOURCE to DEST, or multiple SOURCE<span class="o">(</span>s<span class="o">)</span> to DIRECTORY.</span></span></code></pre></div><p>The <code>SOURCE</code> can be one or many files / directories, and the <code>DEST</code> can be a single file or directory.</p>
<h2 id="copying-multiple-files-to-a-directory">Copying multiple files to a directory</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">cp file1 file2 file3 dir1</span></span></code></pre></div><h2 id="copying-matching-files-to-a-directory">Copying matching files to a directory</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">cp *.txt dir1</span></span></code></pre></div><h2 id="copying-a-directory-to-another-directory">Copying a directory to another directory</h2>
<p>Using the <code>-r</code> or <code>-R</code> or <code>--recursive</code> option, <code>cp</code> will recursively copy a directory - including its files and subdirectories.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">cp -r dir1 ~/Documents</span></span></code></pre></div><h2 id="copying-files-without-clobbering">Copying files without clobbering</h2>
<p>Using the <code>-i</code> or <code>--interactive</code> option, <code>cp</code> will iteratively request user input for files with naming conflicts.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">&gt; cp -i file1 dir1
</span></span><span class="line"><span class="ln">2</span><span class="cl">cp: overwrite <span class="s1">&#39;dir1/file1&#39;</span>?</span></span></code></pre></div><h2 id="include-verbosity-when-copying-files">Include verbosity when copying files</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">&gt; cp -v file1 dir1
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s1">&#39;file1&#39;</span> -&gt; <span class="s1">&#39;dir1/file1&#39;</span></span></span></code></pre></div>]]></content:encoded></item><item><title>How to move files in Linux</title><link>https://how.wtf/how-to-move-files-in-linux.html</link><pubDate>Wed, 15 Feb 2023 00:25:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-move-files-in-linux.html</guid><description>Moving files is an essential task individuals often need to perform.
The mv command and its usage The mv command is used to rename or move files and directories from one location to another.
Basic syntax:
1&amp;gt; mv --help 2Usage: mv [OPTION]... [-T] SOURCE DEST 3 or: mv [OPTION]... SOURCE... DIRECTORY 4 or: mv [OPTION]... -t DIRECTORY SOURCE...`The SOURCE can be one or many files / directories, and the DEST can be a single file or directory.</description><content:encoded><![CDATA[<p>Moving files is an essential task individuals often need to perform.</p>
<h2 id="the-mv-command-and-its-usage">The <code>mv</code> command and its usage</h2>
<p>The <code>mv</code> command is used to rename or move files and directories from one location to another.</p>
<p>Basic syntax:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">&gt; mv --help
</span></span><span class="line"><span class="ln">2</span><span class="cl">Usage: mv <span class="o">[</span>OPTION<span class="o">]</span>... <span class="o">[</span>-T<span class="o">]</span> SOURCE DEST
</span></span><span class="line"><span class="ln">3</span><span class="cl">  or:  mv <span class="o">[</span>OPTION<span class="o">]</span>... SOURCE... DIRECTORY
</span></span><span class="line"><span class="ln">4</span><span class="cl">  or:  mv <span class="o">[</span>OPTION<span class="o">]</span>... -t DIRECTORY SOURCE...<span class="sb">`</span></span></span></code></pre></div><p>The <code>SOURCE</code> can be one or many files / directories, and the <code>DEST</code> can be a single file or directory.</p>
<h2 id="moving-multiple-files-to-a-directory">Moving multiple files to a directory</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">mv file1 file2 dir1</span></span></code></pre></div><h2 id="moving-matching-files-to-a-directory">Moving matching files to a directory</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">mv *.md dir1</span></span></code></pre></div><h2 id="moving-a-directory-to-another-directory">Moving a directory to another directory</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">mv dir1 ~/Documents</span></span></code></pre></div><h2 id="moving-files-without-clobbering">Moving files without clobbering</h2>
<p>Using the <code>-i</code> or <code>--interactive</code> option, <code>mv</code> will iteratively request user input for files with naming conflicts.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">&gt; mv -i file1 ~/Documents
</span></span><span class="line"><span class="ln">2</span><span class="cl">mv: overwrite <span class="s1">&#39;~/Documents/file1&#39;</span>?</span></span></code></pre></div><h2 id="renaming-files">Renaming files</h2>
<p>Rename <code>file1</code> to <code>file2</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">mv file1 file2</span></span></code></pre></div>]]></content:encoded></item><item><title>Create multiple directories at once in terminal</title><link>https://how.wtf/create-multiple-directories-at-once-in-terminal.html</link><pubDate>Tue, 14 Feb 2023 00:00:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/create-multiple-directories-at-once-in-terminal.html</guid><description>Here are different strategies for creating multiple directories/folders or subdirectories at once in a linux terminal.
Using mkdir positional arguments mkdir can be supplied multiple positional arguments.
1mkdir dir1 dir2Using bash brace expansion + mkdir mkdir can be supplied multiple positional arguments using bash&amp;rsquo;s brace expansion.
Creating directories 1mkdir {dir1,dir2}Creating subdirectories -p flag is used to create the parent directory if it does not already exist.
1mkdir -p dir/{dir1,dir2}Creating directories with bash sequences 1mkdir dir{1.</description><content:encoded><![CDATA[<p>Here are different strategies for creating multiple directories/folders or subdirectories at once in a linux terminal.</p>
<h2 id="using-mkdir-positional-arguments">Using <code>mkdir</code> positional arguments</h2>
<p><code>mkdir</code> can be supplied multiple positional arguments.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">mkdir dir1 dir2</span></span></code></pre></div><h2 id="using-bash-brace-expansion--mkdir">Using <code>bash</code> brace expansion + <code>mkdir</code></h2>
<p><code>mkdir</code> can be supplied multiple positional arguments using <code>bash</code>&rsquo;s brace expansion.</p>
<h3 id="creating-directories">Creating directories</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">mkdir <span class="o">{</span>dir1,dir2<span class="o">}</span></span></span></code></pre></div><h3 id="creating-subdirectories">Creating subdirectories</h3>
<p><code>-p</code> flag is used to create the parent directory if it does not already exist.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">mkdir -p dir/<span class="o">{</span>dir1,dir2<span class="o">}</span></span></span></code></pre></div><h3 id="creating-directories-with-bash-sequences">Creating directories with <code>bash</code> sequences</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">mkdir dir<span class="o">{</span>1..5<span class="o">}</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Adding a new IAM User using the AWS CLI</title><link>https://how.wtf/adding-a-new-iam-user-using-the-aws-cli.html</link><pubDate>Mon, 13 Feb 2023 00:20:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/adding-a-new-iam-user-using-the-aws-cli.html</guid><description>How to create a new IAM user with the AWS CLI?
Create a new IAM User To create a new IAM user, issue the following command:
1aws iam create-user --user-name USER 1{ 2 &amp;#34;User&amp;#34;: { 3 &amp;#34;Path&amp;#34;: &amp;#34;/&amp;#34;, 4 &amp;#34;UserName&amp;#34;: &amp;#34;USER&amp;#34;, 5 &amp;#34;UserId&amp;#34;: &amp;#34;AIDA...&amp;#34;, 6 &amp;#34;Arn&amp;#34;: &amp;#34;arn:aws:iam::123456789012:user/USER&amp;#34;, 7 &amp;#34;CreateDate&amp;#34;: &amp;#34;2023-02-13T05:03:54+00:00&amp;#34; 8 } 9}Add IAM User to an IAM Group Create IAM Group If an IAM Group does not exist, create one.</description><content:encoded><![CDATA[<p>How to create a new IAM user with the AWS CLI?</p>
<h2 id="create-a-new-iam-user">Create a new IAM User</h2>
<p>To create a new IAM user, issue the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws iam create-user --user-name USER</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;User&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="nt">&#34;Path&#34;</span><span class="p">:</span> <span class="s2">&#34;/&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">        <span class="nt">&#34;UserName&#34;</span><span class="p">:</span> <span class="s2">&#34;USER&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">        <span class="nt">&#34;UserId&#34;</span><span class="p">:</span> <span class="s2">&#34;AIDA...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">        <span class="nt">&#34;Arn&#34;</span><span class="p">:</span> <span class="s2">&#34;arn:aws:iam::123456789012:user/USER&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">        <span class="nt">&#34;CreateDate&#34;</span><span class="p">:</span> <span class="s2">&#34;2023-02-13T05:03:54+00:00&#34;</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="add-iam-user-to-an-iam-group">Add IAM User to an IAM Group</h2>
<h3 id="create-iam-group">Create IAM Group</h3>
<p>If an IAM Group does not exist, create one.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws iam create-group --group-name GROUP</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;Group&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="nt">&#34;Path&#34;</span><span class="p">:</span> <span class="s2">&#34;/&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">        <span class="nt">&#34;GroupName&#34;</span><span class="p">:</span> <span class="s2">&#34;GROUP&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">        <span class="nt">&#34;GroupId&#34;</span><span class="p">:</span> <span class="s2">&#34;AGPA...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">        <span class="nt">&#34;Arn&#34;</span><span class="p">:</span> <span class="s2">&#34;arn:aws:iam::123456789012:group/GROUP&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">        <span class="nt">&#34;CreateDate&#34;</span><span class="p">:</span> <span class="s2">&#34;2023-02-13T05:05:45+00:00&#34;</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h3 id="grant-access-to-iam-group">Grant access to IAM Group</h3>
<p>The managed policy arn <code>arn:aws:iam::aws:policy/PowerUserAccess</code> is attached to the group in this example.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws iam attach-group-policy --policy-arn arn:aws:iam::aws:policy/PowerUserAccess --group-name GROUP</span></span></code></pre></div><h3 id="add-the-user-to-the-iam-group">Add the user to the IAM group.</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws iam add-user-to-group --user-name USER --group-name GROUP</span></span></code></pre></div><h3 id="verify-user-is-added-to-group">Verify user is added to group</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws iam get-group --group-name GROUP --query <span class="s2">&#34;Users[*].{name:UserName,id:UserId}&#34;</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;USER&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">        <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;AIDA...&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="p">]</span></span></span></code></pre></div><h2 id="grant-aws-console-access">Grant AWS Console Access</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws iam create-login-profile --user-name USER --password PASSWORD --no-password-reset-required</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;LoginProfile&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="nt">&#34;UserName&#34;</span><span class="p">:</span> <span class="s2">&#34;USER&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">        <span class="nt">&#34;CreateDate&#34;</span><span class="p">:</span> <span class="s2">&#34;2023-02-13T05:10:17+00:00&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">        <span class="nt">&#34;PasswordResetRequired&#34;</span><span class="p">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="grant-programmatic-access">Grant Programmatic Access</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws iam create-access-key --user-name USER</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;AccessKey&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="nt">&#34;UserName&#34;</span><span class="p">:</span> <span class="s2">&#34;USER&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">        <span class="nt">&#34;AccessKeyId&#34;</span><span class="p">:</span> <span class="s2">&#34;AKIA...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">        <span class="nt">&#34;Status&#34;</span><span class="p">:</span> <span class="s2">&#34;Active&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">        <span class="nt">&#34;SecretAccessKey&#34;</span><span class="p">:</span> <span class="s2">&#34;UU...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">        <span class="nt">&#34;CreateDate&#34;</span><span class="p">:</span> <span class="s2">&#34;2023-02-13T05:11:18+00:00&#34;</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Clear all CloudFront cache and files using AWS CLI</title><link>https://how.wtf/clear-all-cloudfront-cache-and-files-using-aws-cli.html</link><pubDate>Sun, 12 Feb 2023 14:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/clear-all-cloudfront-cache-and-files-using-aws-cli.html</guid><description>How to invalidate all files or clear all cache for CloudFront using the AWS CLI?
Finding the distribution id If the distribution id is unknown, issue the following command to list all distribution ids:
1aws cloudfront list-distributions --query &amp;#34;DistributionList.Items[*].Id&amp;#34;Clear or Invalidate all cache for CoudFront To invalidate all paths, run the create-invalidation command with a wildcard path /*.
1aws cloudfront create-invalidation --distribution-id CF_DISTRIBUTION_ID --paths &amp;#34;/*&amp;#34; 1{ 2 &amp;#34;Location&amp;#34;: &amp;#34;https://cloudfront.amazonaws.com/2020-05-31/distribution/CF_DISTRIBUTION_ID/invalidation/I3SD80NE98KDJA&amp;#34;, 3 &amp;#34;Invalidation&amp;#34;: { 4 &amp;#34;Id&amp;#34;: &amp;#34;I3SD80NE98KDJA&amp;#34;, 5 &amp;#34;Status&amp;#34;: &amp;#34;InProgress&amp;#34;, 6 &amp;#34;CreateTime&amp;#34;: &amp;#34;2023-02-12T19:20:31.</description><content:encoded><![CDATA[<p>How to invalidate all files or clear all cache for CloudFront using the AWS CLI?</p>
<h2 id="finding-the-distribution-id">Finding the distribution id</h2>
<p>If the distribution id is unknown, issue the following command to list all distribution ids:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws cloudfront list-distributions --query <span class="s2">&#34;DistributionList.Items[*].Id&#34;</span></span></span></code></pre></div><h2 id="clear-or-invalidate-all-cache-for-coudfront">Clear or Invalidate all cache for CoudFront</h2>
<p>To invalidate all paths, run the <code>create-invalidation</code> command with a wildcard path <code>/*</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws cloudfront create-invalidation --distribution-id CF_DISTRIBUTION_ID --paths <span class="s2">&#34;/*&#34;</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="nt">&#34;Location&#34;</span><span class="p">:</span> <span class="s2">&#34;https://cloudfront.amazonaws.com/2020-05-31/distribution/CF_DISTRIBUTION_ID/invalidation/I3SD80NE98KDJA&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="nt">&#34;Invalidation&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        <span class="nt">&#34;Id&#34;</span><span class="p">:</span> <span class="s2">&#34;I3SD80NE98KDJA&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="nt">&#34;Status&#34;</span><span class="p">:</span> <span class="s2">&#34;InProgress&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="nt">&#34;CreateTime&#34;</span><span class="p">:</span> <span class="s2">&#34;2023-02-12T19:20:31.982000+00:00&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="nt">&#34;InvalidationBatch&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">            <span class="nt">&#34;Paths&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">                <span class="nt">&#34;Quantity&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">                <span class="nt">&#34;Items&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">                    <span class="s2">&#34;/*&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">                <span class="p">]</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="nt">&#34;CallerReference&#34;</span><span class="p">:</span> <span class="s2">&#34;cli-1676229631-287576&#34;</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="clear-specific-files-from-cache">Clear specific files from Cache</h2>
<p>If one or more files need invalidation, but not the entire distribution, simply execute the following command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws cloudfront create-invalidation --distribution-id CF_DISTRIBUTION_ID <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --paths <span class="s2">&#34;/path/of/file&#34;</span> <span class="s2">&#34;/path/to/other/file&#34;</span> <span class="s2">&#34;/path/to/folder/*&#34;</span></span></span></code></pre></div><p>Notice the wildcard for <code>/path/to/folder/*</code>. This allows any files under <code>/path/to/folder/</code> to be invalidated with the request.</p>
<h2 id="check-progress-on-validation">Check progress on validation</h2>
<p>To check the progress on an invalidation request, issue the follow command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws cloudfront get-invalidation --id INVALIDATION_ID --distribution-id CF_DISTRIBUTION_ID</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="nt">&#34;Invalidation&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="nt">&#34;Id&#34;</span><span class="p">:</span> <span class="s2">&#34;I3SD80NE98KDJA&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        <span class="nt">&#34;Status&#34;</span><span class="p">:</span> <span class="s2">&#34;Completed&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="nt">&#34;CreateTime&#34;</span><span class="p">:</span> <span class="s2">&#34;2023-02-12T19:20:31.982000+00:00&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="nt">&#34;InvalidationBatch&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">            <span class="nt">&#34;Paths&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">                <span class="nt">&#34;Quantity&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">                <span class="nt">&#34;Items&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">                    <span class="s2">&#34;/*&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">                <span class="p">]</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">            <span class="nt">&#34;CallerReference&#34;</span><span class="p">:</span> <span class="s2">&#34;cli-1676229631-287576&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Find AWS Account Id using CLI or Boto3</title><link>https://how.wtf/find-aws-account-id-using-cli-or-boto3.html</link><pubDate>Sat, 11 Feb 2023 01:15:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/find-aws-account-id-using-cli-or-boto3.html</guid><description>How to find the AWS Account ID using the AWS CLI or Boto3?
AWS CLI Retrieve your full identity
1aws sts get-caller-identity 1{ 2 &amp;#34;UserId&amp;#34;: &amp;#34;AIDA...&amp;#34;, 3 &amp;#34;Account&amp;#34;: &amp;#34;123456789012&amp;#34;, 4 &amp;#34;Arn&amp;#34;: &amp;#34;arn:aws:iam::123456789012:user/user&amp;#34; 5}Use native AWS CLI --query option for querying the output.
1aws sts get-caller-identity --query &amp;#34;Account&amp;#34; --output text 1123456789012Python Boto3 1import boto3 2 3sts = boto3.client(&amp;#34;sts&amp;#34;) 4account_id = sts.get_caller_identity()[&amp;#34;Account&amp;#34;] 5print(account_id) # 0123456789012</description><content:encoded><![CDATA[<p>How to find the AWS Account ID using the AWS CLI or Boto3?</p>
<h2 id="aws-cli">AWS CLI</h2>
<p>Retrieve your full identity</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws sts get-caller-identity</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;UserId&#34;</span><span class="p">:</span> <span class="s2">&#34;AIDA...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nt">&#34;Account&#34;</span><span class="p">:</span> <span class="s2">&#34;123456789012&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nt">&#34;Arn&#34;</span><span class="p">:</span> <span class="s2">&#34;arn:aws:iam::123456789012:user/user&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Use native AWS CLI <code>--query</code> option for querying the output.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws sts get-caller-identity --query <span class="s2">&#34;Account&#34;</span> --output text</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="m">123456789012</span></span></span></code></pre></div><h2 id="python-boto3">Python Boto3</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">sts</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;sts&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">account_id</span> <span class="o">=</span> <span class="n">sts</span><span class="o">.</span><span class="n">get_caller_identity</span><span class="p">()[</span><span class="s2">&#34;Account&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">account_id</span><span class="p">)</span> <span class="c1"># 0123456789012</span></span></span></code></pre></div>]]></content:encoded></item><item><title>How to get start or end of a day in Python</title><link>https://how.wtf/how-to-get-start-or-end-of-a-day-in-python.html</link><pubDate>Fri, 10 Feb 2023 00:00:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-get-start-or-end-of-a-day-in-python.html</guid><description>In Python, datetime natively handles getting the earliest/latest moment of a given day using the combine function.
Get the start of a day 1from datetime import datetime, time 2 3start_of_day = datetime.combine(datetime.now(), time.min) 4print(start_of_day) # 2023-02-10 00:00:00Get the end of a day 1from datetime import datetime, time 2 3end_of_day = datetime.combine(datetime.now(), time.max) 4print(end_of_day) # 2023-02-10 23:59:59.</description><content:encoded><![CDATA[<p>In Python, <code>datetime</code> natively handles getting the earliest/latest moment of a given day using the <code>combine</code> function.</p>
<h2 id="get-the-start-of-a-day">Get the start of a day</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">time</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">start_of_day</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">combine</span><span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">(),</span> <span class="n">time</span><span class="o">.</span><span class="n">min</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">start_of_day</span><span class="p">)</span> <span class="c1"># 2023-02-10 00:00:00</span></span></span></code></pre></div><h2 id="get-the-end-of-a-day">Get the end of a day</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">time</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">end_of_day</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">combine</span><span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">(),</span> <span class="n">time</span><span class="o">.</span><span class="n">max</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">end_of_day</span><span class="p">)</span> <span class="c1"># 2023-02-10 23:59:59.999999</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Resource vs Client in Python Boto3</title><link>https://how.wtf/resource-vs-client-in-python-boto3.html</link><pubDate>Thu, 09 Feb 2023 00:45:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/resource-vs-client-in-python-boto3.html</guid><description>Resource and Client are two different abstractions in the Boto3 SDK. What are the differences between the two?
Clients Clients provide lower-level access to AWS Services. They typically represent a 1:1 functionality mapping of any AWS service API and are generated via JSON service definition files such as the one for DynamoDB. The botocore library is shared between the AWS CLI &amp;amp; Boto3.
For example, the DynamoDB PutItem API call requires TableName and Item parameters to be supplied.</description><content:encoded><![CDATA[<p><strong>Resource</strong> and <strong>Client</strong> are two different abstractions in the Boto3 SDK. What are the differences between the two?</p>
<h2 id="clients">Clients</h2>
<p>Clients provide lower-level access to AWS Services. They typically represent a 1:1 functionality mapping of any AWS service API and are generated via JSON service definition files such as the one for <a href="https://github.com/boto/botocore/blob/develop/botocore/data/dynamodb/2012-08-10/service-2.json">DynamoDB</a>. The botocore library is shared between the AWS CLI &amp; Boto3.</p>
<p>For example, the DynamoDB <code>PutItem</code> API call requires <code>TableName</code> and <code>Item</code> <a href="https://github.com/boto/botocore/blob/ed72f826cb837e24693f540fc19c6e25ade75a95/botocore/data/dynamodb/2012-08-10/service-2.json#L4301">parameters to be supplied</a>. The <code>Item</code> parameter is required to be a <code>PutItemAttributeMap</code> which forces the user to add typing for each value. In addition to handling the strict input types, users are required to handle pagination.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">dynamodb</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">Client</span><span class="p">(</span><span class="s2">&#34;dynamodb&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">dynamodb</span><span class="o">.</span><span class="n">put_item</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="n">TableName</span><span class="o">=</span><span class="s2">&#34;table_name&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="n">Item</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">        <span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="s2">&#34;S&#34;</span><span class="p">:</span> <span class="s2">&#34;test&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="p">)</span></span></span></code></pre></div><h2 id="resources">Resources</h2>
<p>Resources provide higher-level access to AWS Services and reside within <code>boto3</code>. They are only supported for a subset of AWS services and are generated via JSON resource definition files such as the one for <a href="https://github.com/boto/boto3/blob/develop/boto3/data/dynamodb/2012-08-10/resources-1.json">DynamoDB</a></p>
<p>For example, the DynamoDB <code>PutItem</code> API call is completed using the <code>Table</code> object.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">dynamodb</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">Resource</span><span class="p">(</span><span class="s2">&#34;dynamodb&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">table</span> <span class="o">=</span> <span class="n">dynamodb</span><span class="o">.</span><span class="n">Table</span><span class="p">(</span><span class="s2">&#34;table_name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">table</span><span class="o">.</span><span class="n">put_item</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="n">Item</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">        <span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;test&#34;</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="p">)</span></span></span></code></pre></div><p>As opposed to the clients, resources typically handle marshalling data and pagination.</p>
<h2 id="should-i-use-a-client-or-resource">Should I use a client or resource?</h2>
<p>If resources are available for the service your application is interfacing with, use them. Otherwise, use clients. The full list of services are <a href="https://github.com/boto/boto3/tree/develop/boto3/data">here</a>.</p>
<h2 id="note">Note</h2>
<p>Per the <a href="https://boto3.amazonaws.com/v1/documentation/api/latest/guide/resources.html">boto3 resources documentation</a>,</p>
<blockquote>
<p>The AWS Python SDK team does not intend to add new features to the resources interface in boto3. Existing interfaces will continue to operate during boto3&rsquo;s lifecycle. Customers can find access to newer service features through the client interface.</p>
</blockquote>
<p>The AWS Python SDK team <a href="https://github.com/boto/boto3/discussions/3563">will not be adding new resource abstractions</a>; however, the resources that are supported will function in perpetuity.</p>
]]></content:encoded></item><item><title>DynamoDB error: key element does not match the schema</title><link>https://how.wtf/dynamodb-error-key-element-does-not-match-the-schema.html</link><pubDate>Wed, 08 Feb 2023 00:00:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/dynamodb-error-key-element-does-not-match-the-schema.html</guid><description>The provided key element does not match the schema occurs when getting or deleting a record without providing all the proper key elements.
How to fix the error If your DynamoDB schema includes a partition/hash key and a range/sort key, you must specify both attributes.
Given the schema:
1{ 2 &amp;#34;pk&amp;#34;: &amp;#34;test_pk&amp;#34;, 3 &amp;#34;sk&amp;#34;: &amp;#34;test_sk&amp;#34; 4}Python Boto3:
1import boto3 2 3dynamodb = boto3.resource(&amp;#34;dynamodb&amp;#34;) 4table = dynamodb.Table(&amp;#34;test&amp;#34;) 5table.get_item( 6 Key={ 7 &amp;#34;pk&amp;#34;: &amp;#34;test_pk&amp;#34;, 8 &amp;#34;sk&amp;#34;: &amp;#34;test_sk&amp;#34; 9 } 10) 11 12table.</description><content:encoded><![CDATA[<p><strong>The provided key element does not match the schema</strong> occurs when getting or deleting a record without providing all the proper key elements.</p>
<h2 id="how-to-fix-the-error">How to fix the error</h2>
<p>If your DynamoDB schema includes a partition/hash key and a range/sort key, you must specify both attributes.</p>
<p>Given the schema:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;pk&#34;</span><span class="p">:</span> <span class="s2">&#34;test_pk&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nt">&#34;sk&#34;</span><span class="p">:</span> <span class="s2">&#34;test_sk&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Python Boto3:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">dynamodb</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s2">&#34;dynamodb&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">table</span> <span class="o">=</span> <span class="n">dynamodb</span><span class="o">.</span><span class="n">Table</span><span class="p">(</span><span class="s2">&#34;test&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">table</span><span class="o">.</span><span class="n">get_item</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">Key</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="s2">&#34;pk&#34;</span><span class="p">:</span> <span class="s2">&#34;test_pk&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="s2">&#34;sk&#34;</span><span class="p">:</span> <span class="s2">&#34;test_sk&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">table</span><span class="o">.</span><span class="n">delete_item</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">Key</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">        <span class="s2">&#34;pk&#34;</span><span class="p">:</span> <span class="s2">&#34;test_pk&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="s2">&#34;sk&#34;</span><span class="p">:</span> <span class="s2">&#34;test_sk&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="s2">&#34;other&#34;</span><span class="p">:</span> <span class="s2">&#34;test&#34;</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="p">)</span></span></span></code></pre></div>]]></content:encoded></item><item><title>You must specify a region error AWS</title><link>https://how.wtf/you-must-specify-a-region-error-aws.html</link><pubDate>Tue, 07 Feb 2023 00:00:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/you-must-specify-a-region-error-aws.html</guid><description>You must specify a region error occurs when a default AWS Region is not configured.
Error:
1You must specify a region. You can also configure your region by running &amp;#34;aws configure&amp;#34;How to fix the You must specify a region error Method 1: Set the AWS_DEFAULT_REGION environment variable
1export AWS_DEFAULT_REGION=&amp;#34;us-east-1&amp;#34;Method 2: Include the default region in the ~/.aws/config file or run aws configure
1&amp;gt; aws configure 2 AWS Access Key ID [None]: 3 AWS Secret Access Key [None]: 4 Default region name [None]: us-east-1 5 Default output format [None]:The ~/.</description><content:encoded><![CDATA[<p><strong>You must specify a region</strong> error occurs when a default AWS Region is not configured.</p>
<p><strong>Error:</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">You must specify a region. You can also configure your region by running &#34;aws configure&#34;</span></span></code></pre></div><h2 id="how-to-fix-the-you-must-specify-a-region-error">How to fix the <code>You must specify a region</code> error</h2>
<p><strong>Method 1</strong>:
Set the <code>AWS_DEFAULT_REGION</code> environment variable</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">export</span> <span class="nv">AWS_DEFAULT_REGION</span><span class="o">=</span><span class="s2">&#34;us-east-1&#34;</span></span></span></code></pre></div><p><strong>Method 2</strong>:
Include the default region in the <code>~/.aws/config</code> file <em>or</em> run <code>aws configure</code></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">&gt; aws configure
</span></span><span class="line"><span class="ln">2</span><span class="cl">  AWS Access Key ID <span class="o">[</span>None<span class="o">]</span>:
</span></span><span class="line"><span class="ln">3</span><span class="cl">  AWS Secret Access Key <span class="o">[</span>None<span class="o">]</span>:
</span></span><span class="line"><span class="ln">4</span><span class="cl">  Default region name <span class="o">[</span>None<span class="o">]</span>: us-east-1
</span></span><span class="line"><span class="ln">5</span><span class="cl">  Default output format <span class="o">[</span>None<span class="o">]</span>:</span></span></code></pre></div><p>The <code>~/.aws/config</code> file will be generated with the following configuration:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">[default]
</span></span><span class="line"><span class="ln">2</span><span class="cl">region = us-east-1</span></span></code></pre></div><p><strong>Method 3</strong>:
Explicity specify the region with the AWS API</p>
<p>AWS CLI:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws ec2 describe-instances --region us-east-1</span></span></code></pre></div><p>Python Boto3:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">kms</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;kms&#34;</span><span class="p">,</span> <span class="n">region_name</span><span class="o">=</span><span class="s2">&#34;us-east-1&#34;</span><span class="p">)</span></span></span></code></pre></div><p>JavaScript AWS SDK</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">S3Client</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;@aws-sdk/client-s3&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="kr">const</span> <span class="nx">s3Client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">S3Client</span><span class="p">({</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="nx">region</span><span class="o">:</span> <span class="s1">&#39;us-east-1&#39;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">});</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Storing large items in DynamoDB</title><link>https://how.wtf/storing-large-items-in-dynamodb.html</link><pubDate>Mon, 06 Feb 2023 00:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/storing-large-items-in-dynamodb.html</guid><description>Each item in a DynamoDB table has a maximum size limit of 400 KB, including both the attribute names and values. This limit applies to all data types: strings, numbers, and binary data.
The three best ways to mitigate the maximum size limit:
Partitioning the data Compressing the data Storing data in S3 How to handle large data in DynamoDB Partition the data A simple way to get around the item size limit is to split the data into multiple items.</description><content:encoded><![CDATA[<p>Each item in a DynamoDB table has a maximum size limit of 400 KB, including both the attribute names and values. This limit applies to all data types: strings, numbers, and binary data.</p>
<p>The three best ways to mitigate the maximum size limit:</p>
<ol>
<li><a href="#partition-the-data">Partitioning the data</a></li>
<li><a href="#compress-the-data">Compressing the data</a></li>
<li><a href="#store-the-data-in-s3">Storing data in S3</a></li>
</ol>
<h2 id="how-to-handle-large-data-in-dynamodb">How to handle large data in DynamoDB</h2>
<h3 id="partition-the-data">Partition the data</h3>
<p>A simple way to get around the item size limit is to split the data into multiple items.</p>
<p>Table Name: <strong>lorem</strong></p>
<table>
<thead>
<tr>
<th>pk</th>
<th>sk</th>
<th>data</th>
</tr>
</thead>
<tbody>
<tr>
<td>lorem</td>
<td>p#0</td>
<td>Lorem ipsum dolor sit&hellip;</td>
</tr>
<tr>
<td>lorem</td>
<td>p#1</td>
<td>Euismod nisi porta lo&hellip;</td>
</tr>
<tr>
<td>lorem</td>
<td>p#2</td>
<td>rcu risus quis varius&hellip;</td>
</tr>
<tr>
<td>lorem</td>
<td>p#3</td>
<td>phasellus. Enim praes&hellip;</td>
</tr>
</tbody>
</table>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="k">def</span> <span class="nf">partition_data</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">size</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="k">return</span> <span class="p">[</span><span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">:</span><span class="n">i</span><span class="o">+</span><span class="n">size</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">),</span> <span class="n">size</span><span class="p">)]</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># 100 paragraphs of Lorem ipsum</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">lorem</span> <span class="o">=</span> <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="s2">Lorem ipsum dolor sit amet, consectetur adipiscing elit,
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="s2">sed do eiusmod tempor incididunt ut labore et dolore magna 
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="s2">aliqua. Sem integer vitae justo eget magna. At tellus at 
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="s2">urna condimentum mattis pellentesque id. Habitasse...
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="s2">&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="n">dynamodb</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s2">&#34;dynamodb&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="n">table</span> <span class="o">=</span> <span class="n">dynamodb</span><span class="o">.</span><span class="n">Table</span><span class="p">(</span><span class="s2">&#34;lorem&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="n">partition_key</span> <span class="o">=</span> <span class="s2">&#34;lorem&#34;</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="n">sort_key_prefix</span> <span class="o">=</span> <span class="s2">&#34;p#&#34;</span> <span class="c1"># p for partition</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="c1"># Write chunks to DynamoDB</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="n">chunks</span> <span class="o">=</span> <span class="n">partition_data</span><span class="p">(</span><span class="n">lorem</span><span class="p">,</span> <span class="mi">5000</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">chunks</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">    <span class="n">table</span><span class="o">.</span><span class="n">put_item</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">        <span class="n">Item</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">            <span class="s2">&#34;pk&#34;</span><span class="p">:</span> <span class="n">partition_key</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">            <span class="s2">&#34;sk&#34;</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">sort_key_prefix</span><span class="si">}{</span><span class="n">i</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">            <span class="s2">&#34;data&#34;</span><span class="p">:</span> <span class="n">c</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="c1"># Read chunks from DynamoDB</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">    <span class="n">KeyConditionExpression</span><span class="o">=</span><span class="s2">&#34;pk = :pk and begins_with(sk, :sk)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">    <span class="n">ExpressionAttributeValues</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">        <span class="s2">&#34;:pk&#34;</span><span class="p">:</span> <span class="n">partition_key</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">        <span class="s2">&#34;:sk&#34;</span><span class="p">:</span> <span class="n">sort_key_prefix</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">    <span class="n">ScanIndexForward</span><span class="o">=</span><span class="kc">True</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl">
</span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="c1"># Query for all paginated results if applicable.</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="n">items</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;Items&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="k">while</span> <span class="s2">&#34;LastEvaluatedKey&#34;</span> <span class="ow">in</span> <span class="n">response</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">44</span><span class="cl">    <span class="n">response</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">ExclusiveStartKey</span><span class="o">=</span><span class="n">response</span><span class="p">[</span><span class="s2">&#34;LastEvaluatedKey&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">45</span><span class="cl">    <span class="n">items</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">response</span><span class="p">[</span><span class="s2">&#34;Items&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">46</span><span class="cl">
</span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="c1"># Concatenate the data field from all the items</span>
</span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="n">lorem_from_dynamodb</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">i</span><span class="p">[</span><span class="s2">&#34;data&#34;</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">items</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl">
</span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">lorem</span> <span class="o">==</span> <span class="n">lorem_from_dynamodb</span><span class="p">)</span> <span class="c1"># prints True</span></span></span></code></pre></div><h3 id="compress-the-data">Compress the data</h3>
<p>Try to reduce the size of your data by compression. Compression algorithms like Gzip can significantly reduce the size of the data.</p>
<h4 id="compressing-a-single-item">Compressing a single item</h4>
<p>Table Name: <strong>lorem</strong></p>
<table>
<thead>
<tr>
<th>pk</th>
<th>data</th>
</tr>
</thead>
<tbody>
<tr>
<td>lorem</td>
<td>eJy1Xdly3LquffdX6ANu+&hellip;</td>
</tr>
<tr>
<td>lorem</td>
<td>eJytXFl227gS/c8quALtw&hellip;</td>
</tr>
</tbody>
</table>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">zlib</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">def</span> <span class="nf">compress_data</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="k">return</span> <span class="n">zlib</span><span class="o">.</span><span class="n">compress</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">encode</span><span class="p">())</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"># 100 paragraphs of Lorem ipsum</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">lorem</span> <span class="o">=</span> <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="s2">Lorem ipsum dolor sit amet, consectetur adipiscing elit,
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="s2">sed do eiusmod tempor incididunt ut labore et dolore magna 
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="s2">aliqua. Sem integer vitae justo eget magna. At tellus at 
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="s2">urna condimentum mattis pellentesque id. Habitasse...
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="s2">&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="n">dynamodb</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s2">&#34;dynamodb&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="n">table</span> <span class="o">=</span> <span class="n">dynamodb</span><span class="o">.</span><span class="n">Table</span><span class="p">(</span><span class="s2">&#34;lorem&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="n">partition_key</span> <span class="o">=</span> <span class="s2">&#34;lorem&#34;</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="n">sort_key</span> <span class="o">=</span> <span class="s2">&#34;lorem&#34;</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="n">table</span><span class="o">.</span><span class="n">put_item</span><span class="p">(</span><span class="n">Item</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;pk&#34;</span><span class="p">:</span> <span class="n">partition_key</span><span class="p">,</span> <span class="s2">&#34;data&#34;</span><span class="p">:</span> <span class="n">compress_data</span><span class="p">(</span><span class="n">lorem</span><span class="p">)})</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">get_item</span><span class="p">(</span><span class="n">Key</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;pk&#34;</span><span class="p">:</span> <span class="n">partition_key</span><span class="p">})</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;Item&#34;</span><span class="p">][</span><span class="s2">&#34;data&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="n">lorem_from_dynamodb</span> <span class="o">=</span> <span class="n">zlib</span><span class="o">.</span><span class="n">decompress</span><span class="p">(</span><span class="nb">bytes</span><span class="p">(</span><span class="n">data</span><span class="p">))</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">lorem_from_dynamodb</span> <span class="o">==</span> <span class="n">lorem</span><span class="p">)</span>  <span class="c1"># prints true</span></span></span></code></pre></div><h4 id="compressing-a-partitioned-item">Compressing a partitioned item</h4>
<p><strong>DynamoDB schema:</strong></p>
<p>Table Name: <strong>lorem</strong></p>
<table>
<thead>
<tr>
<th>pk</th>
<th>sk</th>
<th>data</th>
</tr>
</thead>
<tbody>
<tr>
<td>lorem</td>
<td>p#0</td>
<td>eJy1Xdly3LquffdX6ANu+&hellip;</td>
</tr>
<tr>
<td>lorem</td>
<td>p#1</td>
<td>eJytXFl227gS/c8quALtw&hellip;</td>
</tr>
</tbody>
</table>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">zlib</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">def</span> <span class="nf">partition_data</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">size</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="k">return</span> <span class="p">[</span><span class="n">data</span><span class="p">[</span><span class="n">i</span> <span class="p">:</span> <span class="n">i</span> <span class="o">+</span> <span class="n">size</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">),</span> <span class="n">size</span><span class="p">)]</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="k">def</span> <span class="nf">compress_data</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="k">return</span> <span class="n">zlib</span><span class="o">.</span><span class="n">compress</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">encode</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c1"># 100 paragraphs of Lorem ipsum</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">lorem</span> <span class="o">=</span> <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="s2">Lorem ipsum dolor sit amet, consectetur adipiscing elit,
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="s2">sed do eiusmod tempor incididunt ut labore et dolore magna 
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="s2">aliqua. Sem integer vitae justo eget magna. At tellus at 
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="s2">urna condimentum mattis pellentesque id. Habitasse...
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="s2">&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="n">dynamodb</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s2">&#34;dynamodb&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="n">table</span> <span class="o">=</span> <span class="n">dynamodb</span><span class="o">.</span><span class="n">Table</span><span class="p">(</span><span class="s2">&#34;lorem&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="n">partition_key</span> <span class="o">=</span> <span class="s2">&#34;lorem&#34;</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="n">sort_key_prefix</span> <span class="o">=</span> <span class="s2">&#34;p#&#34;</span>  <span class="c1"># p for partition</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">
</span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="c1"># Write chunks to DynamoDB</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="n">chunks</span> <span class="o">=</span> <span class="n">partition_data</span><span class="p">(</span><span class="n">lorem</span><span class="p">,</span> <span class="mi">50000</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">chunks</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">    <span class="n">table</span><span class="o">.</span><span class="n">put_item</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">        <span class="n">Item</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">            <span class="s2">&#34;pk&#34;</span><span class="p">:</span> <span class="n">partition_key</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">            <span class="s2">&#34;sk&#34;</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">sort_key_prefix</span><span class="si">}{</span><span class="n">i</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">            <span class="s2">&#34;data&#34;</span><span class="p">:</span> <span class="n">compress_data</span><span class="p">(</span><span class="n">c</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">
</span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="c1"># Read chunks from DynamoDB</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl">    <span class="n">KeyConditionExpression</span><span class="o">=</span><span class="s2">&#34;pk = :pk and begins_with(sk, :sk)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl">    <span class="n">ExpressionAttributeValues</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;:pk&#34;</span><span class="p">:</span> <span class="n">partition_key</span><span class="p">,</span> <span class="s2">&#34;:sk&#34;</span><span class="p">:</span> <span class="n">sort_key_prefix</span><span class="p">},</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">    <span class="n">ScanIndexForward</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">43</span><span class="cl">
</span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="c1"># Query for all paginated results if applicable.</span>
</span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="n">items</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;Items&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="k">while</span> <span class="s2">&#34;LastEvaluatedKey&#34;</span> <span class="ow">in</span> <span class="n">response</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">47</span><span class="cl">    <span class="n">response</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">ExclusiveStartKey</span><span class="o">=</span><span class="n">response</span><span class="p">[</span><span class="s2">&#34;LastEvaluatedKey&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">48</span><span class="cl">    <span class="n">items</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">response</span><span class="p">[</span><span class="s2">&#34;Items&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl">
</span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="c1"># Concatenate the data field from all the items</span>
</span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="n">lorem_from_dynamodb</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">52</span><span class="cl">    <span class="n">zlib</span><span class="o">.</span><span class="n">decompress</span><span class="p">(</span><span class="nb">bytes</span><span class="p">(</span><span class="n">i</span><span class="p">[</span><span class="s2">&#34;data&#34;</span><span class="p">]))</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">items</span>
</span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">54</span><span class="cl">
</span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">lorem_from_dynamodb</span> <span class="o">==</span> <span class="n">lorem</span><span class="p">)</span> <span class="c1"># prints true</span></span></span></code></pre></div><h3 id="store-the-data-in-s3">Store the data in S3</h3>
<p>Consider storing the data in S3 as opposed to an attribute value in DynamoDB.</p>
<p>Table Name: <strong>lorem</strong></p>
<table>
<thead>
<tr>
<th>pk</th>
<th>s3_key</th>
</tr>
</thead>
<tbody>
<tr>
<td>lorem</td>
<td>s3://bucket/key</td>
</tr>
</tbody>
</table>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="c1"># 100 paragraphs of Lorem ipsum</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">lorem</span> <span class="o">=</span> <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="s2">Lorem ipsum dolor sit amet, consectetur adipiscing elit,
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="s2">sed do eiusmod tempor incididunt ut labore et dolore magna 
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="s2">aliqua. Sem integer vitae justo eget magna. At tellus at 
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="s2">urna condimentum mattis pellentesque id. Habitasse...
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="s2">&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">bucket_name</span> <span class="o">=</span> <span class="s2">&#34;bucket_name&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">object_key</span> <span class="o">=</span> <span class="s2">&#34;object_key&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">partition_key</span> <span class="o">=</span> <span class="s2">&#34;lorem&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">s3_key</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;s3://</span><span class="si">{</span><span class="n">bucket_name</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">object_key</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="c1"># Store data in S3 object</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="n">s3</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">&#34;s3&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="n">s3</span><span class="o">.</span><span class="n">put_object</span><span class="p">(</span><span class="n">Bucket</span><span class="o">=</span><span class="n">bucket_name</span><span class="p">,</span> <span class="n">Key</span><span class="o">=</span><span class="n">object_key</span><span class="p">,</span> <span class="n">Body</span><span class="o">=</span><span class="n">lorem</span><span class="o">.</span><span class="n">encode</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="c1"># Store reference to S3 object in DynamoDB</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="n">dynamodb</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s2">&#34;dynamodb&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="n">table</span> <span class="o">=</span> <span class="n">dynamodb</span><span class="o">.</span><span class="n">Table</span><span class="p">(</span><span class="s2">&#34;lorem&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="n">table</span><span class="o">.</span><span class="n">put_item</span><span class="p">(</span><span class="n">Item</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;pk&#34;</span><span class="p">:</span> <span class="n">partition_key</span><span class="p">,</span> <span class="s2">&#34;s3_key&#34;</span><span class="p">:</span> <span class="n">s3_key</span><span class="p">})</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="c1"># Get reference to S3 object in DynamoDB</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">get_item</span><span class="p">(</span><span class="n">Key</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;pk&#34;</span><span class="p">:</span> <span class="n">partition_key</span><span class="p">})</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="n">s3_key</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;Item&#34;</span><span class="p">][</span><span class="s2">&#34;s3_key&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="c1"># Read contents of S3 object</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="n">bucket</span><span class="p">,</span> <span class="n">key</span> <span class="o">=</span> <span class="n">s3_key</span><span class="p">[</span><span class="mi">5</span><span class="p">:]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">)</span>  <span class="c1"># remove &#34;s3://&#34; prefix and split on &#34;/&#34;</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">s3</span><span class="o">.</span><span class="n">get_object</span><span class="p">(</span><span class="n">Bucket</span><span class="o">=</span><span class="n">bucket</span><span class="p">,</span> <span class="n">Key</span><span class="o">=</span><span class="n">key</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="n">lorem_from_s3</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">&#34;Body&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">read</span><span class="p">()</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">
</span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">lorem_from_s3</span> <span class="o">==</span> <span class="n">lorem</span><span class="p">)</span> <span class="c1"># prints True</span></span></span></code></pre></div>]]></content:encoded></item><item><title>How to push an empty commit in Git</title><link>https://how.wtf/how-to-push-an-empty-commit-in-git.html</link><pubDate>Thu, 01 Dec 2022 23:05:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-push-an-empty-commit-in-git.html</guid><description>Pushing an empty commit using Git is straightforward. Git provides an optional flag on the git commit command: --allow-empty.
Pushing without making changes 1git commit --allow-empty -m &amp;#34;empty commit&amp;#34; 1git pushThe commit will be pushed without requiring changes.
Why is this useful? This is useful for retrying a CI pipeline when an issue occurs with a GitHub webhook or CI service.</description><content:encoded><![CDATA[<p>Pushing an empty commit using Git is straightforward. Git provides an optional flag on the <code>git commit</code> command: <code>--allow-empty</code>.</p>
<h2 id="pushing-without-making-changes">Pushing without making changes</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">git commit --allow-empty -m &#34;empty commit&#34;</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">git push</span></span></code></pre></div><p>The commit will be pushed without requiring changes.</p>
<h2 id="why-is-this-useful">Why is this useful?</h2>
<p>This is useful for retrying a CI pipeline when an issue occurs with a GitHub webhook <em>or</em> CI service.</p>
]]></content:encoded></item><item><title>Interfaces in Python</title><link>https://how.wtf/interfaces-in-python.html</link><pubDate>Sat, 01 Oct 2022 15:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/interfaces-in-python.html</guid><description>Python does not have the traditional interface keyword as seen in other programming languages. Instead, the language supports ducktyping and multiple inheritance which may satisfy the need for interfaces for some use cases.
However, there are native pythonic methods to create / implement an interface.
Ducktyping If it quacks like a duck and walks like a duck, Python assumes it&amp;rsquo;s a duck:
1from dataclasses import dataclass 2 3@dataclass 4class User: 5 id: str 6 name: str 7 8class UserService: 9 def get_user_by_id(self, id: str) -&amp;gt; User: 10 &amp;#34;&amp;#34;&amp;#34;Retrieve user by ID&amp;#34;&amp;#34;&amp;#34; 11 pass 12 13class Database(UserService): 14 def get_user_by_id(self, id: str) -&amp;gt; User: 15 &amp;#34;&amp;#34;&amp;#34;Retrieves user by ID from an database&amp;#34;&amp;#34;&amp;#34; 16 # Implementation goes here 17 pass 18 19class Cache(UserService): 20 def get_user_by_id(self, id: str) -&amp;gt; User: 21 &amp;#34;&amp;#34;&amp;#34;Retrieves user by ID from cache&amp;#34;&amp;#34;&amp;#34; 22 # Implementation goes here 23 passDue to the lack of enforcement, this paradigm may not scale well for the implementer&amp;rsquo;s needs.</description><content:encoded><![CDATA[<p>Python does not have the traditional <code>interface</code> keyword as seen in other programming languages. Instead, the language supports ducktyping and multiple inheritance which may satisfy the need for interfaces for some use cases.</p>
<p>However, there are native pythonic methods to create / implement an interface.</p>
<h2 id="ducktyping">Ducktyping</h2>
<p>If it quacks like a duck and walks like a duck, Python assumes it&rsquo;s a duck:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nd">@dataclass</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="k">class</span> <span class="nc">User</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="nb">id</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="k">class</span> <span class="nc">UserService</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="k">def</span> <span class="nf">get_user_by_id</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">User</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="s2">&#34;&#34;&#34;Retrieve user by ID&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="k">pass</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="k">class</span> <span class="nc">Database</span><span class="p">(</span><span class="n">UserService</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="k">def</span> <span class="nf">get_user_by_id</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">User</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="s2">&#34;&#34;&#34;Retrieves user by ID from an database&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="c1"># Implementation goes here</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="k">pass</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="k">class</span> <span class="nc">Cache</span><span class="p">(</span><span class="n">UserService</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="k">def</span> <span class="nf">get_user_by_id</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">User</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">        <span class="s2">&#34;&#34;&#34;Retrieves user by ID from cache&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">        <span class="c1"># Implementation goes here</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">        <span class="k">pass</span></span></span></code></pre></div><p>Due to the lack of enforcement, this paradigm may not scale well for the implementer&rsquo;s needs.</p>
<h2 id="abstract-base-classes">Abstract Base Classes</h2>
<p>Introduced in Python 2.6, abstract base classes allow for interface creation.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">abc</span> <span class="kn">import</span> <span class="n">ABC</span><span class="p">,</span> <span class="n">abstractmethod</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nd">@dataclass</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">class</span> <span class="nc">User</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="nb">id</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="k">class</span> <span class="nc">UserService</span><span class="p">(</span><span class="n">ABC</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="nd">@abstractmethod</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="k">def</span> <span class="nf">get_user_by_id</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">User</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="s2">&#34;&#34;&#34;Retrieve user by ID&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="k">raise</span> <span class="ne">NotImplementedError</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="k">class</span> <span class="nc">Database</span><span class="p">(</span><span class="n">UserService</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="k">def</span> <span class="nf">get_user_by_id</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">User</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="s2">&#34;&#34;&#34;Retrieves user by ID from a database&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">        <span class="c1"># Implementation goes here</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">        <span class="k">pass</span></span></span></code></pre></div><p>This covers two cases:</p>
<ol>
<li>The inheriting class <em>must</em> implement the abstract method</li>
<li>The implementation cannot instantiate this parent&rsquo;s method: <code>super().get_user_by_id(id)</code></li>
</ol>
]]></content:encoded></item><item><title>How to Set Default Audio in Ubuntu</title><link>https://how.wtf/how-to-set-default-audio-in-ubuntu.html</link><pubDate>Mon, 27 Jun 2022 02:10:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-set-default-audio-in-ubuntu.html</guid><description>Using the pactl command, setting default audio in Ubuntu is straightforward. For startup persistence, Ubuntu Startup Applications comes in handy.
pactl is the cli entry for the PulseAudio sound server and will be used in this tutorial.
List all input and output audio List audio outputs:
1pactl list short sinks 11 alsa_output.pci-0000_06_00.6.HiFi__hw_Generic__sink module-alsa-card.c s16le 2ch 48000Hz RUNNINGList audio inputs:
1pactl list short sources 11 alsa_input.usb-Blue_Microphones_Yeti_Stereo_Microphone_797_2019_02_24_60522-00.analog-stereo module-alsa-card.c s16le 2ch 44100Hz SUSPENDED 22 alsa_input.</description><content:encoded><![CDATA[<p>Using the <code>pactl</code> command, setting default audio in Ubuntu is straightforward. For startup persistence, Ubuntu Startup Applications comes in handy.</p>
<p><code>pactl</code> is the cli entry for the PulseAudio sound server and will be used in this tutorial.</p>
<h2 id="list-all-input-and-output-audio">List all input and output audio</h2>
<p>List audio outputs:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">pactl list short sinks</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">1	alsa_output.pci-0000_06_00.6.HiFi__hw_Generic__sink	module-alsa-card.c	s16le 2ch 48000Hz	RUNNING</span></span></code></pre></div><p>List audio inputs:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">pactl list short sources</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">1	alsa_input.usb-Blue_Microphones_Yeti_Stereo_Microphone_797_2019_02_24_60522-00.analog-stereo	module-alsa-card.c	s16le 2ch 44100Hz	SUSPENDED
</span></span><span class="line"><span class="ln">2</span><span class="cl">2	alsa_input.pci-0000_06_00.6.HiFi__hw_Generic__source	module-alsa-card.c	s16le 2ch 44100Hz	SUSPENDED
</span></span><span class="line"><span class="ln">3</span><span class="cl">3	alsa_input.pci-0000_06_00.6.HiFi__hw_acp__source	module-alsa-card.c	s32le 2ch 48000Hz	SUSPENDED</span></span></code></pre></div><p>Take note of the devices listed in the output.</p>
<h2 id="set-default-input-and-output-audio">Set default input and output audio</h2>
<p>Command to set default audio output:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">pactl set-default-sink &lt;device&gt;</span></span></code></pre></div><p>Example usage:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">pactl set-default-sink alsa_output.pci-0000_06_00.6.HiFi__hw_Generic__sink</span></span></code></pre></div><p>Command to set default audio input:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">pactl set-default-source &lt;device&gt;</span></span></code></pre></div><p>Example usage:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">pactl set-default-source alsa_input.usb-Blue_Microphones_Yeti_Stereo_Microphone_797_2019_02_24_60522-00.analog-stereo</span></span></code></pre></div><h2 id="persist-command-on-startrestart">Persist command on start/restart</h2>
<p>Persisting audio output:</p>
<ol>
<li>Open the application named &ldquo;Startup Applications&rdquo; (should be preinstalled)</li>
<li>Click &ldquo;Add&rdquo; button in the upper right hand corner</li>
<li>Enter a command name such as: &ldquo;Set default audio output&rdquo; in the <code>Name:</code> field</li>
<li>Place the <code>pactl set-default-sink &lt;device&gt;</code> command in the <code>Command:</code> field</li>
<li>Click &ldquo;Add&rdquo; button in the bottom right hand corner of the prompt</li>
</ol>
<p>Persisting audio input:</p>
<ol>
<li>Click &ldquo;Add&rdquo; button in the upper right hand corner</li>
<li>Enter a command name such as: &ldquo;Set default audio input&rdquo; in the <code>Name:</code> field</li>
<li>Place the <code>pactl set-default-source &lt;device&gt;</code> command in the <code>Command:</code> field</li>
<li>Click &ldquo;Add&rdquo; button in the bottom right hand corner of the prompt</li>
</ol>
]]></content:encoded></item><item><title>Check if a String Contains a Substring in Python</title><link>https://how.wtf/check-if-a-string-contains-a-substring-in-python.html</link><pubDate>Fri, 24 Jun 2022 01:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/check-if-a-string-contains-a-substring-in-python.html</guid><description>Checking if a string contains a substring is trivial in Python!
The in Operator The in operator is the most straightforward and pythonic method.
Checking if a string has a substring:
1string = &amp;#34;howwtf&amp;#34; 2substring = &amp;#34;wtf&amp;#34; 3 4if substring in string: 5 print(&amp;#34;exists&amp;#34;) 1existsChecking if a string has any substrings:
1string = &amp;#34;howwtf&amp;#34; 2substrings = [&amp;#34;how&amp;#34;, &amp;#34;apple&amp;#34;] 3if any(x in string for x in substrings): 4 print(&amp;#34;exists&amp;#34;) 1existsChecking if a string has all substrings:</description><content:encoded><![CDATA[<p>Checking if a string contains a substring is trivial in Python!</p>
<h2 id="the-in-operator">The <code>in</code> Operator</h2>
<p>The <code>in</code> operator is the most straightforward and pythonic method.</p>
<p>Checking if a string has a substring:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">string</span> <span class="o">=</span> <span class="s2">&#34;howwtf&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">substring</span> <span class="o">=</span> <span class="s2">&#34;wtf&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">if</span> <span class="n">substring</span> <span class="ow">in</span> <span class="n">string</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;exists&#34;</span><span class="p">)</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">exists</span></span></code></pre></div><p>Checking if a string has any substrings:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">string</span> <span class="o">=</span> <span class="s2">&#34;howwtf&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">substrings</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;how&#34;</span><span class="p">,</span> <span class="s2">&#34;apple&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">if</span> <span class="nb">any</span><span class="p">(</span><span class="n">x</span> <span class="ow">in</span> <span class="n">string</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">substrings</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;exists&#34;</span><span class="p">)</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">exists</span></span></code></pre></div><p>Checking if a string has all substrings:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">string</span> <span class="o">=</span> <span class="s2">&#34;howwtf&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">substrings</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;how&#34;</span><span class="p">,</span> <span class="s2">&#34;wtf&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">if</span> <span class="nb">all</span><span class="p">(</span><span class="n">x</span> <span class="ow">in</span> <span class="n">string</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">substrings</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;all exist&#34;</span><span class="p">)</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">all exist</span></span></code></pre></div>]]></content:encoded></item><item><title>For Loops in Bash</title><link>https://how.wtf/for-loops-in-bash.html</link><pubDate>Sun, 19 Jun 2022 22:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/for-loops-in-bash.html</guid><description>Using a for loop in Bash is simple!
for loop over strings 1for i in &amp;#34;follow&amp;#34; &amp;#34;the&amp;#34; &amp;#34;white&amp;#34; &amp;#34;rabbit&amp;#34;; do 2 echo &amp;#34;${i}&amp;#34; 3done 1follow 2the 3white 4rabbitfor loop with range 1for i in {0..2}; do 2 echo &amp;#34;${i}&amp;#34; 3done 10 21 32 bash 4 added an increment parameter for ranges
1for i in {0..6..2}; do 2 echo &amp;#34;${i}&amp;#34; 3done 10 22 34 46for loop with array 1a=(&amp;#34;fried&amp;#34; &amp;#34;green&amp;#34; &amp;#34;tomatoes&amp;#34;) 2for i in ${a[@]}; do 3 echo &amp;#34;${i}&amp;#34; 4done 1fried 2green 3tomatoesfor loop C-style 1for (( i = 0; i &amp;lt;= 3; i++ )); do 2 echo &amp;#34;${i}&amp;#34; 3done 10 21 32 43for loop control statements: break &amp;amp; continue break statement The break statement terminates the current loop.</description><content:encoded><![CDATA[<p>Using a <code>for</code> loop in Bash is simple!</p>
<h2 id="for-loop-over-strings">for loop over strings</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">for</span> i in <span class="s2">&#34;follow&#34;</span> <span class="s2">&#34;the&#34;</span> <span class="s2">&#34;white&#34;</span> <span class="s2">&#34;rabbit&#34;</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">i</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">done</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">follow
</span></span><span class="line"><span class="ln">2</span><span class="cl">the
</span></span><span class="line"><span class="ln">3</span><span class="cl">white
</span></span><span class="line"><span class="ln">4</span><span class="cl">rabbit</span></span></code></pre></div><h2 id="for-loop-with-range">for loop with range</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">for</span> i in <span class="o">{</span>0..2<span class="o">}</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">i</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">done</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">0
</span></span><span class="line"><span class="ln">2</span><span class="cl">1
</span></span><span class="line"><span class="ln">3</span><span class="cl">2</span></span></code></pre></div><blockquote>
<p><code>bash</code> 4 added an increment parameter for ranges</p>
</blockquote>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">for</span> i in <span class="o">{</span>0..6..2<span class="o">}</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">i</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">done</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">0
</span></span><span class="line"><span class="ln">2</span><span class="cl">2
</span></span><span class="line"><span class="ln">3</span><span class="cl">4
</span></span><span class="line"><span class="ln">4</span><span class="cl">6</span></span></code></pre></div><h2 id="for-loop-with-array">for loop with array</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">a</span><span class="o">=(</span><span class="s2">&#34;fried&#34;</span> <span class="s2">&#34;green&#34;</span> <span class="s2">&#34;tomatoes&#34;</span><span class="o">)</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">for</span> i in <span class="si">${</span><span class="nv">a</span><span class="p">[@]</span><span class="si">}</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">i</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">done</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">fried
</span></span><span class="line"><span class="ln">2</span><span class="cl">green
</span></span><span class="line"><span class="ln">3</span><span class="cl">tomatoes</span></span></code></pre></div><h2 id="for-loop-c-style">for loop C-style</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">for</span> <span class="o">((</span> <span class="nv">i</span> <span class="o">=</span> 0<span class="p">;</span> i &lt;<span class="o">=</span> 3<span class="p">;</span> i++ <span class="o">))</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">i</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">done</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">0
</span></span><span class="line"><span class="ln">2</span><span class="cl">1
</span></span><span class="line"><span class="ln">3</span><span class="cl">2
</span></span><span class="line"><span class="ln">4</span><span class="cl">3</span></span></code></pre></div><h2 id="for-loop-control-statements-break--continue">for loop control statements: break &amp; continue</h2>
<h3 id="break-statement">break statement</h3>
<p>The <code>break</code> statement terminates the current loop.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">for</span> i in <span class="s2">&#34;first&#34;</span> <span class="s2">&#34;second&#34;</span> <span class="s2">&#34;break&#34;</span> <span class="s2">&#34;third&#34;</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="k">if</span> <span class="o">[[</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">i</span><span class="si">}</span><span class="s2">&#34;</span> <span class="o">==</span> <span class="s2">&#34;break&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="nb">break</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">i</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="k">done</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">first
</span></span><span class="line"><span class="ln">2</span><span class="cl">second</span></span></code></pre></div><h3 id="continue-statement">continue statement</h3>
<p>The <code>continue</code> statement skips the current iteration and &lsquo;continues&rsquo; to the next iteration.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">for</span> i in <span class="s2">&#34;first&#34;</span> <span class="s2">&#34;second&#34;</span> <span class="s2">&#34;break&#34;</span> <span class="s2">&#34;third&#34;</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="k">if</span> <span class="o">[[</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">i</span><span class="si">}</span><span class="s2">&#34;</span> <span class="o">==</span> <span class="s2">&#34;break&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="k">continue</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">i</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="k">done</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">first
</span></span><span class="line"><span class="ln">2</span><span class="cl">second
</span></span><span class="line"><span class="ln">3</span><span class="cl">third</span></span></code></pre></div>]]></content:encoded></item><item><title>Deploy AWS Cloudfront and security headers with Terraform</title><link>https://how.wtf/deploy-aws-cloudfront-and-security-headers-with-terraform.html</link><pubDate>Sun, 12 Dec 2021 02:15:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/deploy-aws-cloudfront-and-security-headers-with-terraform.html</guid><description>I made a post in July 2021 regarding AWS CloudFront + security headers. Using AWS Cloudfront and Cloudfront Functions, security headers were injected in viewer responses; however, AWS Cloudfront natively supports security headers as of Nov. 2nd, 2021 alongside configurable CORS and custom HTTP response headers.
Security Headers Cloudfront can natively support all the security headers from the last post:
permissions-policy referrer-policy strict-transport-security x-content-type-options x-frame-options x-xss-protection Terraform Code Begin with defining an aws_cloudfront_response_headers_policy resource in Terraform.</description><content:encoded><![CDATA[<p>I made a post in July 2021 regarding <a href="https://how.wtf/deploy-cloudfront-functions-to-add-security-headers-with-aws-cdk.html">AWS CloudFront + security headers</a>. Using AWS Cloudfront and Cloudfront Functions, security headers were injected in viewer responses; however, AWS Cloudfront <a href="https://aws.amazon.com/about-aws/whats-new/2021/11/amazon-cloudfront-supports-cors-security-custom-http-response-headers">natively supports security headers as of Nov. 2nd, 2021</a> alongside configurable CORS and custom HTTP response headers.</p>
<h2 id="security-headers">Security Headers</h2>
<p>Cloudfront can natively support all the security headers from the last post:</p>
<ul>
<li>permissions-policy</li>
<li>referrer-policy</li>
<li>strict-transport-security</li>
<li>x-content-type-options</li>
<li>x-frame-options</li>
<li>x-xss-protection</li>
</ul>
<h2 id="terraform-code">Terraform Code</h2>
<p>Begin with defining an <code>aws_cloudfront_response_headers_policy</code> resource in Terraform. This resources contains all the header policy information. In the following example, the values for each <code>security_headers_config</code> were copied from <a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/example-function-add-security-headers.html">AWS&rsquo;s documentation</a>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-hcl" data-lang="hcl"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">resource</span> <span class="s2">&#34;aws_cloudfront_response_headers_policy&#34; &#34;headers_policy&#34;</span> {
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="n">  name</span> <span class="o">=</span> <span class="s2">&#34;security-headers-policy&#34;</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="k">custom_headers_config</span> {
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="k">items</span> {
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">      header</span> <span class="o">=</span> <span class="s2">&#34;permissions-policy&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">      override</span> <span class="o">=</span> <span class="kt">true</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">      value</span> <span class="o">=</span><span class="n"> &#34;accelerometer</span><span class="o">=</span><span class="p">(),</span><span class="n"> camera</span><span class="o">=</span><span class="p">(),</span><span class="n"> geolocation</span><span class="o">=</span><span class="p">(),</span><span class="n"> gyroscope</span><span class="o">=</span><span class="p">(),</span><span class="n"> magnetometer</span><span class="o">=</span><span class="p">(),</span><span class="n"> microphone</span><span class="o">=</span><span class="p">(),</span><span class="n"> payment</span><span class="o">=</span><span class="p">(),</span><span class="n"> usb</span><span class="o">=</span><span class="p">()</span><span class="err">&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    }
</span></span><span class="line"><span class="ln">10</span><span class="cl">  }
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl">  <span class="k">security_headers_config</span> {
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="k">content_type_options</span> {
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">      override</span> <span class="o">=</span> <span class="kt">true</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    }
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="k">frame_options</span> {
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="n">      override</span> <span class="o">=</span> <span class="kt">true</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="n">      frame_option</span> <span class="o">=</span> <span class="s2">&#34;DENY&#34;</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    }
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl">    <span class="k">referrer_policy</span> {
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="n">      override</span> <span class="o">=</span> <span class="kt">true</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="n">      referrer_policy</span> <span class="o">=</span> <span class="s2">&#34;same-origin&#34;</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    }
</span></span><span class="line"><span class="ln">26</span><span class="cl">
</span></span><span class="line"><span class="ln">27</span><span class="cl">    <span class="k">strict_transport_security</span> {
</span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="n">      override</span> <span class="o">=</span> <span class="kt">true</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="n">      access_control_max_age_sec</span> <span class="o">=</span> <span class="m">63072000</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="n">      include_subdomains</span> <span class="o">=</span> <span class="kt">true</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="n">      preload</span> <span class="o">=</span> <span class="kt">true</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">    }
</span></span><span class="line"><span class="ln">33</span><span class="cl">
</span></span><span class="line"><span class="ln">34</span><span class="cl">    <span class="k">xss_protection</span> {
</span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="n">      override</span> <span class="o">=</span> <span class="kt">true</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="n">      mode_block</span> <span class="o">=</span> <span class="kt">true</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="n">      protection</span> <span class="o">=</span> <span class="kt">true</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">    }
</span></span><span class="line"><span class="ln">39</span><span class="cl">  }
</span></span><span class="line"><span class="ln">40</span><span class="cl">}</span></span></code></pre></div><p>Attach it to a Cloudfront Behavior. In this case, I attached it to the <code>default_cache_behavior</code> block.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-hcl" data-lang="hcl"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">locals</span> {
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="n">  cloudfront_origin_id</span> <span class="o">=</span> <span class="s2">&#34;s3&#34;</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">}
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">resource</span> <span class="s2">&#34;aws_cloudfront_distribution&#34; &#34;distribution&#34;</span> {
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">  aliases</span> <span class="o">=</span> <span class="k">var</span><span class="p">.</span><span class="k">domain_names</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">  enabled</span> <span class="o">=</span> <span class="kt">true</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">  <span class="k">origin</span> {
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">    domain_name</span> <span class="o">=</span> <span class="k">aws_s3_bucket</span><span class="p">.</span><span class="k">bucket</span><span class="p">.</span><span class="k">bucket_domain_name</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">    origin_id</span> <span class="o">=</span> <span class="k">local</span><span class="p">.</span><span class="k">cloudfront_origin_id</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">  }
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl">  <span class="k">default_cache_behavior</span> {
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="n">    allowed_methods</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;GET&#34;, &#34;HEAD&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="n">    cached_methods</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;GET&#34;, &#34;HEAD&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="n">    compress</span> <span class="o">=</span> <span class="kt">true</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="n">    target_origin_id</span> <span class="o">=</span> <span class="k">local</span><span class="p">.</span><span class="k">cloudfront_origin_id</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="n">    viewer_protocol_policy</span> <span class="o">=</span> <span class="s2">&#34;redirect-to-https&#34;</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="n">    response_headers_policy_id</span> <span class="o">=</span> <span class="k">aws_cloudfront_response_headers_policy</span><span class="p">.</span><span class="k">headers_policy</span><span class="p">.</span><span class="k">id</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">  }
</span></span><span class="line"><span class="ln">22</span><span class="cl">
</span></span><span class="line"><span class="ln">23</span><span class="cl">  <span class="k">restrictions</span> {
</span></span><span class="line"><span class="ln">24</span><span class="cl">    <span class="k">geo_restriction</span> {
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="n">      restriction_type</span> <span class="o">=</span> <span class="s2">&#34;none&#34;</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">    }
</span></span><span class="line"><span class="ln">27</span><span class="cl">  }
</span></span><span class="line"><span class="ln">28</span><span class="cl">}</span></span></code></pre></div><p>Once your infrastructure is deployed, AWS CloudFront will forward security headers. To see this in action, refer to the <a href="https://github.com/thomasnotfound/how.wtf/blob/130df83b8bdccee26557be4a73908c30651a9a5e/terraform/modules/website/main.tf"><code>how.wtf</code></a> repository.</p>
]]></content:encoded></item><item><title>How to split a string in Bash</title><link>https://how.wtf/how-to-split-a-string-in-bash.html</link><pubDate>Sat, 11 Dec 2021 02:30:00 -0500</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-split-a-string-in-bash.html</guid><description>Splitting a string in bash is easy with the help of the internal field separator (IFS).
Bash string split using IFS 1string=&amp;#34;you got a friend in me&amp;#34; 2IFS=&amp;#39; &amp;#39; read -ra split &amp;lt;&amp;lt;&amp;lt; &amp;#34;$string&amp;#34; 3echo &amp;#34;${split[*]}&amp;#34; 4# Output: you got a friend in me 5echo &amp;#34;${split[3]}&amp;#34; 6# Output: friendThe above method does not interfere with the IFS global variable since it&amp;rsquo;s only set for that single invocation.</description><content:encoded><![CDATA[<p>Splitting a string in <code>bash</code> is easy with the help of the <a href="https://en.wikipedia.org/wiki/Input_Field_Separators">internal field separator</a> (<code>IFS</code>).</p>
<h2 id="bash-string-split-using-ifs">Bash string split using IFS</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">string</span><span class="o">=</span><span class="s2">&#34;you got a friend in me&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nv">IFS</span><span class="o">=</span><span class="s1">&#39; &#39;</span> <span class="nb">read</span> -ra split <span class="o">&lt;&lt;&lt;</span> <span class="s2">&#34;</span><span class="nv">$string</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">split</span><span class="p">[*]</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># Output: you got a friend in me</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">split</span><span class="p">[3]</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c1"># Output: friend</span></span></span></code></pre></div><p>The above method does not interfere with the <code>IFS</code> global variable since it&rsquo;s only set for that single invocation.</p>
]]></content:encoded></item><item><title>How to upgrade the AWS CDK CLI</title><link>https://how.wtf/how-to-upgrade-the-aws-cdk-cli.html</link><pubDate>Sat, 28 Aug 2021 01:10:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/how-to-upgrade-the-aws-cdk-cli.html</guid><description>AWS CDK CLI users are commonly faced with an error:
This CDK CLI is no compatible with the CDK library used by your application. Please upgrade the CLI to the latest versionLuckily, there are two easy methods for resolving that involve a single command.
NPM npm install -g aws-cdk@latest
Yarn yarn global upgrade aws-cdk</description><content:encoded><![CDATA[<p>AWS CDK CLI users are commonly faced with an error:</p>





<pre tabindex="0"><code>This CDK CLI is no compatible with the CDK library used by your application. Please upgrade the CLI to the latest version</code></pre><p>Luckily, there are two easy methods for resolving that involve a single command.</p>
<h2 id="npm">NPM</h2>
<p><code>npm install -g aws-cdk@latest</code></p>
<h2 id="yarn">Yarn</h2>
<p><code>yarn global upgrade aws-cdk</code></p>
]]></content:encoded></item><item><title>Using Virtualenv with Python</title><link>https://how.wtf/using-virtualenv-with-python.html</link><pubDate>Sat, 10 Jul 2021 21:15:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/using-virtualenv-with-python.html</guid><description>What is Virtualenv? Virtualenv is a tool used for creating isolated Python environments. It allows multiple Python environments/projects to coexist on the same computer with their own dependencies, python versions, and pip versions.
How to install Virtualenv Using Python&amp;rsquo;s package manager, pip or pip3, virtualenv can be installed with a single command:
1pip install --user virtualenvOptionally, you can install it for all users:
1pip install virtualenvHow do I create a new virtualenv environment?</description><content:encoded><![CDATA[<h2 id="what-is-virtualenv">What is Virtualenv?</h2>
<p>Virtualenv is a tool used for creating isolated Python environments. It allows multiple Python environments/projects to coexist on the same computer with their own dependencies, python versions, and pip versions.</p>
<h2 id="how-to-install-virtualenv">How to install Virtualenv</h2>
<p>Using Python&rsquo;s package manager, <code>pip</code> or <code>pip3</code>, virtualenv can be installed with a single command:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install --user virtualenv</span></span></code></pre></div><p>Optionally, you can install it for all users:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip install virtualenv</span></span></code></pre></div><h2 id="how-do-i-create-a-new-virtualenv-environment">How do I create a new virtualenv environment?</h2>
<p>Simply navigate to the project directory and use the <code>virtualenv</code> cli command with a name for the environment (<code>venv</code> in this case):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">$ <span class="nb">cd</span> ~/projects/myproject
</span></span><span class="line"><span class="ln">2</span><span class="cl">$ virtualenv venv
</span></span><span class="line"><span class="ln">3</span><span class="cl">created virtual environment CPython3.8.5.final.0-64 in 1993ms
</span></span><span class="line"><span class="ln">4</span><span class="cl">  creator CPython3Posix<span class="o">(</span><span class="nv">dest</span><span class="o">=</span>/home/user/projects/myproject, <span class="nv">clear</span><span class="o">=</span>False, <span class="nv">no_vcs_ignore</span><span class="o">=</span>False, <span class="nv">global</span><span class="o">=</span>False<span class="o">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">  seeder FromAppData<span class="o">(</span><span class="nv">download</span><span class="o">=</span>False, <span class="nv">pip</span><span class="o">=</span>bundle, <span class="nv">setuptools</span><span class="o">=</span>bundle, <span class="nv">wheel</span><span class="o">=</span>bundle, <span class="nv">via</span><span class="o">=</span>copy, <span class="nv">app_data_dir</span><span class="o">=</span>/home/user/.local/share/virtualenv<span class="o">)</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    added seed packages: <span class="nv">pip</span><span class="o">==</span>21.0.1, <span class="nv">setuptools</span><span class="o">==</span>56.0.0, <span class="nv">wheel</span><span class="o">==</span>0.36.2
</span></span><span class="line"><span class="ln">7</span><span class="cl">  activators BashActivator,CShellActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator</span></span></code></pre></div><p>This creates a new folder named <code>venv</code> in the project directory.</p>
<h2 id="how-do-i-useactivate-a-virtualenv-venv-environment">How do I use/activate a virtualenv (venv) environment?</h2>
<p>To activate the virtualized environment, run the following command from the project directory:</p>
<p>On Linux / MacOS:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">source</span> venv/bin/activate</span></span></code></pre></div><p>On Windows:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">.<span class="se">\v</span>env<span class="se">\S</span>cripts<span class="se">\a</span>ctivate</span></span></code></pre></div><p>With the isolated environment activated, any <code>pip install packagename</code> will be contained within the directories of the virtualized environment.</p>
<h2 id="how-do-i-deactivate-a-virtualenv-venv-environment">How do I deactivate a virtualenv (venv) environment?</h2>
<p>Simply type the following command to deactivate:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">deactivate</span></span></code></pre></div>]]></content:encoded></item><item><title>Deploy Cloudfront Functions to add security headers with AWS CDK</title><link>https://how.wtf/deploy-cloudfront-functions-to-add-security-headers-with-aws-cdk.html</link><pubDate>Sun, 04 Jul 2021 09:15:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/deploy-cloudfront-functions-to-add-security-headers-with-aws-cdk.html</guid><description>With the newly published CloudFront Functions, developers can leverage fast and short lived functions to handle simplistic tasks for viewer requests and responses.
The AWS article covers the differences between Lambda@Edge and CloudFront Functions in detail.
For a quick reference, here is the table from it:
Attribute CloudFront Functions Lambda@Edge Runtime support JavaScript (ECMAScript 5.1 compliant) Node.js / Python Execution location 218+ CloudFront Edge Locations 13 CloudFront Regional Edge Caches CloudFront triggers supported Viewer request / Viewer response Viewer request /Viewer response / Origin request / Origin response Maximum execution time Less than 1 millisecond 5 seconds (viewer triggers) 30 seconds (origin triggers) Maximum memory 2MB 128MB (viewer triggers) / 10GB (origin triggers) Total package size 10 KB 1 MB (viewer triggers) / 50 MB (origin triggers) Network access No Yes File system access No Yes Access to the request body No Yes Pricing Free tier available; charged per request No free tier; charged per request and function duration The Cloudfront Function Code Using Javascript (ECMAScript 5.</description><content:encoded><![CDATA[<p>With the newly published <a href="https://aws.amazon.com/blogs/aws/introducing-cloudfront-functions-run-your-code-at-the-edge-with-low-latency-at-any-scale/">CloudFront Functions</a>, developers can leverage fast and short lived functions to handle simplistic tasks for viewer requests and responses.</p>
<p>The AWS article covers the differences between Lambda@Edge and CloudFront Functions in detail.</p>
<p>For a quick reference, here is the table from it:</p>
<table>
<thead>
<tr>
<th>Attribute</th>
<th>CloudFront Functions</th>
<th>Lambda@Edge</th>
</tr>
</thead>
<tbody>
<tr>
<td>Runtime support</td>
<td>JavaScript (ECMAScript 5.1 compliant)</td>
<td>Node.js / Python</td>
</tr>
<tr>
<td>Execution location</td>
<td>218+ CloudFront Edge Locations</td>
<td>13 CloudFront Regional Edge Caches</td>
</tr>
<tr>
<td>CloudFront triggers supported</td>
<td>Viewer request / Viewer response</td>
<td>Viewer request /Viewer response / Origin request / Origin response</td>
</tr>
<tr>
<td>Maximum execution time</td>
<td>Less than 1 millisecond</td>
<td>5 seconds (viewer triggers) 30 seconds (origin triggers)</td>
</tr>
<tr>
<td>Maximum memory</td>
<td>2MB</td>
<td>128MB (viewer triggers) / 10GB (origin triggers)</td>
</tr>
<tr>
<td>Total package size</td>
<td>10 KB</td>
<td>1 MB (viewer triggers) / 50 MB (origin triggers)</td>
</tr>
<tr>
<td>Network access</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>File system access</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>Access to the request body</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>Pricing</td>
<td>Free tier available; charged per request</td>
<td>No free tier; charged per request and function duration</td>
</tr>
</tbody>
</table>
<h2 id="the-cloudfront-function-code">The Cloudfront Function Code</h2>
<p>Using Javascript (ECMAScript 5.1 compliant), the following code adds common security headers to viewer responses:</p>
<ul>
<li>permissions-policy</li>
<li>referrer-policy</li>
<li>strict-transport-security</li>
<li>x-content-type-options</li>
<li>x-frame-options</li>
<li>x-xss-protection</li>
</ul>
<p>Create a new file named <code>headers.js</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kd">function</span> <span class="nx">handler</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="kd">var</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">event</span><span class="p">.</span><span class="nx">response</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="kd">var</span> <span class="nx">headers</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">headers</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="nx">headers</span><span class="p">[</span><span class="s1">&#39;permissions-policy&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="nx">value</span><span class="o">:</span> <span class="s1">&#39;accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="nx">headers</span><span class="p">[</span><span class="s1">&#39;referrer-policy&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">value</span><span class="o">:</span> <span class="s1">&#39;same-origin&#39;</span><span class="p">};</span> 
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="nx">headers</span><span class="p">[</span><span class="s1">&#39;strict-transport-security&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">value</span><span class="o">:</span> <span class="s1">&#39;max-age=63072000; includeSubdomains; preload&#39;</span> <span class="p">};</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="nx">headers</span><span class="p">[</span><span class="s1">&#39;x-content-type-options&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">value</span><span class="o">:</span> <span class="s1">&#39;nosniff&#39;</span> <span class="p">};</span> 
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="nx">headers</span><span class="p">[</span><span class="s1">&#39;x-frame-options&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">value</span><span class="o">:</span> <span class="s1">&#39;DENY&#39;</span> <span class="p">};</span> 
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="nx">headers</span><span class="p">[</span><span class="s1">&#39;x-xss-protection&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">value</span><span class="o">:</span> <span class="s1">&#39;1; mode=block&#39;</span> <span class="p">};</span> 
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="k">return</span> <span class="nx">response</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="p">};</span></span></span></code></pre></div><p>This code was a modified version from the AWS documentation described <a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/example-function-add-security-headers.html">here</a>.</p>
<h2 id="the-aws-cdk-code">The AWS CDK Code</h2>
<p>The production version of the code in this section can be found in the <a href="https://github.com/thomasnotfound/how.wtf/tree/02a170a08c7a1e44194c0ad1b58ca92968449b8d/infrastructure">how.wtf</a> open source repository.</p>
<h3 id="create-a-requirementstxt">Create a requirements.txt</h3>
<p>For this tutorial, version 1.111.0 of the AWS CDK was used.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="ln">1</span><span class="cl">aws-cdk.aws_cloudfront===1.111.0
</span></span><span class="line"><span class="ln">2</span><span class="cl">aws-cdk.aws_s3===1.111.0
</span></span><span class="line"><span class="ln">3</span><span class="cl">aws-cdk.core===1.111.0</span></span></code></pre></div><h3 id="install-the-dependencies">Install the dependencies</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">pip3 install -r requirements.txt</span></span></code></pre></div><h3 id="create-apppy">Create app.py</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_cdk</span> <span class="kn">import</span> <span class="n">core</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kn">from</span> <span class="nn">stack</span> <span class="kn">import</span> <span class="n">WebsiteStack</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">app</span> <span class="o">=</span> <span class="n">core</span><span class="o">.</span><span class="n">App</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">WebsiteStack</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="s2">&#34;website&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="n">app</span><span class="o">.</span><span class="n">synth</span><span class="p">()</span></span></span></code></pre></div><h3 id="create-cdkjson">Create cdk.json</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="nt">&#34;app&#34;</span><span class="p">:</span> <span class="s2">&#34;python3 app.py&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h3 id="create-stackpy-with-a-basic-s3-bucket">Create stack.py with a basic S3 Bucket</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_cdk</span> <span class="kn">import</span> <span class="n">core</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_cdk</span> <span class="kn">import</span> <span class="n">aws_cloudfront</span> <span class="k">as</span> <span class="n">cloudfront</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_cdk</span> <span class="kn">import</span> <span class="n">aws_s3</span> <span class="k">as</span> <span class="n">s3</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">class</span> <span class="nc">WebsiteStack</span><span class="p">(</span><span class="n">core</span><span class="o">.</span><span class="n">Stack</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">app</span><span class="p">:</span> <span class="n">core</span><span class="o">.</span><span class="n">App</span><span class="p">,</span> <span class="nb">id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="nb">id</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="n">bucket</span> <span class="o">=</span> <span class="n">s3</span><span class="o">.</span><span class="n">Bucket</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">            <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">            <span class="s2">&#34;bucket&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">            <span class="n">website_index_document</span><span class="o">=</span><span class="s2">&#34;index.html&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="n">public_read_access</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="n">removal_policy</span><span class="o">=</span><span class="n">core</span><span class="o">.</span><span class="n">RemovalPolicy</span><span class="o">.</span><span class="n">DESTROY</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="p">)</span></span></span></code></pre></div><h3 id="add-the-cloudfront-function--distribution">Add the CloudFront Function + Distribution</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_cdk</span> <span class="kn">import</span> <span class="n">core</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_cdk</span> <span class="kn">import</span> <span class="n">aws_cloudfront</span> <span class="k">as</span> <span class="n">cloudfront</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">aws_cdk</span> <span class="kn">import</span> <span class="n">aws_s3</span> <span class="k">as</span> <span class="n">s3</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">class</span> <span class="nc">WebsiteStack</span><span class="p">(</span><span class="n">core</span><span class="o">.</span><span class="n">Stack</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">app</span><span class="p">,</span> <span class="nb">id</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="nb">id</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="n">bucket</span> <span class="o">=</span> <span class="n">s3</span><span class="o">.</span><span class="n">Bucket</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">            <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">            <span class="s2">&#34;bucket&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">            <span class="n">website_index_document</span><span class="o">=</span><span class="s2">&#34;index.html&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="n">public_read_access</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="n">removal_policy</span><span class="o">=</span><span class="n">core</span><span class="o">.</span><span class="n">RemovalPolicy</span><span class="o">.</span><span class="n">DESTROY</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl">        <span class="n">security_headers</span> <span class="o">=</span> <span class="n">cloudfront</span><span class="o">.</span><span class="n">Function</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">            <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">            <span class="s2">&#34;security_headers&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">            <span class="n">code</span><span class="o">=</span><span class="n">cloudfront</span><span class="o">.</span><span class="n">FunctionCode</span><span class="o">.</span><span class="n">from_file</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">                <span class="n">file_path</span><span class="o">=</span><span class="s2">&#34;headers.js&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">            <span class="p">),</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">
</span></span><span class="line"><span class="ln">26</span><span class="cl">        <span class="n">distribution</span> <span class="o">=</span> <span class="n">cloudfront</span><span class="o">.</span><span class="n">CloudFrontWebDistribution</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">            <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">            <span class="s2">&#34;cdn&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">            <span class="n">origin_configs</span><span class="o">=</span><span class="p">[</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">                <span class="n">cloudfront</span><span class="o">.</span><span class="n">SourceConfiguration</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">                    <span class="n">s3_origin_source</span><span class="o">=</span><span class="n">cloudfront</span><span class="o">.</span><span class="n">S3OriginConfig</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">                        <span class="n">s3_bucket_source</span><span class="o">=</span><span class="n">bucket</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">                    <span class="p">),</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">                    <span class="n">behaviors</span><span class="o">=</span><span class="p">[</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">                        <span class="n">cloudfront</span><span class="o">.</span><span class="n">Behavior</span><span class="p">(</span><span class="n">is_default_behavior</span><span class="o">=</span><span class="kc">True</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">                        <span class="n">cloudfront</span><span class="o">.</span><span class="n">Behavior</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">                            <span class="n">path_pattern</span><span class="o">=</span><span class="s2">&#34;*&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">                            <span class="n">function_associations</span><span class="o">=</span><span class="p">[</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl">                                <span class="n">cloudfront</span><span class="o">.</span><span class="n">FunctionAssociation</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl">                                    <span class="n">event_type</span><span class="o">=</span><span class="n">cloudfront</span><span class="o">.</span><span class="n">FunctionEventType</span><span class="o">.</span><span class="n">VIEWER_RESPONSE</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">                                    <span class="n">function</span><span class="o">=</span><span class="n">security_headers</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl">                                <span class="p">),</span>
</span></span><span class="line"><span class="ln">43</span><span class="cl">                            <span class="p">],</span>
</span></span><span class="line"><span class="ln">44</span><span class="cl">                        <span class="p">),</span>
</span></span><span class="line"><span class="ln">45</span><span class="cl">                    <span class="p">],</span>
</span></span><span class="line"><span class="ln">46</span><span class="cl">                <span class="p">)</span>
</span></span><span class="line"><span class="ln">47</span><span class="cl">            <span class="p">],</span>
</span></span><span class="line"><span class="ln">48</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl">
</span></span><span class="line"><span class="ln">50</span><span class="cl">        <span class="n">core</span><span class="o">.</span><span class="n">CfnOutput</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">51</span><span class="cl">            <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">52</span><span class="cl">            <span class="s2">&#34;distribution-domain-name&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">53</span><span class="cl">            <span class="n">value</span><span class="o">=</span><span class="n">distribution</span><span class="o">.</span><span class="n">distribution_domain_name</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">54</span><span class="cl">        <span class="p">)</span></span></span></code></pre></div><p>The directory structure should look like this:</p>





<pre tabindex="0"><code>project/
├── app.py
├── cdk.json
├── headers.js
├── requirements.txt
└── stack.py</code></pre><h3 id="deploy-the-stack">Deploy the stack</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">cdk deploy website</span></span></code></pre></div><p>Because of the <code>CfnOutput</code>, the distribution&rsquo;s domain name is exposed via an output on the stack:</p>





<pre tabindex="0"><code>Outputs:
website.distributiondomainname = hostname.cloudfront.net</code></pre><h3 id="add-indexhtml-document-to-the-s3-bucket">Add index.html document to the S3 bucket</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>Security headers!<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span></span></span></code></pre></div><h3 id="test-the-headers">Test the headers</h3>
<p>After adding the <code>index.html</code> document, visit the distribution&rsquo;s domain name to ensure it is working correctly.</p>
<p>To test the security headers, either use your favorite request tool or use <a href="https://securityheaders.com">securityheaders.com</a>.</p>
]]></content:encoded></item><item><title>Convert two lists into a dictionary in Python</title><link>https://how.wtf/convert-two-lists-into-a-dictionary-in-python.html</link><pubDate>Sat, 22 May 2021 13:35:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/convert-two-lists-into-a-dictionary-in-python.html</guid><description>Converting two lists into a dictionary is a breeze in Python when using the dict and zip methods! Additionally, there are alternatives.
Using Zip &amp;amp; Dict 1&amp;gt;&amp;gt;&amp;gt; students = [&amp;#34;Cody&amp;#34;, &amp;#34;Ashley&amp;#34;, &amp;#34;Kerry&amp;#34;] 2&amp;gt;&amp;gt;&amp;gt; grades = [93.5, 95.4, 82.8] 3&amp;gt;&amp;gt;&amp;gt; dict(zip(students, grades)) 4{&amp;#39;Cody&amp;#39;: 93.5, &amp;#39;Ashley&amp;#39;: 95.4, &amp;#39;Kerry&amp;#39;: 82.8}Dictionary Comprehension 1&amp;gt;&amp;gt;&amp;gt; students = [&amp;#34;Cody&amp;#34;, &amp;#34;Ashley&amp;#34;, &amp;#34;Kerry&amp;#34;] 2&amp;gt;&amp;gt;&amp;gt; grades = [93.5, 95.4, 82.8] 3&amp;gt;&amp;gt;&amp;gt; {s: g for s, g in zip(students, grades)} 4{&amp;#39;Cody&amp;#39;: 93.</description><content:encoded><![CDATA[<p>Converting two lists into a dictionary is a breeze in Python when using the <code>dict</code> and <code>zip</code> methods! Additionally, there are alternatives.</p>
<h2 id="using-zip--dict">Using Zip &amp; Dict</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="n">students</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;Cody&#34;</span><span class="p">,</span> <span class="s2">&#34;Ashley&#34;</span><span class="p">,</span> <span class="s2">&#34;Kerry&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="n">grades</span> <span class="o">=</span> <span class="p">[</span><span class="mf">93.5</span><span class="p">,</span> <span class="mf">95.4</span><span class="p">,</span> <span class="mf">82.8</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="nb">dict</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">students</span><span class="p">,</span> <span class="n">grades</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">{</span><span class="s1">&#39;Cody&#39;</span><span class="p">:</span> <span class="mf">93.5</span><span class="p">,</span> <span class="s1">&#39;Ashley&#39;</span><span class="p">:</span> <span class="mf">95.4</span><span class="p">,</span> <span class="s1">&#39;Kerry&#39;</span><span class="p">:</span> <span class="mf">82.8</span><span class="p">}</span></span></span></code></pre></div><h2 id="dictionary-comprehension">Dictionary Comprehension</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="n">students</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;Cody&#34;</span><span class="p">,</span> <span class="s2">&#34;Ashley&#34;</span><span class="p">,</span> <span class="s2">&#34;Kerry&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="n">grades</span> <span class="o">=</span> <span class="p">[</span><span class="mf">93.5</span><span class="p">,</span> <span class="mf">95.4</span><span class="p">,</span> <span class="mf">82.8</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="p">{</span><span class="n">s</span><span class="p">:</span> <span class="n">g</span> <span class="k">for</span> <span class="n">s</span><span class="p">,</span> <span class="n">g</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">students</span><span class="p">,</span> <span class="n">grades</span><span class="p">)}</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">{</span><span class="s1">&#39;Cody&#39;</span><span class="p">:</span> <span class="mf">93.5</span><span class="p">,</span> <span class="s1">&#39;Ashley&#39;</span><span class="p">:</span> <span class="mf">95.4</span><span class="p">,</span> <span class="s1">&#39;Kerry&#39;</span><span class="p">:</span> <span class="mf">82.8</span><span class="p">}</span></span></span></code></pre></div><h2 id="python--26">Python &lt;= 2.6</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">izip</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="n">students</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;Cody&#34;</span><span class="p">,</span> <span class="s2">&#34;Ashley&#34;</span><span class="p">,</span> <span class="s2">&#34;Kerry&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="n">grades</span> <span class="o">=</span> <span class="p">[</span><span class="mf">93.5</span><span class="p">,</span> <span class="mf">95.4</span><span class="p">,</span> <span class="mf">82.8</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="nb">dict</span><span class="p">(</span><span class="n">izip</span><span class="p">(</span><span class="n">keys</span><span class="p">,</span> <span class="n">values</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">{</span><span class="s1">&#39;Cody&#39;</span><span class="p">:</span> <span class="mf">93.5</span><span class="p">,</span> <span class="s1">&#39;Ashley&#39;</span><span class="p">:</span> <span class="mf">95.4</span><span class="p">,</span> <span class="s1">&#39;Kerry&#39;</span><span class="p">:</span> <span class="mf">82.8</span><span class="p">}</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Sort a list of tuples by an item in Python</title><link>https://how.wtf/sort-a-list-of-tuples-by-an-item-in-python.html</link><pubDate>Sat, 08 May 2021 23:00:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/sort-a-list-of-tuples-by-an-item-in-python.html</guid><description>Python has native sort capabilities available for use. You can sort a list of objects by leveraging one of the method specified below.
The questions that this post addresses:
Q: How do you sort a list of tuples by the 1st item? Q: How do you sort a list of tuples by the 2nd item? Q: How do you sort a list of tuples in reverse? sorted() function The sorted() function returns a sorted iterable object, such as a list, in a specified order.</description><content:encoded><![CDATA[<p>Python has native <code>sort</code> capabilities available for use. You can sort a list of objects by leveraging one of the method specified below.</p>
<p>The questions that this post addresses:</p>
<ol>
<li><strong>Q:</strong> How do you sort a list of tuples by the 1st item?</li>
<li><strong>Q:</strong> How do you sort a list of tuples by the 2nd item?</li>
<li><strong>Q:</strong> How do you sort a list of tuples in reverse?</li>
</ol>
<h2 id="sorted-function"><code>sorted()</code> function</h2>
<p>The <code>sorted()</code> function returns a sorted iterable object, such as a list, in a specified order. It does <strong>not</strong> modify the list in place.</p>
<p>By default, the <code>sorted()</code> function evaluates the items to determine their order. In the example below, the lexical ordering of the 1st index determines the sorted list.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">lst</span> <span class="o">=</span> <span class="p">[(</span><span class="s2">&#34;val2&#34;</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="s2">&#34;val1&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">lst</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"># Output: [(&#39;val1&#39;, 1), (&#39;val2&#39;, 2)]</span></span></span></code></pre></div><p>If the 1st elements are identical, the 2nd element determines the ordering:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">lst</span> <span class="o">=</span> <span class="p">[(</span><span class="s2">&#34;val1&#34;</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="s2">&#34;val1&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">lst</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"># Output: [(&#39;val1&#39;, 1), (&#39;val2&#39;, 2)]</span></span></span></code></pre></div><p>You can optionally specify an index to sort on using a lambda function:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">lst</span> <span class="o">=</span> <span class="p">[(</span><span class="s2">&#34;val2&#34;</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="s2">&#34;val1&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"># Output: [(&#39;val1&#39;, 1), (&#39;val2&#39;, 2)]</span></span></span></code></pre></div><p>Reverse as well:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">lst</span> <span class="o">=</span> <span class="p">[(</span><span class="s2">&#34;val2&#34;</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="s2">&#34;val1&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"># Output: [(&#39;val2&#39;, 2), (&#39;val1&#39;, 1)]</span></span></span></code></pre></div><p>Using <code>itemgetter</code> instead of <code>lambda</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">operator</span> <span class="kn">import</span> <span class="n">itemgetter</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">lst</span> <span class="o">=</span> <span class="p">[(</span><span class="s2">&#34;val1&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="s2">&#34;val2&#34;</span><span class="p">,</span> <span class="mi">2</span><span class="p">)]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="n">itemgetter</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># Output: [(&#39;val2&#39;, 2), (&#39;val1&#39;, 1)]</span></span></span></code></pre></div><h2 id="listsort-function"><code>list.sort()</code> function</h2>
<p>The <code>list.sort()</code> method sorts a list <strong>in place</strong> and does <strong>not</strong> return a value.</p>
<p>Similar to the <code>sorted()</code> function, it uses the lexical ordering of the 1st index to determine the sorted list.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">lst</span> <span class="o">=</span> <span class="p">[(</span><span class="s2">&#34;val2&#34;</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="s2">&#34;val1&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">lst</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">lst</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># Output: [(&#39;val1&#39;, 1), (&#39;val2&#39;, 2)]</span></span></span></code></pre></div><p>If the 1st elements are identical, the 2nd element determines the ordering:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">lst</span> <span class="o">=</span> <span class="p">[(</span><span class="s2">&#34;val1&#34;</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="s2">&#34;val1&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">lst</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">lst</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># Output: [(&#39;val1&#39;, 1), (&#39;val2&#39;, 2)]</span></span></span></code></pre></div><p>You can optionally specify an index to sort on using a lambda function:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">lst</span> <span class="o">=</span> <span class="p">[(</span><span class="s2">&#34;val2&#34;</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="s2">&#34;val1&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">lst</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">lst</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># Output: [(&#39;val1&#39;, 1), (&#39;val2&#39;, 2)]</span></span></span></code></pre></div><p>Reverse as well:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">lst</span> <span class="o">=</span> <span class="p">[(</span><span class="s2">&#34;val1&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="s2">&#34;val2&#34;</span><span class="p">,</span> <span class="mi">2</span><span class="p">)]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">lst</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">lst</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># Output: [(&#39;val2&#39;, 2), (&#39;val1&#39;, 1)]</span></span></span></code></pre></div><p>Using <code>itemgetter</code> instead of <code>lambda</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">operator</span> <span class="kn">import</span> <span class="n">itemgetter</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">lst</span> <span class="o">=</span> <span class="p">[(</span><span class="s2">&#34;val1&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="s2">&#34;val2&#34;</span><span class="p">,</span> <span class="mi">2</span><span class="p">)]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">lst</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="n">itemgetter</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">lst</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1"># Output: [(&#39;val2&#39;, 2), (&#39;val1&#39;, 1)]</span></span></span></code></pre></div>]]></content:encoded></item><item><title>Ternary operator in Bash</title><link>https://how.wtf/ternary-operator-in-bash.html</link><pubDate>Sun, 02 May 2021 01:35:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/ternary-operator-in-bash.html</guid><description>The ternary operator is a form of syntactic sugar for an in-line if/else statement. Many languages natively support the operator:
JavaScript:
1const color = &amp;#39;blue&amp;#39;; 2console.log(color === &amp;#39;blue&amp;#39; ? &amp;#39;🟦&amp;#39; : &amp;#39;🟩&amp;#39;); 3// Output: 🟦 Python:
1color = &amp;#34;blue&amp;#34; 2print(&amp;#34;🟦&amp;#34; if color == &amp;#34;blue&amp;#34; else &amp;#34;🟩&amp;#34;) 3# Output: 🟦C:
1#include &amp;lt;stdio.h&amp;gt; 2#include &amp;lt;string.h&amp;gt; 3 4int main() 5{ 6 char color[4] = &amp;#34;blue&amp;#34;; 7 printf(&amp;#34;%s&amp;#34;, (strcmp(color, &amp;#34;blue&amp;#34;) == 0) ? &amp;#34;🟦&amp;#34; : &amp;#34;🟩&amp;#34;); 8} 9// Output: 🟦 Ternary Operation Bash does not have a native ternary operator.</description><content:encoded><![CDATA[<p>The ternary operator is a form of syntactic sugar for an in-line if/else statement. Many languages natively support the operator:</p>
<p><strong>JavaScript:</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="kr">const</span> <span class="nx">color</span> <span class="o">=</span> <span class="s1">&#39;blue&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">color</span> <span class="o">===</span> <span class="s1">&#39;blue&#39;</span> <span class="o">?</span> <span class="s1">&#39;🟦&#39;</span> <span class="o">:</span> <span class="s1">&#39;🟩&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1">// Output: 🟦
</span></span></span></code></pre></div><p><strong>Python:</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">color</span> <span class="o">=</span> <span class="s2">&#34;blue&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;🟦&#34;</span> <span class="k">if</span> <span class="n">color</span> <span class="o">==</span> <span class="s2">&#34;blue&#34;</span> <span class="k">else</span> <span class="s2">&#34;🟩&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"># Output: 🟦</span></span></span></code></pre></div><p><strong>C:</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="ln">1</span><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="kt">char</span> <span class="n">color</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="s">&#34;blue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;%s&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nf">strcmp</span><span class="p">(</span><span class="n">color</span><span class="p">,</span> <span class="s">&#34;blue&#34;</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="o">?</span> <span class="s">&#34;🟦&#34;</span> <span class="o">:</span> <span class="s">&#34;🟩&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="c1">// Output: 🟦
</span></span></span></code></pre></div><h2 id="ternary-operation">Ternary Operation</h2>
<p>Bash does not have a native ternary operator. Instead, the same functionality can be achieved using:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">color</span><span class="o">=</span><span class="s2">&#34;blue&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="o">[[</span> <span class="s2">&#34;</span><span class="nv">$color</span><span class="s2">&#34;</span> <span class="o">==</span> <span class="s2">&#34;blue&#34;</span> <span class="o">]]</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;🟦&#34;</span> <span class="o">||</span> <span class="nb">echo</span> <span class="s2">&#34;🟩&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"># Output: 🟦</span></span></span></code></pre></div><p><code>[[ &quot;$color&quot; == &quot;blue&quot; ]]</code> has an exit status of <strong>0</strong>, so it evaluates the right expression of the <code>&amp;&amp;</code> and echoes the blue emoji.</p>
<p>Similarly, if <code>color=&quot;green&quot;</code>, the <code>[[ &quot;$color&quot; == &quot;blue&quot; ]]</code> expression would have a nonzero exit status, so it evaluates the next logical statement (<code>||</code>) and echos the green emoji.</p>
<h3 id="saving-to-a-variable">Saving to a variable</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">color</span><span class="o">=</span><span class="s2">&#34;blue&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nv">emoji</span><span class="o">=</span><span class="k">$(</span><span class="o">[[</span> <span class="s2">&#34;</span><span class="nv">$color</span><span class="s2">&#34;</span> <span class="o">==</span> <span class="s2">&#34;blue&#34;</span> <span class="o">]]</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;🟦&#34;</span> <span class="o">||</span> <span class="nb">echo</span> <span class="s2">&#34;🟩&#34;</span><span class="k">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">echo</span> <span class="nv">$emoji</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># Output: 🟦</span></span></span></code></pre></div><h3 id="-caution">⚠️ Caution</h3>
<p>If the right-hand side of the <code>&amp;&amp;</code> condition has a nonzero exit status, it will silently default to the or (<code>||</code>) expression.</p>
<p><code>[[ cond ]] &amp;&amp; op1 || op2</code> ➜ <code>op2</code> will be selected if <code>op1</code> fails.</p>
<p><strong>Takeaway</strong>: Be mindful of the <code>op1</code> operation. Ensure it exits with a 0 status code, or you may receive a false negative.</p>
]]></content:encoded></item><item><title>Spread operator in Python</title><link>https://how.wtf/spread-operator-in-python.html</link><pubDate>Wed, 28 Apr 2021 01:00:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/spread-operator-in-python.html</guid><description>The JavaScript spread operator (...) is a useful and convenient syntax for expanding iterable objects into function arguments, array literals, or other object literals.
Python contains a similar &amp;ldquo;spread&amp;rdquo; operator that allows for iterable unpacking. Each of the examples below will demonstrate the comparison between the two languages.
Function Arguments JavaScript:
1function multiply(a, b) { 2 return a * b; 3} 4const numbers = [3, 5]; 5console.log(multiply(...numbers)); 6// Output: 15 Python:</description><content:encoded><![CDATA[<p>The JavaScript spread operator <code>(...)</code> is a useful and convenient syntax for expanding iterable objects into function arguments, array literals, or other object literals.</p>
<p>Python contains a similar &ldquo;spread&rdquo; operator that allows for iterable unpacking. Each of the examples below will demonstrate the comparison between the two languages.</p>
<h2 id="function-arguments">Function Arguments</h2>
<p>JavaScript:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="kd">function</span> <span class="nx">multiply</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="k">return</span> <span class="nx">a</span> <span class="o">*</span> <span class="nx">b</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="kr">const</span> <span class="nx">numbers</span> <span class="o">=</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">];</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">multiply</span><span class="p">(...</span><span class="nx">numbers</span><span class="p">));</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c1">// Output: 15
</span></span></span></code></pre></div><p>Python:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">def</span> <span class="nf">multiply</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="k">return</span> <span class="n">a</span> <span class="o">*</span> <span class="n">b</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">numbers</span> <span class="o">=</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">multiply</span><span class="p">(</span><span class="o">*</span><span class="n">numbers</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1"># Output: 15</span></span></span></code></pre></div><h2 id="array-literals">Array Literals</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="kr">const</span> <span class="nx">numbers</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">];</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kr">const</span> <span class="nx">newNumbers</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="p">...</span><span class="nx">numbers</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">newNumbers</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1">// Output: [ 0, 1, 2, 3, 4 ]
</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">numbers</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">new_numbers</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="o">*</span><span class="n">numbers</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">new_numbers</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># Output: [0, 1, 2, 3, 4]</span></span></span></code></pre></div><h2 id="object-literals">Object Literals</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="kr">const</span> <span class="nx">testObj</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">foo</span><span class="o">:</span> <span class="s1">&#39;bar&#39;</span> <span class="p">};</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">({</span> <span class="p">...</span><span class="nx">testObj</span><span class="p">,</span> <span class="nx">foo2</span><span class="o">:</span> <span class="s1">&#39;bar2&#39;</span> <span class="p">});</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1">// Output: { foo: &#39;bar&#39;, foo2: &#39;bar2&#39; }
</span></span></span></code></pre></div><p>A very similar technique can be applied with Python dictionaries. Notice the double asterisk operator (<code>**</code>).</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">test_obj</span> <span class="o">=</span> <span class="p">{</span> <span class="s1">&#39;foo&#39;</span><span class="p">:</span> <span class="s1">&#39;bar&#39;</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">print</span><span class="p">({</span> <span class="o">**</span><span class="n">test_obj</span><span class="p">,</span> <span class="s1">&#39;foo2&#39;</span><span class="p">:</span> <span class="s1">&#39;bar2&#39;</span> <span class="p">})</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"># Output: {&#39;foo&#39;: &#39;bar&#39;, &#39;foo2&#39;: &#39;bar2&#39;}</span></span></span></code></pre></div><p>To unpack keyword arguments, the double asterisk operator (<code>**</code>) is used. In contrast, the single asterisk operator (<code>*</code>) is used for iterable objects.</p>
]]></content:encoded></item><item><title>AWS CLI query examples</title><link>https://how.wtf/aws-cli-query-examples.html</link><pubDate>Sat, 24 Apr 2021 15:30:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/aws-cli-query-examples.html</guid><description>While some users may prefer to pipe AWS CLI JSON output to jq for parsing, it is possible to leverage the --query functionality that&amp;rsquo;s built-in.
Commonly, users deal with large JSON outputs when executing AWS CLI commands in their environments. To mitigate the process, JMESPath, a powerful filtering language, can specify resource properties, create lists, search output, etc.
AWS CLI Output For reference, the AWS CLI documentation lists JSON document outputs.</description><content:encoded><![CDATA[<p>While some users may prefer to pipe AWS CLI JSON output to <code>jq</code> for parsing, it is possible to leverage the <code>--query</code> functionality that&rsquo;s built-in.</p>
<p>Commonly, users deal with large JSON outputs when executing AWS CLI commands in their environments. To mitigate the process, <a href="https://jmespath.org">JMESPath</a>, a powerful filtering language, can specify resource properties, create lists, search output, etc.</p>
<h2 id="aws-cli-output">AWS CLI Output</h2>
<p>For reference, the AWS CLI documentation lists JSON document outputs. The commands listed below use <code>aws ec2 describe-images</code>, but any combination of the examples can be used for other services and properties.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">aws ec2 describe-images <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --region us-east-1 <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --image-ids ami-1234567890EXAMPLE</span></span></code></pre></div><p>Output (<a href="https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-images.html#examples">provided by AWS</a>):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="nt">&#34;Images&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">            <span class="nt">&#34;VirtualizationType&#34;</span><span class="p">:</span> <span class="s2">&#34;hvm&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">            <span class="nt">&#34;Description&#34;</span><span class="p">:</span> <span class="s2">&#34;Provided by Red Hat, Inc.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">            <span class="nt">&#34;PlatformDetails&#34;</span><span class="p">:</span> <span class="s2">&#34;Red Hat Enterprise Linux&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">            <span class="nt">&#34;EnaSupport&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">            <span class="nt">&#34;Hypervisor&#34;</span><span class="p">:</span> <span class="s2">&#34;xen&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            <span class="nt">&#34;State&#34;</span><span class="p">:</span> <span class="s2">&#34;available&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">            <span class="nt">&#34;SriovNetSupport&#34;</span><span class="p">:</span> <span class="s2">&#34;simple&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">            <span class="nt">&#34;ImageId&#34;</span><span class="p">:</span> <span class="s2">&#34;ami-1234567890EXAMPLE&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">            <span class="nt">&#34;UsageOperation&#34;</span><span class="p">:</span> <span class="s2">&#34;RunInstances:0010&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">            <span class="nt">&#34;BlockDeviceMappings&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">                    <span class="nt">&#34;DeviceName&#34;</span><span class="p">:</span> <span class="s2">&#34;/dev/sda1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">                    <span class="nt">&#34;Ebs&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">                        <span class="nt">&#34;SnapshotId&#34;</span><span class="p">:</span> <span class="s2">&#34;snap-111222333444aaabb&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">                        <span class="nt">&#34;DeleteOnTermination&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">                        <span class="nt">&#34;VolumeType&#34;</span><span class="p">:</span> <span class="s2">&#34;gp2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">                        <span class="nt">&#34;VolumeSize&#34;</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">                        <span class="nt">&#34;Encrypted&#34;</span><span class="p">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">                    <span class="p">}</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">            <span class="p">],</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">            <span class="nt">&#34;Architecture&#34;</span><span class="p">:</span> <span class="s2">&#34;x86_64&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">            <span class="nt">&#34;ImageLocation&#34;</span><span class="p">:</span> <span class="s2">&#34;123456789012/RHEL-8.0.0_HVM-20190618-x86_64-1-Hourly2-GP2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">            <span class="nt">&#34;RootDeviceType&#34;</span><span class="p">:</span> <span class="s2">&#34;ebs&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">            <span class="nt">&#34;OwnerId&#34;</span><span class="p">:</span> <span class="s2">&#34;123456789012&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">            <span class="nt">&#34;RootDeviceName&#34;</span><span class="p">:</span> <span class="s2">&#34;/dev/sda1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">            <span class="nt">&#34;CreationDate&#34;</span><span class="p">:</span> <span class="s2">&#34;2019-05-10T13:17:12.000Z&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">            <span class="nt">&#34;Public&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">            <span class="nt">&#34;ImageType&#34;</span><span class="p">:</span> <span class="s2">&#34;machine&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">            <span class="nt">&#34;Name&#34;</span><span class="p">:</span> <span class="s2">&#34;RHEL-8.0.0_HVM-20190618-x86_64-1-Hourly2-GP2&#34;</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Please note <code>Images</code> is a top-level list-type element in the JSON document.</p>
<h2 id="examples">Examples</h2>
<p><strong>Warning</strong>: The AWS <code>describe-images</code> commands outputs a large JSON document. The JMESPath <a href="https://jmespath.org/tutorial.html#list-and-slice-projections">list slicing</a> (<code>Images[:3]</code>) feature is leveraged to truncate the results. If the full output is desired, use <code>Images[]</code> instead.</p>
<h3 id="listing-outputs">Listing Outputs</h3>
<p><strong>List the <code>ImageId</code> of the first 3 images owned by Amazon:</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">$ aws ec2 describe-images <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --owner amazon <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --query <span class="s2">&#34;Images[:3].ImageId&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="o">[</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="s2">&#34;aki-04206613&#34;</span>,
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="s2">&#34;aki-0a4aa863&#34;</span>,
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="s2">&#34;aki-12f0127b&#34;</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="o">]</span></span></span></code></pre></div><p><strong>Note:</strong> <code>Images[:3].ImageId</code> outputs the property into a single list. If a list for each image is desired, use <code>Images[:3].[ImageId]</code>. As shown in the next example, it&rsquo;s useful for listing multiple properties.</p>
<p><strong>List the <code>ImageId</code> and <code>OwnerId</code> of the first 3 images owned by Amazon:</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln"> 1</span><span class="cl">$ aws ec2 describe-images <span class="se">\
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="se"></span>  --owner amazon <span class="se">\
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="se"></span>  --query <span class="s2">&#34;Images[:3].[ImageId,OwnerId]&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="o">[</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="o">[</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="s2">&#34;aki-04206613&#34;</span>,
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="s2">&#34;137112412989&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="o">]</span>,
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="o">[</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="s2">&#34;aki-0a4aa863&#34;</span>,
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="s2">&#34;470254534024&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="o">]</span>,
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="o">[</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">        <span class="s2">&#34;aki-12f0127b&#34;</span>,
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="s2">&#34;470254534024&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="o">]</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="o">]</span></span></span></code></pre></div><p><strong>List the <code>ImageId</code> and <code>OwnerId</code> of the first 3 images owned by Amazon in a list of JSON objects:</strong></p>
<p>If desired, the output values can be nested in a hash object using JMESPath&rsquo;s <a href="https://jmespath.org/tutorial.html#multiselect">hash multi-selection</a> feature.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln"> 1</span><span class="cl">$ aws ec2 describe-images <span class="se">\
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="se"></span>  --owner amazon <span class="se">\
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="se"></span>  --query <span class="s2">&#34;Images[:3].{image:ImageId,owner:OwnerId}&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="o">[</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="o">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="s2">&#34;image&#34;</span>: <span class="s2">&#34;aki-04206613&#34;</span>,
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="s2">&#34;owner&#34;</span>: <span class="s2">&#34;137112412989&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="o">}</span>,
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="o">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="s2">&#34;image&#34;</span>: <span class="s2">&#34;aki-0a4aa863&#34;</span>,
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="s2">&#34;owner&#34;</span>: <span class="s2">&#34;470254534024&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="o">}</span>,
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="o">{</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">        <span class="s2">&#34;image&#34;</span>: <span class="s2">&#34;aki-12f0127b&#34;</span>,
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="s2">&#34;owner&#34;</span>: <span class="s2">&#34;470254534024&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="o">}</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="o">]</span></span></span></code></pre></div><h3 id="filter-projection--pipe-expressions">Filter Projection &amp; Pipe Expressions</h3>
<p><strong>List the <code>ImageId</code> of the first 3 images that are owned by Amazon&rsquo;s <code>OwnerId</code> of <code>137112412989</code>:</strong></p>
<p>JMESPath provides two features needed to accomplish this query:</p>
<ol>
<li><a href="https://jmespath.org/tutorial.html#filter-projections">Filter Projection</a></li>
<li><a href="https://jmespath.org/tutorial.html#pipe-expressions">Pipe Expressions</a></li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">$ aws ec2 describe-images <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --owner amazon <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --query <span class="s2">&#34;Images[?OwnerId==&#39;137112412989&#39;] | [:3].ImageId&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="o">[</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="s2">&#34;aki-04206613&#34;</span>,
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="s2">&#34;aki-499ccb20&#34;</span>,
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="s2">&#34;aki-5c21674b&#34;</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="o">]</span></span></span></code></pre></div><p>The combination of a filter projection, <code>Images[?OwnerId=='137112412989']</code>, and a pipe expression, <code>| [:3].ImageId</code> satisfies the requirement.</p>
<p>Here&rsquo;s the Python code representing the filter projection operation:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">for</span> <span class="n">image</span> <span class="ow">in</span> <span class="n">inputData</span><span class="p">[</span><span class="s1">&#39;Images&#39;</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="k">if</span> <span class="n">image</span><span class="p">[</span><span class="s1">&#39;OwnerId&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;137112412989&#39;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">image</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="k">return</span> <span class="n">result</span></span></span></code></pre></div><p>It returns:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="nt">&#34;ImageId&#34;</span><span class="p">:</span> <span class="s2">&#34;aki-04206613&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        <span class="nt">&#34;OwnerId&#34;</span><span class="p">:</span> <span class="s2">&#34;137112412989&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="nt">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="nt">&#34;ImageId&#34;</span><span class="p">:</span> <span class="s2">&#34;aki-499ccb20&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="nt">&#34;OwnerId&#34;</span><span class="p">:</span> <span class="s2">&#34;137112412989&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="nt">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="nt">&#34;ImageId&#34;</span><span class="p">:</span> <span class="s2">&#34;aki-5c21674b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">        <span class="nt">&#34;OwnerId&#34;</span><span class="p">:</span> <span class="s2">&#34;137112412989&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="nt">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="s2">&#34;...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="s2">&#34;...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="s2">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="p">]</span></span></span></code></pre></div><p>Then, grab the first three using the pipe expression:</p>
<p><code>| [:3]</code></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="nt">&#34;ImageId&#34;</span><span class="p">:</span> <span class="s2">&#34;aki-04206613&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        <span class="nt">&#34;OwnerId&#34;</span><span class="p">:</span> <span class="s2">&#34;137112412989&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="nt">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="nt">&#34;ImageId&#34;</span><span class="p">:</span> <span class="s2">&#34;aki-499ccb20&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="nt">&#34;OwnerId&#34;</span><span class="p">:</span> <span class="s2">&#34;137112412989&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="nt">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="nt">&#34;ImageId&#34;</span><span class="p">:</span> <span class="s2">&#34;aki-5c21674b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">        <span class="nt">&#34;OwnerId&#34;</span><span class="p">:</span> <span class="s2">&#34;137112412989&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="nt">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="p">]</span></span></span></code></pre></div><p>Then, add the specific <code>ImageId</code> property:</p>
<p><code>| [:3].ImageId</code></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="s2">&#34;aki-04206613&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="s2">&#34;aki-499ccb20&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="s2">&#34;aki-5c21674b&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">]</span></span></span></code></pre></div><h3 id="function-expressions">Function Expressions</h3>
<p>JMESPath supports function expressions:</p>
<p><strong>List the <code>Id</code> and <code>CreationDate</code> of the first 3 images that are owned by Amazon whose <code>PlatformDetails</code> contain the string &lsquo;Linux&rsquo; in sorted order by <code>CreationDate</code>:</strong></p>
<p>Step #1: Use the <code>contains</code> function and grab the first 3 results:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln"> 1</span><span class="cl">$ aws ec2 describe-images <span class="se">\
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="se"></span>  --owner amazon <span class="se">\
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="se"></span>  --query <span class="s2">&#34;Images[?contains(PlatformDetails, &#39;Linux&#39;)] | [:3]&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="o">[</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="o">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="s2">&#34;CreationDate&#34;</span>: <span class="s2">&#34;2016-09-28T21:31:10.000Z&#34;</span>,
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="s2">&#34;ImageId&#34;</span>: <span class="s2">&#34;aki-04206613&#34;</span>,
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="s2">&#34;PlatformDetails&#34;</span>: <span class="s2">&#34;Linux/UNIX&#34;</span>,
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="s2">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="o">}</span>,
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="o">{</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="s2">&#34;CreationDate&#34;</span>: <span class="s2">&#34;2009-12-15T18:44:15.000Z&#34;</span>,
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="s2">&#34;ImageId&#34;</span>: <span class="s2">&#34;aki-0a4aa863&#34;</span>,
</span></span><span class="line"><span class="ln">14</span><span class="cl">        <span class="s2">&#34;PlatformDetails&#34;</span>: <span class="s2">&#34;Linux/UNIX&#34;</span>,
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="s2">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="o">}</span>,
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="o">{</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">        <span class="s2">&#34;CreationDate&#34;</span>: <span class="s2">&#34;&#34;</span>,
</span></span><span class="line"><span class="ln">19</span><span class="cl">        <span class="s2">&#34;ImageId&#34;</span>: <span class="s2">&#34;aki-12f0127b&#34;</span>,
</span></span><span class="line"><span class="ln">20</span><span class="cl">        <span class="s2">&#34;PlatformDetails&#34;</span>: <span class="s2">&#34;Linux/UNIX&#34;</span>,
</span></span><span class="line"><span class="ln">21</span><span class="cl">        <span class="s2">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">    <span class="o">}</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="o">]</span></span></span></code></pre></div><p>This filters the top-level <code>Images</code> for all objects with <code>Linux</code> in their <code>PlatformDetails</code> value.</p>
<p>Step #2: Sort by <code>CreationDate</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">$ aws ec2 describe-images <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --owner amazon <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --query <span class="s2">&#34;Images[?contains(PlatformDetails, &#39;Linux&#39;)] | [:3] | sort_by(@, &amp;CreationDate)[].{CreationDate:CreationDate,Id:ImageId}&#34;</span></span></span></code></pre></div><p>The <code>sort_by</code> function requires an input similar to this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="err">KeyNameHere:</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="nt">&#34;key1&#34;</span><span class="p">:</span> <span class="s2">&#34;val1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">        <span class="nt">&#34;key2&#34;</span><span class="p">:</span> <span class="s2">&#34;val2&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="p">]</span></span></span></code></pre></div><p>If results were ordered by the <code>key2</code> field, the query would be:
<code>sort_by(KeyNameHere, &amp;key2)</code></p>
<p>Similarly, the input to the <code>sort_by</code> function in the example was:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="nt">&#34;CreationDate&#34;</span><span class="p">:</span> <span class="s2">&#34;2016-09-28T21:31:10.000Z&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        <span class="nt">&#34;ImageId&#34;</span><span class="p">:</span> <span class="s2">&#34;aki-04206613&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="nt">&#34;PlatformDetails&#34;</span><span class="p">:</span> <span class="s2">&#34;Linux/UNIX&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="nt">&#34;...&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="p">{</span> <span class="nt">&#34;...&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="p">{</span> <span class="nt">&#34;...&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">]</span></span></span></code></pre></div><p>There is not a top-level key present. In this case, the character <code>@</code> is used to represent the list that is being passed. Additionally, the key that is being sorted on must begin with an <code>&amp;</code>.</p>
<p>After the <code>sort_by</code> function, the list is &ldquo;retrieved&rdquo; <code>[]</code> and the result is formatted to a customized JSON output.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="nt">&#34;CreationDate&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        <span class="nt">&#34;Id&#34;</span><span class="p">:</span> <span class="s2">&#34;aki-12f0127b&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="nt">&#34;CreationDate&#34;</span><span class="p">:</span> <span class="s2">&#34;2009-12-15T18:44:15.000Z&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="nt">&#34;Id&#34;</span><span class="p">:</span> <span class="s2">&#34;aki-0a4aa863&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="nt">&#34;CreationDate&#34;</span><span class="p">:</span> <span class="s2">&#34;2016-09-28T21:31:10.000Z&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="nt">&#34;Id&#34;</span><span class="p">:</span> <span class="s2">&#34;aki-04206613&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">]</span></span></span></code></pre></div><p>The first object contains a null <code>CreationDate</code> value. Luckily, it can be removed from the output using the <code>not_null</code> function.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln"> 1</span><span class="cl">$ aws ec2 describe-images <span class="se">\
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="se"></span>  --owner amazon <span class="se">\
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="se"></span>  --query <span class="s2">&#34;Images[?contains(PlatformDetails, &#39;Linux&#39;)] | [:4] | @[?not_null(CreationDate)] | sort_by(@, &amp;CreationDate)[].{CreationDate:CreationDate,Id:ImageId}&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="o">[</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="o">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="s2">&#34;CreationDate&#34;</span>: <span class="s2">&#34;2009-12-15T18:44:15.000Z&#34;</span>,
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="s2">&#34;Id&#34;</span>: <span class="s2">&#34;aki-0a4aa863&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="o">}</span>,
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="o">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="s2">&#34;CreationDate&#34;</span>: <span class="s2">&#34;2010-09-28T03:52:22.000Z&#34;</span>,
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="s2">&#34;Id&#34;</span>: <span class="s2">&#34;aki-1c669375&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="o">}</span>,
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="o">{</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">        <span class="s2">&#34;CreationDate&#34;</span>: <span class="s2">&#34;2016-09-28T21:31:10.000Z&#34;</span>,
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="s2">&#34;Id&#34;</span>: <span class="s2">&#34;aki-04206613&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="o">}</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="o">]</span></span></span></code></pre></div><p>Lastly, a common scenario is to filter based on environment variables:</p>
<p><strong>Retrieve a cloudformation export by name and store the value</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="ln">1</span><span class="cl">$ <span class="nv">export_name</span><span class="o">=</span><span class="k">$(</span>aws cloudformation list-exports <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>    --query <span class="s2">&#34;Exports[?Name==&#39;</span><span class="nv">$ENV_VAR</span><span class="s2">&#39;].Value&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>    --output text<span class="k">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">$ <span class="nb">echo</span> <span class="nv">$export_name</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">value_here</span></span></code></pre></div><p>The environment variable was used by wrapping with single quotes!</p>
]]></content:encoded></item><item><title>3 ways to format strings in Python</title><link>https://how.wtf/3-ways-to-format-strings-in-python.html</link><pubDate>Wed, 21 Apr 2021 01:25:00 -0400</pubDate><author>Thomas Taylor</author><guid>https://how.wtf/3-ways-to-format-strings-in-python.html</guid><description>In Python versions 3.6 and above, literal string interpolation receives the hype; however, did you know that there are several ways to format strings in Python?
String Formatting (printf-style) String objects have a built-in operation: the % operator (modulo).
If the operator is used once in a string, then a single non-tuple object may be used:
1&amp;gt;&amp;gt;&amp;gt; &amp;#34;Ogres are like %s&amp;#34; % &amp;#34;onions&amp;#34; 2&amp;#39;Ogres are like onions&amp;#39;In this example, the conversion type, %s (string), will be replaced by &amp;ldquo;onions&amp;rdquo;.</description><content:encoded><![CDATA[<p>In Python versions 3.6 and above, literal string interpolation receives the hype; however, did you know that there are several ways to format strings in Python?</p>
<h2 id="string-formatting-printf-style">String Formatting (printf-style)</h2>
<p>String objects have a built-in operation: the <strong>%</strong> operator (modulo).</p>
<p>If the operator is used once in a string, then a single non-tuple object may be used:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="s2">&#34;Ogres are like </span><span class="si">%s</span><span class="s2">&#34;</span> <span class="o">%</span> <span class="s2">&#34;onions&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s1">&#39;Ogres are like onions&#39;</span></span></span></code></pre></div><p>In this example, the conversion type, <code>%s</code> (string), will be replaced by &ldquo;onions&rdquo;.</p>
<p>Otherwise, the strings must be placed within a tuple of <strong>exact length</strong> or a dictionary.</p>
<p><strong>Tuple</strong>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="s2">&#34;</span><span class="si">%s</span><span class="s2"> are like </span><span class="si">%s</span><span class="s2">&#34;</span> <span class="o">%</span> <span class="p">(</span><span class="s2">&#34;Ogres&#34;</span><span class="p">,</span> <span class="s2">&#34;onions&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s1">&#39;Ogres are like onions&#39;</span></span></span></code></pre></div><p><strong>Dictionary</strong>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="s2">&#34;</span><span class="si">%(character)s</span><span class="s2"> are like </span><span class="si">%(vegetable)s</span><span class="s2">&#34;</span> <span class="o">%</span> <span class="p">{</span><span class="s2">&#34;character&#34;</span><span class="p">:</span> <span class="s2">&#34;Ogres&#34;</span><span class="p">,</span> <span class="s2">&#34;vegetable&#34;</span><span class="p">:</span> <span class="s2">&#34;onions&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s1">&#39;Ogres are like onions&#39;</span></span></span></code></pre></div><p>Additionally, there are flag characters and other types. To represent an integer, the type <code>%d</code> (for decimal) could be used. In the example below, <code>%d</code> was used in combination with the <code>0</code> flag character to add trailing zeros.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="s2">&#34;</span><span class="si">%03d</span><span class="s2"> - License to kill&#34;</span> <span class="o">%</span> <span class="mi">7</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s1">&#39;007 - License to kill&#39;</span></span></span></code></pre></div><p>More information can be found <a href="https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting">here</a> about the printf-style string formatting.</p>
<h2 id="string-format-method">String Format Method</h2>
<p>While the predecessor leveraged type conversions and flag characters, Python 3 introduced the <code>str.format(*args, **kwargs)</code> string method.</p>
<p><strong>Using positional arguments</strong>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="s2">&#34;</span><span class="si">{}</span><span class="s2">, </span><span class="si">{}</span><span class="s2">, </span><span class="si">{}</span><span class="s2">&#34;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&#34;one&#34;</span><span class="p">,</span> <span class="s2">&#34;two&#34;</span><span class="p">,</span> <span class="s2">&#34;three&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s1">&#39;one, two, three&#39;</span></span></span></code></pre></div><p><strong>Using indices</strong>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="s2">&#34;</span><span class="si">{2}</span><span class="s2">, </span><span class="si">{1}</span><span class="s2">, </span><span class="si">{0}</span><span class="s2">&#34;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&#34;apple&#34;</span><span class="p">,</span> <span class="s2">&#34;orange&#34;</span><span class="p">,</span> <span class="s2">&#34;cow&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s1">&#39;cow, orange, apple&#39;</span></span></span></code></pre></div><p><strong>Using repeated indices</strong>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="s2">&#34;</span><span class="si">{1}</span><span class="s2">, it&#39;s </span><span class="si">{0}</span><span class="s2">. Why </span><span class="si">{0}</span><span class="s2">?&#34;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="s1">&#39;Naturally&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s2">&#34;Naturally, it&#39;s 13. Why 13?&#34;</span></span></span></code></pre></div><p><strong>Named arguments</strong>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="s2">&#34;</span><span class="si">{character}</span><span class="s2"> are like </span><span class="si">{food}</span><span class="s2">&#34;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">character</span><span class="o">=</span><span class="s2">&#34;Ogres&#34;</span><span class="p">,</span> <span class="n">food</span><span class="o">=</span><span class="s2">&#34;onions&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s1">&#39;Ogres are like onions&#39;</span></span></span></code></pre></div><p><strong>Accessing arguments&rsquo; items</strong>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="n">coord</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="s2">&#34;Plot the coordinate: (</span><span class="si">{0[0]}</span><span class="s2">, </span><span class="si">{0[1]}</span><span class="s2">)&#34;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">coord</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="s1">&#39;Plot the coordinate: (1, 5)&#39;</span></span></span></code></pre></div><p><strong>Thousands separator</strong>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="s2">&#34;It&#39;s over </span><span class="si">{:,}</span><span class="s2">!&#34;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="mi">9000</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s2">&#34;It&#39;s over 9,000!&#34;</span></span></span></code></pre></div><p>&hellip; and more format string syntax tricks <a href="https://docs.python.org/3/library/string.html#format-string-syntax">here</a>.</p>
<h2 id="literal-string-interpolation">Literal String Interpolation</h2>
<p>Python 3.6 introduced literal string interpolation, also known as f-strings. F-strings allow you to embed expressions inside string constants.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="n">pet_name</span> <span class="o">=</span> <span class="s2">&#34;Toto&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="n">state</span> <span class="o">=</span> <span class="s2">&#34;Kansas&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">pet_name</span><span class="si">}</span><span class="s2">, I&#39;ve a feeling we&#39;re not in </span><span class="si">{</span><span class="n">state</span><span class="si">}</span><span class="s2"> anymore.&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="s2">&#34;Toto, I&#39;ve a feeling we&#39;re not in Kansas anymore&#34;</span></span></span></code></pre></div><p>F-strings are prefixed with the letter <code>f</code> and allow you to complete operations inline within the string.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="sa">f</span><span class="s2">&#34;3 + 5 = </span><span class="si">{</span><span class="mi">3</span><span class="o">+</span><span class="mi">5</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s1">&#39;3 + 5 = 8&#39;</span></span></span></code></pre></div><p>The existing syntax from the <code>str.format()</code> method can be used.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python3" data-lang="python3"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="sa">f</span><span class="s2">&#34;It&#39;s over </span><span class="si">{</span><span class="mi">9000</span><span class="si">:</span><span class="s2">,</span><span class="si">}</span><span class="s2">!&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s2">&#34;It&#39;s over 9,000!&#34;</span></span></span></code></pre></div>]]></content:encoded></item></channel></rss>