When Django's DecimalField quantize Fails on Alpine Linux

Django
2019-06-22 22:07 (5 years ago) ytyng

Failed to run tests for Django Cartridge in an Alpine Docker environment

  File "/var/src/venv/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 958, in prepare_value
value = field.get_db_prep_save(value, connection=self.connection)
File "/var/src/venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 1612, in get_db_prep_save
self.max_digits, self.decimal_places)
File "/var/src/venv/lib/python3.6/site-packages/django/db/backends/base/operations.py", line 493, in adapt_decimalfield_value
return utils.format_number(value, max_digits, decimal_places)
File "/var/src/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 200, in format_number
value = value.quantize(decimal.Decimal(".1") ** decimal_places, context=context)
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
InvalidOperation: [<class 'decimal.InvalidOperation'>]


was encountered.

Upon investigation, it was found that

decimal_places was set to 127.

(In another test environment, it was set to 0, and the tests passed)

decimal_places is determined by

./manage.py shell

from locale import localeconv; localeconv()
{'currency_symbol': '¥',
'decimal_point': '.',
'frac_digits': 0,
'grouping': [],
'int_curr_symbol': 'JPY ',
'int_frac_digits': 0,
'mon_decimal_point': '.',
'mon_grouping': [3, 3, 0],
'mon_thousands_sep': ',',
'n_cs_precedes': 1,
'n_sep_by_space': 0,
'n_sign_posn': 4,
'negative_sign': '-',
'p_cs_precedes': 1,
'p_sep_by_space': 0,
'p_sign_posn': 1,
'positive_sign': '',
'thousands_sep': ''}

This uses the frac_digits value.

In the environment where the test fails:

 {'currency_symbol': '',
'decimal_point': '.',
'frac_digits': 127,
'grouping': [],
'int_curr_symbol': '',
'int_frac_digits': 127,
'mon_decimal_point': '',
'mon_grouping': [],
'mon_thousands_sep': '',
'n_cs_precedes': 127,
'n_sep_by_space': 127,
'n_sign_posn': 127,
'negative_sign': '',
'p_cs_precedes': 127,
'p_sep_by_space': 127,
'p_sign_posn': 127,
'positive_sign': '',
'thousands_sep': ''}


The locale settings seem to be insufficient.



I tried to create the musl-locales by writing the Dockerfile as follows:

ENV MUSL_LOCPATH="/usr/share/i18n/locales/musl"

RUN apk --no-cache add libintl && \
apk --no-cache --virtual .locale_build add cmake make musl-dev gcc gettext-dev git && \
git clone https://gitlab.com/ytyng/musl-locales && \
cd musl-locales && cmake -DLOCALE_PROFILE=OFF -DCMAKE_INSTALL_PREFIX:PATH=/usr . && make && make install && \
cd .. && rm -r musl-locales && \
apk del .locale_build


However, the int_frac_digits value did not change.

Since I couldn't figure out another way, I patched
the locale settings in Django as follows:

setattr(locale, '_override_localeconv',
{'currency_symbol': '¥',
'decimal_point': '.',
'frac_digits': 0,
'grouping': [],
'int_curr_symbol': 'JPY ',
'int_frac_digits': 0,
'mon_decimal_point': '.',
'mon_grouping': [3, 3, 0],
'mon_thousands_sep': ',',
'n_cs_precedes': 1,
'n_sep_by_space': 0,
'n_sign_posn': 4,
'negative_sign': '-',
'p_cs_precedes': 1,
'p_sep_by_space': 0,
'p_sign_posn': 1,
'positive_sign': '',
'thousands_sep': ''})


By patching locale._override_localeconv in this way, the tests passed successfully.

In environments dealing with locales, it might be better to use Debian or similar instead of Alpine Linux.

Currently unrated

Comments

Archive

2024
2023
2022
2021
2020
2019
2018
2017
2016
2015
2014
2013
2012
2011