<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Today I Learned</title><description>A collection of useful things I&apos;ve learned.</description><link>https://til.viseshprasad.com/</link><item><title>appendChild</title><link>https://til.viseshprasad.com/javascript/appendchild/</link><guid isPermaLink="true">https://til.viseshprasad.com/javascript/appendchild/</guid><pubDate>Sun, 23 Feb 2025 01:05:06 GMT</pubDate><content:encoded>&lt;p&gt;Move an element from its current position to the new position.
Also can be used across different containers.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const container = document.querySelector(&amp;quot;.container&amp;quot;);
container.appendChild(container.firstElementChild);

// carousel effect
setInterval(() =&amp;gt; {
    const container = document.querySelector(&amp;#39;.container&amp;#39;);
    container.appendChild(container.firstElementChild);
  }, 1000)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>javascript</category></item><item><title>Extract files from a docker container without running it</title><link>https://til.viseshprasad.com/python/docker-extract-without-running/</link><guid isPermaLink="true">https://til.viseshprasad.com/python/docker-extract-without-running/</guid><pubDate>Fri, 24 Jan 2025 21:04:04 GMT</pubDate><content:encoded>&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import docker
from docker.errors import APIError
from pathlib import Path
import tarfile

def pull_and_extract_files(image_url, output_directory):
    &amp;quot;&amp;quot;&amp;quot;
    Pulls a Docker image from a registry URL, extracts files from the /Nexus/CEI folder,
    and saves them to a specified directory on the disk.

    :param image_url: URL of the Docker image (e.g., &amp;quot;registry_url/repository:tag&amp;quot;)
    :param output_directory: Directory where the files will be saved
    &amp;quot;&amp;quot;&amp;quot;
    client = docker.from_env()

    try:
        # Pull the image from the registry
        print(f&amp;quot;Pulling image {image_url}...&amp;quot;)
        image = client.images.pull(image_url)
        print(&amp;quot;Image pulled successfully.&amp;quot;)

        # Create a temporary container from the image
        print(&amp;quot;Creating temporary container...&amp;quot;)
        container = client.containers.create(image.id)

        try:
            # Copy the /Nexus/CEI folder from the container
            print(&amp;quot;Copying files from /Nexus/CEI...&amp;quot;)
            tar_stream, _ = container.get_archive(&amp;quot;/Nexus/CEI&amp;quot;)

            # Ensure the output directory exists
            output_path = Path(output_directory)
            output_path.mkdir(parents=True, exist_ok=True)

            # Save the tar archive
            tar_file_path = output_path / &amp;quot;cei_files.tar&amp;quot;

            with tar_file_path.open(&amp;quot;wb&amp;quot;) as tar_file:
                for chunk in tar_stream:
                    tar_file.write(chunk)

            print(f&amp;quot;Files saved as tar archive: {tar_file_path}&amp;quot;)
            print(&amp;quot;Extracting tar archive...&amp;quot;)

            # Extract the tar archive
            with tarfile.open(tar_file_path) as tar:
                tar.extractall(path=output_path)

            print(f&amp;quot;Files extracted to: {output_path}&amp;quot;)

        finally:
            # Clean up the container
            print(&amp;quot;Removing temporary container...&amp;quot;)
            container.remove()

    except APIError as e:
        print(f&amp;quot;Docker API error: {e}&amp;quot;)
    except FileNotFoundError as e:
        print(f&amp;quot;File not found: {e}&amp;quot;)
    except Exception as e:
        print(f&amp;quot;An unexpected error occurred: {e}&amp;quot;)
    finally:
        client.close()

# Example usage
if __name__ == &amp;quot;__main__&amp;quot;:
    image_url = &amp;quot;your_registry_url/your_repository:your_tag&amp;quot;
    output_dir = &amp;quot;/path/to/output_directory&amp;quot;
    pull_and_extract_files(image_url, output_dir)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>python</category></item><item><title>Verify and lazy load imports of a python package</title><link>https://til.viseshprasad.com/python/verify-lazy-load-imports/</link><guid isPermaLink="true">https://til.viseshprasad.com/python/verify-lazy-load-imports/</guid><pubDate>Fri, 24 Jan 2025 20:46:49 GMT</pubDate><content:encoded>&lt;p&gt;Scenario: You have a python package with an entry point class that needs to be instantiated and
setup before other classes in the package can be imported and used.&lt;/p&gt;
&lt;p&gt;Solution: Intercept the getattr method of the package&amp;#39;s &lt;code&gt;__init__.py&lt;/code&gt; file to verify and lazy load
the other classes in the package.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;__init__.py&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# serverless

# Import entry point class
from .adr import ADR

# Expose entry point class
__all__ = [&amp;quot;ADR&amp;quot;]


# Lazy import mechanism for dependent classes
class _LazyLoader:
    &amp;quot;&amp;quot;&amp;quot;
    Lazy loader for dependent classes to defer imports until accessed.
    This enforces ADR.setup() to be called before triggering the imports.
    &amp;quot;&amp;quot;&amp;quot;

    def __init__(self):
        self._initialized = False

    def _initialize(self):
        &amp;quot;&amp;quot;&amp;quot;Perform the actual imports when accessed for the first time.&amp;quot;&amp;quot;&amp;quot;
        # Ensure ADR has been set up
        ADR.ensure_setup()

        # Define the modules to be imported
        item_classes = (
            &amp;quot;Item&amp;quot;,
            &amp;quot;HTML&amp;quot;,
            &amp;quot;Animation&amp;quot;,
            ...
        )
        # Dynamically import classes from item and template using importlib
        import importlib

        item_module = importlib.import_module(&amp;quot;.item&amp;quot;, package=__package__)

        # Dynamically add these to the module namespace and __all__
        for cls_name in item_classes:
            cls = getattr(item_module, cls_name, None)
            if cls:
                globals()[cls_name] = cls
                __all__.append(cls_name)

        self._initialized = True

    def __getattr__(self, name):
        if not self._initialized:
            self._initialize()
        return globals()[name]


# Create a lazy loader instance
_lazy_loader = _LazyLoader()


# Define a custom module-level __getattr__ to defer imports
def __getattr__(name):
    return getattr(_lazy_loader, name)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;adr.py&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;class ADR:
    # Class-level variable to track the active instance
    _curr_instance = None

    def __init__(
        self,
        ...
    ) -&amp;gt; None:
        ...
        self.is_setup = False
        ADR._curr_instance = self  # Set this as the current active instance

    def setup(self):
        &amp;quot;&amp;quot;&amp;quot;
        Perform the setup operations for the ADR instance.
        &amp;quot;&amp;quot;&amp;quot;
        ... # Perform setup operations
        self.is_setup = True

    @classmethod
    def ensure_setup(cls):
        &amp;quot;&amp;quot;&amp;quot;
        Check if the current ADR instance has been set up.
        Raise an ImportError if not.
        &amp;quot;&amp;quot;&amp;quot;
        if not cls._curr_instance or not cls._curr_instance.is_setup:
            raise ImportError(
                &amp;quot;ADR has not been set up yet. Please create an ADR instance and call its `setup()` method &amp;quot;
                &amp;quot;before importing and using other classes.&amp;quot;
            )
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>python</category></item><item><title>Defining setup.py dependencies using a URL</title><link>https://til.viseshprasad.com/python/url-deps/</link><guid isPermaLink="true">https://til.viseshprasad.com/python/url-deps/</guid><pubDate>Mon, 13 Jan 2025 17:46:13 GMT</pubDate><content:encoded>&lt;p&gt;Any branch on GitHub can be installed by pip by finding the URL to the zip export of that branch.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;https://github.com/&amp;lt;owner&amp;gt;/&amp;lt;repository&amp;gt;/archive/refs/heads/&amp;lt;branch&amp;gt;.zip&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The solution is to use packagename @ URL, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;setup(
    name=&amp;quot;photos-to-sqlite&amp;quot;,
    ...
    install_requires=[
        &amp;quot;sqlite-utils&amp;gt;=2.7&amp;quot;,
        &amp;quot;boto3&amp;gt;=1.12.41&amp;quot;,
        &amp;quot;osxphotos&amp;gt;=0.28.13 ; sys_platform==&amp;#39;darwin&amp;#39;&amp;quot;,
    ]
    extras_require={
        &amp;quot;test&amp;quot;: [&amp;quot;pytest&amp;quot;, &amp;quot;black&amp;quot;, &amp;quot;hypothesis&amp;quot;, &amp;quot;cogapp&amp;quot;],
        &amp;quot;docs&amp;quot;: [
            &amp;quot;furo&amp;quot;,
            &amp;quot;sphinx-autobuild&amp;quot;,
            &amp;quot;codespell&amp;quot;,
            &amp;quot;sphinx-copybutton&amp;quot;,
            &amp;quot;beanbag-docutils @ https://github.com/simonw/beanbag-docutils/archive/refs/heads/bytes-in-url.zip&amp;quot;,
        ]
)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>python</category></item><item><title>Efficiently copying a file</title><link>https://til.viseshprasad.com/python/copy-files/</link><guid isPermaLink="true">https://til.viseshprasad.com/python/copy-files/</guid><pubDate>Mon, 13 Jan 2025 17:46:11 GMT</pubDate><content:encoded>&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import shutil
shutil.copyfileobj(open(&amp;#39;file1&amp;#39;, &amp;#39;rb&amp;#39;), open(&amp;#39;file2&amp;#39;, &amp;#39;wb&amp;#39;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.python.org/3/library/shutil.html#shutil.copyfileobj&quot;&gt;https://docs.python.org/3/library/shutil.html#shutil.copyfileobj&lt;/a&gt;&lt;/p&gt;
</content:encoded><category>python</category></item><item><title>Use setup.py to install platform-specific dependencies</title><link>https://til.viseshprasad.com/python/platform-deps/</link><guid isPermaLink="true">https://til.viseshprasad.com/python/platform-deps/</guid><pubDate>Mon, 13 Jan 2025 16:52:03 GMT</pubDate><content:encoded>&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;setup(
    name=&amp;quot;photos-to-sqlite&amp;quot;,
    ...
    install_requires=[
        &amp;quot;sqlite-utils&amp;gt;=2.7&amp;quot;,
        &amp;quot;boto3&amp;gt;=1.12.41&amp;quot;,
        &amp;quot;osxphotos&amp;gt;=0.28.13 ; sys_platform==&amp;#39;darwin&amp;#39;&amp;quot;,
    ]
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So &lt;code&gt;; sys_platform==&amp;#39;darwin&amp;#39;&lt;/code&gt; in the install requires line.&lt;/p&gt;
&lt;p&gt;More details: &lt;a href=&quot;https://www.python.org/dev/peps/pep-0508/#environment-markers&quot;&gt;https://www.python.org/dev/peps/pep-0508/#environment-markers&lt;/a&gt;
and &lt;a href=&quot;https://hynek.me/articles/conditional-python-dependencies/&quot;&gt;https://hynek.me/articles/conditional-python-dependencies/&lt;/a&gt;&lt;/p&gt;
</content:encoded><category>python</category></item><item><title>structuredClone</title><link>https://til.viseshprasad.com/javascript/structuredclone/</link><guid isPermaLink="true">https://til.viseshprasad.com/javascript/structuredclone/</guid><pubDate>Mon, 13 Jan 2025 05:52:00 GMT</pubDate><content:encoded>&lt;p&gt; The object spread syntax &lt;code&gt;...&lt;/code&gt; makes a shallow clone of an object, but a shallow clone is only useful for cloning primitive values in the object.
 If you have values like arrays or objects, they aren’t cloned, but the reference to the original object is cloned.
 In late 2021, Deno, Node.js and Firefox released support for structuredClone, followed in 2022 by the other browsers.
The structuredClone algorithm is a deep clone algorithm, like Python’s &lt;code&gt;copy.deepcopy()&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const mushrooms1 = {
  amanita: [&amp;quot;muscaria&amp;quot;, &amp;quot;virosa&amp;quot;],
};

const mushrooms2 = structuredClone(mushrooms1);

mushrooms2.amanita.push(&amp;quot;pantherina&amp;quot;);
mushrooms1.amanita.pop();

console.log(mushrooms2.amanita); // [&amp;quot;muscaria&amp;quot;, &amp;quot;virosa&amp;quot;, &amp;quot;pantherina&amp;quot;]
console.log(mushrooms1.amanita); // [&amp;quot;muscaria&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone&quot;&gt;MDN docs&lt;/a&gt;&lt;/p&gt;
</content:encoded><category>javascript</category></item><item><title>Update all submodules to latest commit on origin</title><link>https://til.viseshprasad.com/git/update-all-submodules-to-latest-commit-on-origin/</link><guid isPermaLink="true">https://til.viseshprasad.com/git/update-all-submodules-to-latest-commit-on-origin/</guid><pubDate>Sat, 11 Jan 2025 23:37:22 GMT</pubDate><content:encoded>&lt;p&gt;I use &lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Tools-Submodules&quot;&gt;Git submodules&lt;/a&gt; in a bunch of projects, and one common task is checking out the latest commit on the origin.&lt;/p&gt;
&lt;p&gt;Since Git 1.8.2 this is a one-liner, but I&amp;#39;m always forgetting it, so here it is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;git submodule update --remote --rebase # or `--merge` if you swing that way
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The answers to &lt;a href=&quot;https://stackoverflow.com/q/5828324&quot;&gt;this StackOverflow question&lt;/a&gt; have some more detail (including a command that works on earlier versions of Git).&lt;/p&gt;
</content:encoded><category>git</category></item><item><title>Ignore all .DS_Store files</title><link>https://til.viseshprasad.com/git/ignore-all-ds-store-files/</link><guid isPermaLink="true">https://til.viseshprasad.com/git/ignore-all-ds-store-files/</guid><pubDate>Sat, 11 Jan 2025 23:37:22 GMT</pubDate><content:encoded>&lt;p&gt;If you use git on a Mac, chances are you&amp;#39;ve accidentally committed a &lt;code&gt;.DS_Store&lt;/code&gt; to a repo. I used to reflexively add &lt;code&gt;.DS_Store&lt;/code&gt; to all my &lt;code&gt;.gitignore&lt;/code&gt; files to avoid ever repeating that mistake.&lt;/p&gt;
&lt;p&gt;But there&amp;#39;s a better way! You can add a global &lt;code&gt;.gitignore&lt;/code&gt; file to your global config with this command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git config --global core.excludesFile &amp;#39;~/.gitignore&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The single quotes around &lt;code&gt;~/.gitignore&lt;/code&gt; aren&amp;#39;t strictly necessary; if you don&amp;#39;t use them, the &lt;code&gt;~&lt;/code&gt; will just get expanded into the absolute path to your home directory.&lt;/p&gt;
&lt;p&gt;Under the hood, that command just adds this to your &lt;code&gt;~/.gitconfig&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[core]
        excludesFile = ~/.gitignore
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>git</category></item><item><title>Conditionally extend a template</title><link>https://til.viseshprasad.com/django/conditionally-extend-a-template/</link><guid isPermaLink="true">https://til.viseshprasad.com/django/conditionally-extend-a-template/</guid><pubDate>Sat, 11 Jan 2025 23:37:22 GMT</pubDate><content:encoded>&lt;p&gt;Django supports &lt;a href=&quot;https://docs.djangoproject.com/en/5.0/ref/templates/language/#id1&quot;&gt;template inheritance&lt;/a&gt; via the &lt;code&gt;extends&lt;/code&gt; tag. Often, a template inheritance chain follows all the way up to a &amp;quot;base&amp;quot; template that contains the full markup for a page, from the doctype to the closing HTML tag.&lt;/p&gt;
&lt;p&gt;A common pattern when using libraries like htmx is returning HTML fragments. In these cases, it can make sense to conditionally extend a template: return the full page when visited directly but &lt;a href=&quot;https://htmx.org/docs/#progressive_enhancement&quot;&gt;return a fragment when requested via Ajax&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s say we have this page layout, &lt;code&gt;layout.html&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;!-- ... --&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    {% block content %}{% endblock %}
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A template rendered within this layout would look something like this:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;{% extends &amp;quot;layout.html&amp;quot;}

{% block content %}&amp;lt;p&amp;gt;Hello, world!&amp;lt;/p&amp;gt;{% endblock %}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To render the template standalone, we can create a &amp;quot;stub&amp;quot; layout (say, &lt;code&gt;ajax.html&lt;/code&gt;) that declares the block and nothing else:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;{% block content %}{% endblock %}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, instead of using a string literal for the name of the template to extend, we use a variable. We can default to &lt;code&gt;layout.html&lt;/code&gt; if it&amp;#39;s omitted:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;{% extends layout|default:&amp;quot;layout.html&amp;quot;}

{% block content %}&amp;lt;p&amp;gt;Hello, world!&amp;lt;/p&amp;gt;{% endblock %}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The view that renders the template might look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def view(request: HttpRequest):
  return render(
    request,
    template_name=&amp;quot;some_template.html&amp;quot;,
    context={ &amp;quot;layout&amp;quot;: &amp;quot;ajax.html&amp;quot; if request.headers.get(&amp;quot;hx-request&amp;quot;) else None },
  )
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>django</category></item></channel></rss>