<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://epicserve.com//feed/til.xml" rel="self" type="application/atom+xml" /><link href="https://epicserve.com//" rel="alternate" type="text/html" /><updated>2024-12-07T00:00:43+00:00</updated><id>https://epicserve.com//feed/til.xml</id><title type="html">Epicserve | Til</title><subtitle>Web development with epic service!</subtitle><author><name>Brent O&apos;Connor</name></author><entry><title type="html">Who knew Python had an HTML module?</title><link href="https://epicserve.com//til/2024/11/15/python-html-module/" rel="alternate" type="text/html" title="Who knew Python had an HTML module?" /><published>2024-11-15T00:00:00+00:00</published><updated>2024-11-15T00:00:00+00:00</updated><id>https://epicserve.com//til/2024/11/15/python-html-module</id><content type="html" xml:base="https://epicserve.com//til/2024/11/15/python-html-module/"><![CDATA[<p>While one of our student engineers was fixing a bug in our HTML-to-Markdown converter, they asked why we weren’t using
Python’s built-in <a href="https://docs.python.org/3/library/html.html#html.unescape">html.unescape()</a> function to
convert HTML entities to Unicode characters.</p>

<p>The reason was simple: I wasn’t aware it existed. Upon investigation, I discovered that <code class="language-plaintext highlighter-rouge">html.unescape()</code> would
indeed convert HTML entities like <code class="language-plaintext highlighter-rouge">&amp;nbsp;</code> to actual non-breaking space characters.</p>

<p>We ultimately decided against implementing this method right now. Currently, we’re replacing <code class="language-plaintext highlighter-rouge">&amp;nbsp;</code> with
a regular space character rather than a non-breaking space character, and using <code class="language-plaintext highlighter-rouge">html.unescape()</code> would change how
text is rendered wherever we use this function. Before making such a change, we would need spend a little more time
investigating to ensure it would benefit our users without introducing unexpected side effects.</p>

