<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kamal Mustafa</title>
    <description>The latest articles on DEV Community by Kamal Mustafa (@k4ml).</description>
    <link>https://dev.to/k4ml</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F29385%2Ffe2b68bb-af97-4310-a279-feb29b877c07.jpg</url>
      <title>DEV Community: Kamal Mustafa</title>
      <link>https://dev.to/k4ml</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/k4ml"/>
    <language>en</language>
    <item>
      <title>Passing Django request object</title>
      <dc:creator>Kamal Mustafa</dc:creator>
      <pubDate>Wed, 30 Oct 2024 03:15:55 +0000</pubDate>
      <link>https://dev.to/k4ml/passing-django-request-object-5cek</link>
      <guid>https://dev.to/k4ml/passing-django-request-object-5cek</guid>
      <description>&lt;p&gt;It handy to pass the request object around but that's a bad practice. Maybe it's influenced from past experiences in PHP where &lt;code&gt;$_REQUEST&lt;/code&gt; is available from anywhere in your code.&lt;/p&gt;

&lt;p&gt;Limit &lt;code&gt;request&lt;/code&gt; object in views function only. It should gather all the required data from the request, maybe using form or serializer. Calling other functions from the views function should only pass specific parameters that function need.&lt;/p&gt;

&lt;p&gt;This will make testing easier as you don't have to mock the request object when testing specific functions that are not views. It encourage better API for your functions, for example:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_articles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_articles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;category&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Adding pytest command to Django manage.py</title>
      <dc:creator>Kamal Mustafa</dc:creator>
      <pubDate>Mon, 28 Oct 2024 04:46:07 +0000</pubDate>
      <link>https://dev.to/k4ml/adding-pytest-command-to-django-managepy-4j77</link>
      <guid>https://dev.to/k4ml/adding-pytest-command-to-django-managepy-4j77</guid>
      <description>&lt;p&gt;The preferred way to invoke pytest is via the &lt;code&gt;pytest&lt;/code&gt; command. Even the app &lt;code&gt;pytest-django&lt;/code&gt; doesn't provide a management command to invoke pytest.&lt;/p&gt;

&lt;p&gt;But I prefer to invoke my django project through a single place, which is the &lt;code&gt;manage.py&lt;/code&gt; script at the project root. So I just add it to the script:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
import pathlib
import subprocess

def main():
    BASE_DIR = pathlib.Path(__file__).parent.absolute()
    sys.path[0] = str(BASE_DIR / "src")

    """Run administrative tasks."""
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "medan.settings")
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc

    # wrap pytest command here so we don't have to manage
    # PYTHONPATH in multiple places. django-pytest unfortunately
    # doesn't provide native management commands so we still need
    # to invoke pytest directly
    if len(sys.argv) &amp;gt; 1 and sys.argv[1] == "pytest":
        pytest_args = " ".join(sys.argv[2:])
        os.environ["PYTHONPATH"] = sys.path[0]
        subprocess.run(f".venv/bin/pytest {pytest_args}", shell=True, env=os.environ)
    else:
        execute_from_command_line(sys.argv)


if __name__ == "__main__":
    main()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allow us to run pytest as:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;poetry run python manage.py pytest -s -x ./path/to/tests/test_*.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>python</category>
      <category>testing</category>
    </item>
    <item>
      <title>PostgreSQL as a Celery Broker</title>
      <dc:creator>Kamal Mustafa</dc:creator>
      <pubDate>Wed, 23 Oct 2024 01:48:20 +0000</pubDate>
      <link>https://dev.to/k4ml/postgresql-as-a-celery-broker-d8d</link>
      <guid>https://dev.to/k4ml/postgresql-as-a-celery-broker-d8d</guid>
      <description>&lt;p&gt;I’m currently using Redis as the broker for Celery, but since I already have PostgreSQL running, I wondered if I could use it as a broker instead. This would eliminate the need for a separate Redis server, saving cost a bit.&lt;/p&gt;

&lt;p&gt;I came across &lt;a href="https://github.com/celery/celery/issues/5149" rel="noopener noreferrer"&gt;this GitHub issue&lt;/a&gt; discussing PostgreSQL as a potential Celery broker. This led me to discover an interesting alternative task queue called &lt;a href="https://github.com/LaunchPlatform/bq" rel="noopener noreferrer"&gt;BQ&lt;/a&gt;, which is built specifically to use PostgreSQL for task management.&lt;/p&gt;

