Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gettext breaks pytest tests

I'm working on internationalizing a Python tool.

Following Python's docs, I initialize gettext at startup as such:

trans = gettext.translation(domain, 'locale', fallback=True)
trans.install('gettext')

And changed logging calls from:

logger.debug('message')

to:

logger.debug(gettext('message'))

The issue is as follows. Since my unit tests run against individual methods/functions, gettext hasn't been installed, and gettext() isn't available. We get an error like this:

>       logger.debug(gettext('message'))
E       NameError: name 'gettext' is not defined

How does one test code internationalized with Python's gettext module?

like image 292
Jones Avatar asked Sep 14 '26 19:09

Jones


1 Answers

You could write a custom fixture that will mimic the l10n installation in the test suite.

Example

I have tried to recreate your issue in a module named spam.py:

# spam.py
import logging


logging.basicConfig(level=logging.INFO)
LOGGER = logging.getLogger(__name__)


def eggs():
    LOGGER.info(gettext('message'))


if __name__ == '__main__':
    import gettext as g
    trans = g.translation('spam', 'locale', fallback=True)
    trans.install('gettext')

    eggs()

Running the program yields as expected:

$ python spam.py
INFO:__main__:message

Now here's a test for spam.eggs:

# test_spam.py

import spam

def test_eggs(caplog):
    spam.eggs()
    assert len(caplog.records) == 1

The test fails as expected:

$ pytest test_spam.py
================================ test session starts ==============================
platform darwin -- Python 3.6.3, pytest-3.3.1, py-1.5.2, pluggy-0.6.0
rootdir: /Users/hoefling/projects/private/stackoverflow/so-48195889, inifile:
plugins: forked-0.2, xdist-1.20.1, mock-1.6.3, hypothesis-3.44.4
collected 1 item

test_spam.py F                                                                                                                             [100%]

==================================== FAILURES =====================================
____________________________________ test_eggs ____________________________________

caplog = <_pytest.logging.LogCaptureFixture object at 0x1056ba0b8>

    def test_eggs(caplog):
>       spam.eggs()

test_spam.py:4:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

    def eggs():
>       LOGGER.info(gettext('message'))
E       NameError: name 'gettext' is not defined

spam.py:9: NameError
============================ 1 failed in 0.07 seconds =============================

Solution

In the root dir, create a conftest.py. In there, implement a fixture that will automatically run once when a test session starts:

# conftest.py

import pytest

@pytest.fixture(scope='session', autouse=True)
def install_l10n():
    import gettext as g
    trans = g.translation('spam', 'locale', fallback=True)
    trans.install('gettext')

The test will pass now:

$ pytest test_spam.py
================================ test session starts ==============================
platform darwin -- Python 3.6.3, pytest-3.3.1, py-1.5.2, pluggy-0.6.0
rootdir: /Users/hoefling/projects/private/stackoverflow/so-48195889, inifile:
plugins: forked-0.2, xdist-1.20.1, mock-1.6.3, hypothesis-3.44.4
collected 1 item

test_spam.py .                                                                                                                             [100%]

============================ 1 passed in 0.01 seconds =============================
like image 174
hoefling Avatar answered Sep 17 '26 07:09

hoefling