How to avoid flake8's "F821 undefined name '_'" when _ has been installed by gettext?

zezollo picture zezollo · Jun 15, 2016 · Viewed 10.9k times · Source

Problem overview:

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

As stated by the doc:

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

So, everything runs fine.

Only problem: flake8 shows errors (actually returned by PyFlakes):

$ flake8 *.py
lib.py:2:12: F821 undefined name '_'
main_script.py:8:7: F821 undefined name '_'

This is normal, as _ is indeed not defined in main_script.py nor lib.py.

Simple structure that reproduces the problem:

.
├── lib.py
├── locale
│   └── de
│       └── LC_MESSAGES
│           ├── myapp.mo
│           └── myapp.po
└── main_script.py

Where lib.py contains this:

def fct(sentence):
    return _(sentence)

and main_script.py this:

#!/usr/bin/env python3

import gettext

import lib

gettext.translation('myapp', 'locale', ['de']).install()
print(_('A sentence'))
print(lib.fct('A sentence'))

and myapp.po contains:

msgid ""
msgstr ""
"Project-Id-Version: myapp\n"

msgid "A sentence"
msgstr "Ein Satz"

(was compiled by poedit to produce the mo file).

As stated above, the main script does work:

$ ./main_script.py 
Ein Satz
Ein Satz

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

Solutions to solve the situation that look bad (or worse):

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

Answer

Anonymous picture Anonymous · Jun 15, 2016

You could specify the --builtins="_" which is more specific than --ignore F821.

You should be able to specify this in a configuration file as well if you don't like command line arguments.