&lt;p&gt;What caught my attention with BQ is that it use mix way to process tasks: the traditional polling method &lt;strong&gt;and&lt;/strong&gt; a pub-sub model, which is pretty unique. For those unfamiliar, BQ’s pub-sub system leverages PostgreSQL’s &lt;code&gt;NOTIFY&lt;/code&gt; function. The way it works is that when a new task is added, &lt;code&gt;NOTIFY&lt;/code&gt; sends a signal to listening clients, so they can act immediately—no more constant polling to check for new tasks, which can be more efficient.&lt;/p&gt;

&lt;p&gt;One thing I’ve been mindful of when working with task queues is the &lt;strong&gt;noisy neighbor&lt;/strong&gt; problem, where one task queue can consume too many resources and affect the performance of others. I haven’t fully explored how BQ handles this, but it’s definitely something to look into if you’re considering a PostgreSQL-based task queue.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>queue</category>
      <category>celery</category>
    </item>
    <item>
      <title>Wagtail programmatically create page translation</title>
      <dc:creator>Kamal Mustafa</dc:creator>
      <pubDate>Mon, 30 Sep 2024 04:06:00 +0000</pubDate>
      <link>https://dev.to/k4ml/wagtail-programmatically-create-page-translation-2814</link>
      <guid>https://dev.to/k4ml/wagtail-programmatically-create-page-translation-2814</guid>
      <description>&lt;p&gt;I can't find any programmatic interface to create page translation. All the logics seems being implemented in &lt;code&gt;SubmitTranslationView&lt;/code&gt; in &lt;code&gt;wagtail.contrib.simple_translation.views&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So the only way to access those programmatically is by simulating the request to access the views. I wrapped this in a function named &lt;code&gt;translate_page()&lt;/code&gt;. To translate a page, we can call this function as:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;page_ja&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;translate_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ja&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or we can pass the optional parameter &lt;code&gt;include_subtree&lt;/code&gt;:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;page_ja&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;translate_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ja&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include_subtree&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the function is defined as:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;translate_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include_subtree&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Locale&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_or_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;language_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;locales&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;include_subtree&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;include_subtree&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;simple_translation:submit_page_translation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;page_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RequestFactory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
    &lt;span class="n"&gt;get_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;middleware&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SessionMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FallbackStorage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;SubmitPageTranslationView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;SubmitPageTranslationView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;page_translated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_translations&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;specific&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;page_translated&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have another function called &lt;code&gt;translate_snippet()&lt;/code&gt;. The only difference is just the url to submit and no &lt;code&gt;include_subtree&lt;/code&gt; parameter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Page tree gotchas
&lt;/h2&gt;

&lt;p&gt;For all our sites, we have a setup script that will automatically populating some posts and their translation so that developer can start working right away instead of having to create sample pages manually.&lt;/p&gt;

&lt;p&gt;Our page structure is like this:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HomePage ==&amp;gt; BlogIndexPage ==&amp;gt; BlogPage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the setup script will do the following:-&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create the root admin user, let's call it user One.&lt;/li&gt;
&lt;li&gt;Create instance of HomePage&lt;/li&gt;
&lt;li&gt;Attach HomePage as new root page&lt;/li&gt;
&lt;li&gt;Create Japanese translation of HomePage&lt;/li&gt;
&lt;li&gt;Create instance of BlogIndexPage&lt;/li&gt;
&lt;li&gt;Populate BlogPage with sample posts and attach them under BlogIndexPage&lt;/li&gt;
&lt;li&gt;Translate BlogIndexPage with &lt;code&gt;include_subtree=True&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This all works well until we're setting new site where the page structure is:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BlogIndexPage ==&amp;gt; BlogPage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we omitted &lt;code&gt;HomePage&lt;/code&gt; (&lt;em&gt;which I think a bad idea now but let's save it for another topic&lt;/em&gt;) since this site is mainly a blog. The first thing I notice after running the setup script is that no translation of the blog posts created, despite we already passed &lt;code&gt;include_subtree&lt;/code&gt; when translating BlogIndexPage.&lt;/p&gt;