<p>Additionally, looking at the <a href="https://github.com/python/cpython/blob/3.13/Lib/html/entities.py">source code</a> it seems
like there are lots of HTML entities that would be converted to Unicode characters. I asked Claude AI and he said
there are 2,125 entities defined. So it seems like it would be prudent to thoroughly evaluate all these potential
conversions before implementing such a change.</p>]]></content><author><name>Brent O&apos;Connor</name></author><category term="til" /><summary type="html"><![CDATA[While one of our student engineers was fixing a bug in our HTML-to-Markdown converter, they asked why we weren’t using Python’s built-in html.unescape() function to convert HTML entities to Unicode characters.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://epicserve.com//assets/images/epicserve-default-social-share-logo.png" /><media:content medium="image" url="https://epicserve.com//assets/images/epicserve-default-social-share-logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Enhancing Jekyll SEO with Image Thumbnails</title><link href="https://epicserve.com//til/2024/11/07/jekyll-seo-tag/" rel="alternate" type="text/html" title="Enhancing Jekyll SEO with Image Thumbnails" /><published>2024-11-07T00:00:00+00:00</published><updated>2024-11-07T00:00:00+00:00</updated><id>https://epicserve.com//til/2024/11/07/jekyll-seo-tag</id><content type="html" xml:base="https://epicserve.com//til/2024/11/07/jekyll-seo-tag/"><![CDATA[<p>I was frustrated when sharing links on social networks because my posts weren’t displaying a thumbnail image. Then, I
discovered that Jekyll, along with the theme I’m using, automatically includes <a href="https://ogp.me/">Open Graph</a> tags for
images thanks to the <a href="https://github.com/jekyll/jekyll-seo-tag">jekyll-seo-tag</a> plugin.</p>

<p>To enable images, all I needed to do was add an <code class="language-plaintext highlighter-rouge">image</code> key to the front matter of my posts. Here’s an example:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">image</span><span class="pi">:</span>
  <span class="na">path</span><span class="pi">:</span> <span class="s">/assets/images/post-image.webp</span>
  <span class="na">alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Post</span><span class="nv"> </span><span class="s">Image</span><span class="nv"> </span><span class="s">Alt</span><span class="nv"> </span><span class="s">Text"</span>
</code></pre></div></div>

<p>If you want a default image to be used when no image is specified, you can set it in the <code class="language-plaintext highlighter-rouge">_config.yml</code> file:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">defaults</span><span class="pi">:</span>
  <span class="pi">-</span>
    <span class="na">scope</span><span class="pi">:</span>
      <span class="na">path</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span> <span class="c1"># an empty string here means all files in the project</span>
    <span class="na">values</span><span class="pi">:</span>
      <span class="na">image</span><span class="pi">:</span>
        <span class="na">path</span><span class="pi">:</span> <span class="s">/assets/images/default-social-share-image.png</span>
        <span class="na">alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Epicserve</span><span class="nv"> </span><span class="s">Logo"</span>
</code></pre></div></div>]]></content><author><name>Brent O&apos;Connor</name></author><category term="til" /><summary type="html"><![CDATA[I was frustrated when sharing links on social networks because my posts weren’t displaying a thumbnail image. Then, I discovered that Jekyll, along with the theme I’m using, automatically includes Open Graph tags for images thanks to the jekyll-seo-tag plugin.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://epicserve.com//assets/images/jekyll-seo-tag/jekyll-seo-tag.webp" /><media:content medium="image" url="https://epicserve.com//assets/images/jekyll-seo-tag/jekyll-seo-tag.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">UV Tool is fun and useful!</title><link href="https://epicserve.com//til/2024/11/03/uv-tools/" rel="alternate" type="text/html" title="UV Tool is fun and useful!" /><published>2024-11-03T00:00:00+00:00</published><updated>2024-11-03T00:00:00+00:00</updated><id>https://epicserve.com//til/2024/11/03/uv-tools</id><content type="html" xml:base="https://epicserve.com//til/2024/11/03/uv-tools/"><![CDATA[<p>I didn’t technically learn all of this today, but I’ve slowly been learning new things about UV almost daily. Here are
some of the awesome things <code class="language-plaintext highlighter-rouge">uv tool</code> can do:</p>

<ol>
  <li>With <code class="language-plaintext highlighter-rouge">uv tool run</code>, you can run commands to test things without the need to install them. Example,
<code class="language-plaintext highlighter-rouge">uv tool run pycowsay "hi"</code>. This will run the <code class="language-plaintext highlighter-rouge">pycowsay</code> command with the argument <code class="language-plaintext highlighter-rouge">hi</code>. I was curious if the python
package was cached and if so, how it was cached. So I asked, and
<a href="https://x.com/charliermarsh/status/1850896707946475839">@charliermarsh</a> said the package is cached and
updated frequently.</li>
  <li>Is <code class="language-plaintext highlighter-rouge">uv tool run pycowsay "hi"</code> too long to type? UV has you covered with the <code class="language-plaintext highlighter-rouge">uvx</code> alias, you can use
<code class="language-plaintext highlighter-rouge">uvx pycowsay "hi"</code> instead.</li>
  <li>Do you have a tool you use all the time and want it installed in its own isolated environment? You can use
<code class="language-plaintext highlighter-rouge">uv tool install</code> to install it. Example, <code class="language-plaintext highlighter-rouge">uv tool install ruff</code>. Curious where it was installed to? You can use
<code class="language-plaintext highlighter-rouge">uv tool dir</code> to find out.</li>
  <li>Want to upgrade a tool or all tools? You can use <code class="language-plaintext highlighter-rouge">uv tool upgrade ruff</code> to upgrade the <code class="language-plaintext highlighter-rouge">ruff</code> tool or
<code class="language-plaintext highlighter-rouge">uv tool upgrade --all</code> to upgrade all tools.</li>
</ol>

<p>Want more details? Check out UV’s <a href="https://docs.astral.sh/uv/reference/cli/#uv-tool">documentation</a>.</p>]]></content><author><name>Brent O&apos;Connor</name></author><category term="til" /><summary type="html"><![CDATA[I didn’t technically learn all of this today, but I’ve slowly been learning new things about UV almost daily. Here are some of the awesome things uv tool can do:]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://epicserve.com//assets/images/epicserve-default-social-share-logo.png" /><media:content medium="image" url="https://epicserve.com//assets/images/epicserve-default-social-share-logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Pathlib has nice shortcuts for reading and writing to files</title><link href="https://epicserve.com//til/2024/10/30/pathlib-read-and-write-shortcuts/" rel="alternate" type="text/html" title="Pathlib has nice shortcuts for reading and writing to files" /><published>2024-10-30T00:00:00+00:00</published><updated>2024-10-30T00:00:00+00:00</updated><id>https://epicserve.com//til/2024/10/30/pathlib-read-and-write-shortcuts</id><content type="html" xml:base="https://epicserve.com//til/2024/10/30/pathlib-read-and-write-shortcuts/"><![CDATA[<p>TIL: If you use <code class="language-plaintext highlighter-rouge">pathlib</code> to work with files, you can use the <code class="language-plaintext highlighter-rouge">read_text</code> and <code class="language-plaintext highlighter-rouge">write_text</code> methods to read and write to
files. This is a nice alternative to using <code class="language-plaintext highlighter-rouge">open()</code> and <code class="language-plaintext highlighter-rouge">close()</code> directly.</p>

<p>It used to be that if you wanted to read and write to a file, you would do something like this:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"example.txt"</span><span class="p">,</span> <span class="s">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
    <span class="n">text</span> <span class="o">=</span> <span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>

<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"example.txt"</span><span class="p">,</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
    <span class="n">f</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">text</span> <span class="o">+</span> <span class="s">" (updated)"</span><span class="p">)</span>
</code></pre></div></div>

<p>But with <code class="language-plaintext highlighter-rouge">pathlib</code>, you can do this instead:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>

<span class="n">path</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="s">"example.txt"</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">path</span><span class="p">.</span><span class="n">read_text</span><span class="p">()</span>
<span class="n">path</span><span class="p">.</span><span class="n">write_text</span><span class="p">(</span><span class="n">text</span> <span class="o">+</span> <span class="s">" (updated)"</span><span class="p">)</span>
</code></pre></div></div>

<p>Using <code class="language-plaintext highlighter-rouge">pathlib</code> is not only more concise but also handles file opening and closing for you, ensuring proper resource management.</p>

<h2 id="behind-the-scenes">Behind the Scenes</h2>
<p>From the <code class="language-plaintext highlighter-rouge">pathlib</code> source code, you can see that <code class="language-plaintext highlighter-rouge">read_text</code> and <code class="language-plaintext highlighter-rouge">write_text</code> methods using context managers to open and
close the files, so you don’t have to worry about it:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">read_text</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">errors</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
    <span class="s">"""
    Open the file in text mode, read it, and close the file.
    """</span>
    <span class="k">with</span> <span class="bp">self</span><span class="p">.</span><span class="nb">open</span><span class="p">(</span><span class="n">mode</span><span class="o">=</span><span class="s">'r'</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="n">encoding</span><span class="p">,</span> <span class="n">errors</span><span class="o">=</span><span class="n">errors</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="n">newline</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>

<span class="k">def</span> <span class="nf">write_text</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">errors</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
    <span class="s">"""
    Open the file in text mode, write to it, and close the file.
    """</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
        <span class="k">raise</span> <span class="nb">TypeError</span><span class="p">(</span><span class="s">'data must be str, not %s'</span> <span class="o">%</span> <span class="n">data</span><span class="p">.</span><span class="n">__class__</span><span class="p">.</span><span class="n">__name__</span><span class="p">)</span>
    <span class="k">with</span> <span class="bp">self</span><span class="p">.</span><span class="nb">open</span><span class="p">(</span><span class="n">mode</span><span class="o">=</span><span class="s">'w'</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="n">encoding</span><span class="p">,</span> <span class="n">errors</span><span class="o">=</span><span class="n">errors</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="n">newline</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">f</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</code></pre></div></div>]]></content><author><name>Brent O&apos;Connor</name></author><category term="til" /><summary type="html"><![CDATA[TIL: If you use pathlib to work with files, you can use the read_text and write_text methods to read and write to files. This is a nice alternative to using open() and close() directly.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://epicserve.com//assets/images/epicserve-default-social-share-logo.png" /><media:content medium="image" url="https://epicserve.com//assets/images/epicserve-default-social-share-logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>