How to avoid flake8's "F821 undefined name '_'" when _ has been installed by gettext? : <h2>Problem overview:</h2>

<p>In my project's main script, <code>gettext</code> installs the function <code>_()</code> that is used in other modules for translations (like in <code>print(_('Something to translate'))</code>).</p>

<p>As stated by <a href="https://docs.python.org/3/library/gettext.html#gettext.install" rel="noreferrer">the doc</a>:</p>

<blockquote>
  <p>the _() function [is] installed in Python’s builtins namespace, so it is easily accessible in all modules of your application.</p>
</blockquote>

<p>So, everything runs fine.</p>

<p><em>Only problem</em>: <code>flake8</code> shows errors (actually returned by PyFlakes):</p>

<pre><code>$ flake8 *.py
lib.py:2:12: F821 undefined name '_'
main_script.py:8:7: F821 undefined name '_'
</code></pre>

<p>This is normal, as <code>_</code> is indeed not defined in main_script.py nor lib.py.</p>

<h2>Simple structure that reproduces the problem:</h2>

<pre><code>.
├── lib.py
├── locale
│   └── de
│       └── LC_MESSAGES
│           ├── myapp.mo
│           └── myapp.po
└── main_script.py
</code></pre>

<p>Where lib.py contains this:</p>

<pre><code>def fct(sentence):
    return _(sentence)
</code></pre>

<p>and main_script.py this:</p>

<pre><code>#!/usr/bin/env python3

import gettext

import lib

gettext.translation('myapp', 'locale', ['de']).install()
print(_('A sentence'))
print(lib.fct('A sentence'))
</code></pre>

<p>and myapp.po contains:</p>

<pre><code>msgid ""
msgstr ""
"Project-Id-Version: myapp\n"

msgid "A sentence"
msgstr "Ein Satz"
</code></pre>

<p>(was compiled by poedit to produce the mo file).</p>

<p>As stated above, the main script does work:</p>

<pre><code>$ ./main_script.py 
Ein Satz
Ein Satz
</code></pre>

<p><strong>Important note: I'm looking for a solution working both for the script where <code>gettext.install()</code> is called <em>and</em> all other modules that <em>do not need to call</em> <code>gettext.install()</code>.</strong> Otherwise, the structure could be even more simple, because calling <code>_()</code> from main_script.py is enough to trigger F821.</p>

<h2>Solutions to solve the situation that look bad (or worse):</h2>

<ul>
<li>add a <code># noqa</code> comment at the end of each line using <code>_()</code></li>
<li><code>--ignore</code> F821 (don't want to do that because this is useful in other situations)</li>
</ul>