&lt;p&gt;My first gut reaction was it could be some changes in new wagtail versions. Most our sites being created few years ago and still on wagtail 5 but for this new site, we will start with wagtail 6 since it's the latest.&lt;/p&gt;

&lt;p&gt;But looking at wagtail's commit logs for &lt;code&gt;simple_translation&lt;/code&gt; &lt;code&gt;views.py&lt;/code&gt;, the code last changes was three years ago. And we can see the code basically the same between wagtail 5 and 6.&lt;/p&gt;

&lt;p&gt;The problem with &lt;code&gt;translate_page&lt;/code&gt; function above is that it doesn't check for any errors. Because catching errors mean you have to parse the request's response for some error string. But tracing the code flow lead me to a stage where I can see the code is not executed because the form is not validated.&lt;/p&gt;

&lt;p&gt;Printing &lt;code&gt;form.errors&lt;/code&gt; showed error messages related to invalid locale. This is strange because we can see in the &lt;code&gt;translate_page&lt;/code&gt; function above we're creating the locale if it doesn't exists yet.&lt;/p&gt;

&lt;p&gt;And printing the form's &lt;code&gt;self.fields["locales"].choices&lt;/code&gt; I can the locale is there in the choice during first call of &lt;code&gt;translate_page()&lt;/code&gt; when translating the root page, but the choices was empty when calling it second time to translate &lt;code&gt;BlogIndexPage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Reading the form's code, &lt;code&gt;locales&lt;/code&gt; field's choices is set dynamically in the &lt;code&gt;__init__&lt;/code&gt; method, where locale of the page that already translated will be removed. This could be the reason why the locale was empty in the second call. But the page is not translated yet!&lt;/p&gt;

&lt;p&gt;Let's recall back the process:-&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create BlogIndexPage&lt;/li&gt;
&lt;li&gt;Attach BlogIndexPage to root page&lt;/li&gt;
&lt;li&gt;Translate root page to ja&lt;/li&gt;
&lt;li&gt;Populate BlogPage and attach them to BlogIndexPage&lt;/li&gt;
&lt;li&gt;Translate BlogIndexPage to ja&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And this is where the light bulb (💡) came in, after hours of debugging. In the original script, we're translating HomePage to ja first, and then BlogIndexPage with all its children. But in this new script, the root page is BlogIndexPage. So BlogIndexPage already translated the second time we call &lt;code&gt;translate_page&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;So that's the reason &lt;code&gt;locales&lt;/code&gt; choices become empty.&lt;/p&gt;

</description>
      <category>python</category>
      <category>wagtail</category>
      <category>i18n</category>
      <category>l10n</category>
    </item>
    <item>
      <title>Inline script defer</title>
      <dc:creator>Kamal Mustafa</dc:creator>
      <pubDate>Thu, 04 Jan 2024 01:20:06 +0000</pubDate>
      <link>https://dev.to/k4ml/inline-script-defer-4dkf</link>
      <guid>https://dev.to/k4ml/inline-script-defer-4dkf</guid>
      <description>&lt;p&gt;Problem when using &lt;code&gt;defer&lt;/code&gt; to load external script is when you have inline script that depends on the external script. This because inline script is executed immediately while deferred script is loaded after the whole page has beed parsed.&lt;/p&gt;

&lt;p&gt;Take this script for example:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!doctype html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;script&amp;gt;
        console.log('Start ...');
    &amp;lt;/script&amp;gt;
    &amp;lt;script defer src="https://unpkg.com/htmx.org@1.9.10" integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC" crossorigin="anonymous"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script&amp;gt;
    htmx.logger = function(elt, event, data) {
    if(console) {
        console.log(event, elt, data);
        }
    }   
    &amp;lt;/script&amp;gt;
    &amp;lt;script&amp;gt;
        htmx.logger("Inside head");
    &amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Javascript DOMContentLoaded&amp;lt;/h1&amp;gt;
    &amp;lt;script type="module"&amp;gt;
        htmx.logger("Inside body");
    &amp;lt;/script&amp;gt;

    &amp;lt;script&amp;gt;
        window.addEventListener('DOMContentLoaded', function() {
            console.log('Inline JS');
        });
    &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The inline script will failed:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start ... localhost:9000:5:17
Uncaught ReferenceError: htmx is not defined
    &amp;lt;anonymous&amp;gt; http://localhost:9000/:9
localhost:9000:9:5
Uncaught ReferenceError: htmx is not defined
    &amp;lt;anonymous&amp;gt; http://localhost:9000/:16
localhost:9000:16:9
Uncaught TypeError: htmx.logger is not a function
    &amp;lt;anonymous&amp;gt; http://localhost:9000/:23
localhost:9000:23:14
Inline JS localhost:9000:28:21
GET
http://localhost:9000/favicon.ico
[HTTP/1 404 File not found 1ms]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fortunately script of type module is &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules"&gt;deferred automatically&lt;/a&gt;. This will work as expected:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!doctype html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;script&amp;gt;
        console.log('Start ...');
    &amp;lt;/script&amp;gt;
    &amp;lt;script defer src="https://unpkg.com/htmx.org@1.9.10" integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC" crossorigin="anonymous"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script type="module"&amp;gt;
    htmx.logger = function(elt, event, data) {
    if(console) {
        console.log(event, elt, data);
        }
    }   
    &amp;lt;/script&amp;gt;
    &amp;lt;script type="module"&amp;gt;
        htmx.logger("Inside head");
    &amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Javascript DOMContentLoaded&amp;lt;/h1&amp;gt;
    &amp;lt;script type="module"&amp;gt;
        htmx.logger("Inside body");
    &amp;lt;/script&amp;gt;

    &amp;lt;script&amp;gt;
        window.addEventListener('DOMContentLoaded', function() {
            console.log('Inline JS');
        });
    &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start ... localhost:9000:5:17
undefined Inside head undefined localhost:9000:11:17
undefined Inside body undefined localhost:9000:11:17
htmx:beforeProcessNode 
&amp;lt;body&amp;gt;

Object { elt: body }
localhost:9000:11:17
Inline JS localhost:9000:28:21
GET
http://localhost:9000/favicon.ico
[HTTP/1 404 File not found 1ms]

htmx:load 
&amp;lt;body&amp;gt;

Object { elt: body }
localhost:9000:11:17
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Browsers support is &lt;a href="https://caniuse.com/es6-module"&gt;96.81%&lt;/a&gt; so I think it's pretty good.&lt;/p&gt;

&lt;p&gt;Original code taken from &lt;a href="https://cylab.be/blog/188/defer-async-and-inline-javascript"&gt;https://cylab.be/blog/188/defer-async-and-inline-javascript&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>Chiselled Ubuntu containers GA</title>
      <dc:creator>Kamal Mustafa</dc:creator>
      <pubDate>Mon, 11 Dec 2023 23:52:04 +0000</pubDate>
      <link>https://dev.to/k4ml/chiselled-ubuntu-containers-ga-4a39</link>
      <guid>https://dev.to/k4ml/chiselled-ubuntu-containers-ga-4a39</guid>
      <description>&lt;p&gt;Smaller &lt;a href="https://canonical.com/blog/chiselled-ubuntu-ga"&gt;Ubuntu container images&lt;/a&gt;. But I think it still low level tools for building such images, unlike &lt;a href="https://github.com/GoogleContainerTools/distroless"&gt;distroless&lt;/a&gt; where you can use it right away.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>containers</category>
    </item>
    <item>
      <title>Isso comment system - alternative to disqus</title>
      <dc:creator>Kamal Mustafa</dc:creator>
      <pubDate>Wed, 02 Aug 2023 11:41:04 +0000</pubDate>
      <link>https://dev.to/k4ml/isso-comment-system-alternative-to-disqus-3h42</link>
      <guid>https://dev.to/k4ml/isso-comment-system-alternative-to-disqus-3h42</guid>
      <description>&lt;p&gt;It's a simple self hosted &lt;a href="https://isso-comments.de/"&gt;comment system&lt;/a&gt;, build in Python and just use sqlite database. By default it only support single website but with some configuration you can also use it for multiple websites.&lt;/p&gt;

&lt;p&gt;This post however, not much about Isso but how do I found it.&lt;/p&gt;

&lt;p&gt;I was reading Luke Plant's &lt;a href="https://lukeplant.me.uk/blog/posts/django-sass-scss-without-nodejs-or-build-step/"&gt;blog&lt;/a&gt; and then noticed his comment form a little bit, different.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0vfNY3Yo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m1hvhisti419dp7grte5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0vfNY3Yo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m1hvhisti419dp7grte5.png" alt="Image description" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It triggered the curiousity inside me so I "view source" it using the  browser Inspect function.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xLkjWjqd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0hbxezuox0elo1a68il5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xLkjWjqd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0hbxezuox0elo1a68il5.png" alt="Image description" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The word isso definitely stand out, so I googled it (isso comments). The rest is history.&lt;/p&gt;

</description>
      <category>python</category>
      <category>disqus</category>
    </item>
    <item>
      <title>Any estimates longer than 3 days tend to be wrong</title>
      <dc:creator>Kamal Mustafa</dc:creator>
      <pubDate>Tue, 16 May 2023 00:16:12 +0000</pubDate>
      <link>https://dev.to/k4ml/any-estimates-longer-than-3-days-tend-to-be-wrong-4ni4</link>
      <guid>https://dev.to/k4ml/any-estimates-longer-than-3-days-tend-to-be-wrong-4ni4</guid>
      <description>&lt;p&gt;So breakdown tasks so that each part can be finished within 3 days.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Break down tasks by 𝗱𝗲𝗰𝗼𝗺𝗽𝗼𝘀𝗶𝗻𝗴 𝗹𝗮𝗿𝗴𝗲 𝗰𝗼𝗺𝗽𝗹𝗲𝘅 𝘁𝗮𝘀𝗸𝘀 into smaller, more manageable ones. For example, we found that jobs estimated up to 3 days of work are accurate.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/posts/milanmilanovic_technology-softwareengineering-programming-activity-7063754883312549888-rEx_/"&gt;Dr. Milan Milanović&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Python virtualenv no activate</title>
      <dc:creator>Kamal Mustafa</dc:creator>
      <pubDate>Thu, 19 Jan 2023 06:08:28 +0000</pubDate>
      <link>https://dev.to/k4ml/python-virtualenv-no-activate-21ln</link>
      <guid>https://dev.to/k4ml/python-virtualenv-no-activate-21ln</guid>
      <description>&lt;p&gt;My workflow when starting new python project or experimenting with something:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir myproject
cd myproject
python -mvenv venv
venv/bin/pip install something
venv/bin/python
&amp;gt;&amp;gt;&amp;gt; import something
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look, there's no need to do something like &lt;code&gt;source venv/bin/activate&lt;/code&gt; to make use of your virtual environment.&lt;/p&gt;

&lt;p&gt;Not using &lt;code&gt;activate&lt;/code&gt; also good for documentation like in README as you don't have the two steps commands and people forgot to run the first step problem.&lt;/p&gt;

&lt;p&gt;Have ever got into situation where you have to ask, "Have you run &lt;code&gt;source venv/bin/activate&lt;/code&gt;?" You don't need to ask this question if you invoke the venv directly.&lt;/p&gt;

&lt;p&gt;Of course this is just for quick experimentation. For a real project we're using poetry. And here's &lt;a href="https://github.com/lalokalabs/labzero" rel="noopener noreferrer"&gt;labzero&lt;/a&gt; our starter project for django.&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>GNOME Asia Summit 2022</title>
      <dc:creator>Kamal Mustafa</dc:creator>
      <pubDate>Thu, 08 Dec 2022 04:17:35 +0000</pubDate>
      <link>https://dev.to/k4ml/gnome-asia-summit-2022-2k20</link>
      <guid>https://dev.to/k4ml/gnome-asia-summit-2022-2k20</guid>
      <description>&lt;p&gt;GNOME Asia Summit 2022 this year was held as physical event in Kuala Lumpur for the first time after 2 years of online conferences due to the COVID-19 pandemic.&lt;/p&gt;

&lt;p&gt;My talk proposal was accepted and I'm presenting the topic of Remote IDE for remote developer. Remote IDE has become my interests this year after fully adopting Github Codespaces and later on Gitpod in my development workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aPfhlwhS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dmoi8ppnyro3waq91fuc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aPfhlwhS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dmoi8ppnyro3waq91fuc.png" alt="Image description" width="880" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sJWEZk5H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x7kuas0346558z1vgnum.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sJWEZk5H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x7kuas0346558z1vgnum.png" alt="Image description" width="880" height="249"&gt;&lt;/a&gt;&lt;br&gt;
Aryan Kaushik shared his journey in Google Summer of Code (SoC) working  on GNOME app Pitivi, porting it from GTK3+ to GTK4.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--62CBoQpN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/csad1a22ilakjvf1o706.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--62CBoQpN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/csad1a22ilakjvf1o706.jpeg" alt="Image description" width="880" height="496"&gt;&lt;/a&gt;&lt;br&gt;
Rosanna Yuen from GNOME Foudation explaining Gnome community Code of Conduct.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BJykO_Zl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5e4gpvx05o2x007uej5u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BJykO_Zl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5e4gpvx05o2x007uej5u.jpg" alt="Image description" width="880" height="496"&gt;&lt;/a&gt;&lt;br&gt;
Adzmely Mansor from Nexoprima shared their experiences integrating critical care medical devices with modern system. I was looking forward for this talk as Adzmely is very well known in local development community. Last time listening to his presentation on linux vertical performance tuning really blew my mind.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lW9Lu3io--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/st2jwsdi63obfje8rull.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lW9Lu3io--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/st2jwsdi63obfje8rull.png" alt="Image description" width="880" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One interesting sharing from him is how they send data from endoscopy machine to the PACS (picture archiving and communication system) which is a medical imaging technology used in healthcare organizations to securely store and digitally transmit electronic images and clinically-relevant reports. The problem is the only way to get data from the machine is by plugging a USB thumbdrive. That make automation not possible. What they did is to plug in a raspberry PI instead which configured to emulate as USB mass storage. Then it just a matter of using inotify to detect writing to the file system and send the file to PACS.&lt;/p&gt;

&lt;p&gt;It's a weekend very well spent connecting with some old friends and also meeting new people during the event. This probably my last event for this year and hopefully next year we will have more physical conferences.&lt;/p&gt;

</description>
      <category>gnome</category>
      <category>remote</category>
      <category>ide</category>
      <category>linux</category>
    </item>
    <item>
      <title>Misc notes on Github Codespaces</title>
      <dc:creator>Kamal Mustafa</dc:creator>
      <pubDate>Sun, 26 Jun 2022 09:59:00 +0000</pubDate>
      <link>https://dev.to/k4ml/nix-on-github-codespaces-4m29</link>
      <guid>https://dev.to/k4ml/nix-on-github-codespaces-4m29</guid>
      <description>&lt;p&gt;Just some quick notes since I have spent few hours trying to get nix working on Codespaces and get our project running.&lt;/p&gt;

&lt;p&gt;I have shared my Dockerfile in this issue at Nix's Github - &lt;a href="https://github.com/NixOS/nix/issues/6680"&gt;https://github.com/NixOS/nix/issues/6680&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-compose&lt;/code&gt; is working fine. We can customize our workspace using Dockerfile. Have to use images provided by Github, using our own image doesn't work. I guess we have to do some more works as stated in this &lt;a href="https://dev.to/xpirit/customizing-codespaces-4mnl"&gt;post&lt;/a&gt; - have Dockerfile.base as well.&lt;/p&gt;

&lt;p&gt;Workspace is stopped after the idle timeout (30mins) but all our work on disk is preserved. So uncommitted changes is still there when we come back, just like working on local computer.&lt;/p&gt;

&lt;p&gt;Everytime we changed stuff in &lt;code&gt;.devcontainer&lt;/code&gt; we have to rebuild the container. For quickly testing your Dockerfile, it's better to just run &lt;code&gt;docker build&lt;/code&gt; in the terminal and if it build cleanly then we rebuild.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd .devcontainer
docker build .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A failure in rebuild will drop us into recovery container so we can fix our Dockerfile but tools are limited here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/microsoft/vscode-dev-containers/tree/main/containers/codespaces-linux/.devcontainer"&gt;https://github.com/microsoft/vscode-dev-containers/tree/main/containers/codespaces-linux/.devcontainer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Heroku cli login issue - &lt;a href="https://github.com/heroku/cli/issues/1914"&gt;https://github.com/heroku/cli/issues/1914&lt;/a&gt; - ip address mismatch. We have same issue when working with remote vm, a workaround is to tunnel http traffic from our browser to the vm, either with vpn or simply ssh tunnel (we use sshuttle).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Workaround 1 - define env var HEROKU_API_KEY - the downside is that your action would not be under your username but the username of that api key owner&lt;/li&gt;
&lt;li&gt;Workaround 2 - Copy the credentials from your local machine - it's stored in &lt;code&gt;$HOME/.netrc&lt;/code&gt; file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://devcenter.heroku.com/articles/authentication"&gt;https://devcenter.heroku.com/articles/authentication&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VSCode editor doesn't enable word wrap by default. Add this to devcontainer.json:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"editor.wordWrap": "wordWrapColumn",
"editor.wrappingIndent": "same",
"editor.wordWrapColumn": 80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List of limitations - &lt;a href="https://code.visualstudio.com/docs/remote/codespaces"&gt;https://code.visualstudio.com/docs/remote/codespaces&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nix</category>
      <category>docker</category>
      <category>github</category>
      <category>codespaces</category>
    </item>
    <item>
      <title>Django: _ (underscore) settings gotchas</title>
      <dc:creator>Kamal Mustafa</dc:creator>
      <pubDate>Tue, 27 Jul 2021 10:38:37 +0000</pubDate>
      <link>https://dev.to/k4ml/django--underscore-settings-gotchas-1ca8</link>
      <guid>https://dev.to/k4ml/django--underscore-settings-gotchas-1ca8</guid>
      <description>&lt;p&gt;It so happened that after we add some localization setup in our app, running our tests error out with:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ackages/django/conf/__init__.py", line 122, in configure
INTERNALERROR&amp;gt;     raise TypeError('Setting %r must be uppercase.' % name)
INTERNALERROR&amp;gt; TypeError: Setting '_' must be uppercase.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The settings in question that we have added is this:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;try:
    from django.utils.translation import gettext_lazy as _
except ImportError:
    _ = lambda s: s
...
...
LANGUAGES = [
    ("en", _("English")),
    ("ja", _("Japanese")),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This however only happened when we run tests, it didn't happened in normal django run. Adding some &lt;code&gt;breakpoint()&lt;/code&gt; in &lt;code&gt;configure()&lt;/code&gt; function proved that it never get called in normal django run (such as through &lt;code&gt;runserver&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;My initial gut feeling tell that this is a problem with pytest_djangoapp but after I did some digging, my thinking a bit skewed.&lt;/p&gt;

&lt;p&gt;Firstly I looked into the &lt;a href="https://github.com/django/django/commit/163236ea0e5df1a301371e79ec35fc67b7a1b7a6"&gt;commit&lt;/a&gt; that introduced this check (not allowed &lt;code&gt;_&lt;/code&gt; as settings attribute). You can find it using &lt;code&gt;blame&lt;/code&gt; on github.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vd2epsPj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bpqab1ie721i5ncw8mh9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vd2epsPj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bpqab1ie721i5ncw8mh9.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So it brought me to &lt;a href="https://code.djangoproject.com/ticket/30234"&gt;issue #30234&lt;/a&gt; on django project issue tracker. At this point I thought Django is at fault as the localization docs still showing example of using &lt;code&gt;_&lt;/code&gt; in settings.py. It doesn't make sense, if you already disallowed using &lt;code&gt;_&lt;/code&gt; in settings, why still show it in official docs?&lt;/p&gt;

&lt;p&gt;Fortunately some wise guy on the issue's comment replied to my comment that this has nothing to do with  Django or its docs. The problem is with pytest_djangoapp which called &lt;code&gt;settings.configure()&lt;/code&gt; and passing &lt;code&gt;_&lt;/code&gt; as part of the settings dict.&lt;/p&gt;

&lt;p&gt;I can't tell how embarrassed I am. I should have check pytest_djangoapp first before posting the comment in the issue tracker.&lt;/p&gt;

</description>
      <category>python</category>
      <category>django</category>
    </item>
  </channel>
</rss>
