From 8121177b144bb421bf36c251d3819301987a0890 Mon Sep 17 00:00:00 2001 From: "T. Franzel" Date: Mon, 1 Apr 2024 00:31:29 +0200 Subject: [PATCH] fix non-translated enum override hash #1198 --- drf_spectacular/plumbing.py | 7 ++++++- tests/conftest.py | 6 +++--- tests/locale/de/LC_MESSAGES/django.mo | Bin 803 -> 868 bytes tests/locale/de/LC_MESSAGES/django.po | 8 +++++++- tests/test_i18n.py | 18 ++++++++++++++++++ tests/test_i18n.yml | 11 +++++++++++ tests/test_postprocessing.py | 6 +++--- 7 files changed, 48 insertions(+), 8 deletions(-) diff --git a/drf_spectacular/plumbing.py b/drf_spectacular/plumbing.py index 2897ad21..07db4b15 100644 --- a/drf_spectacular/plumbing.py +++ b/drf_spectacular/plumbing.py @@ -38,6 +38,7 @@ ) from django.utils.functional import Promise, cached_property from django.utils.module_loading import import_string +from django.utils.translation import get_language from django.utils.translation import gettext_lazy as _ from rest_framework import exceptions, fields, mixins, serializers, versioning from rest_framework.compat import unicode_http_header @@ -859,8 +860,12 @@ def deep_import_string(string: str) -> Any: pass -@cache def load_enum_name_overrides(): + return _load_enum_name_overrides(get_language()) + + +@functools.lru_cache() +def _load_enum_name_overrides(language: str): overrides = {} for name, choices in spectacular_settings.ENUM_NAME_OVERRIDES.items(): if isinstance(choices, str): diff --git a/tests/conftest.py b/tests/conftest.py index 6218127c..0fa8463a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -179,11 +179,11 @@ def clear_generator_settings(): @pytest.fixture() def clear_caches(): - from drf_spectacular.plumbing import get_openapi_type_mapping, load_enum_name_overrides - load_enum_name_overrides.cache_clear() + from drf_spectacular.plumbing import _load_enum_name_overrides, get_openapi_type_mapping + _load_enum_name_overrides.cache_clear() get_openapi_type_mapping.cache_clear() yield - load_enum_name_overrides.cache_clear() + _load_enum_name_overrides.cache_clear() get_openapi_type_mapping.cache_clear() diff --git a/tests/locale/de/LC_MESSAGES/django.mo b/tests/locale/de/LC_MESSAGES/django.mo index 2089281f4632c6dcabaaf0f3c1d00fb9d788fd17..2937b76036a2540ae7b2b3becaefbfc397746e33 100644 GIT binary patch delta 270 zcmX|+&k6xi6o=0+1`Q>RjIyv$_DZ(?lnu|IrWv7>npjwQ2IL83XC-!C#73s%G2}Zb zzxw*_?cQ_lxd-cItsi-FFC-0R2p|h5&^)0I5hTGeMB=!N9bCZ$+`wAj$2mN~CA`9V zX9rdGm)Nh*9h)LUiC7dlcw;U2;2L&$#l|hH=L1X+Nq`QZ(SbA;(Ci=m3~eN}xi;<2 h)L;3tk#xOqYZT7L(a7|?Nf>&8w3mzd?iO=l`~@T~9?Ad! delta 203 zcmaFDwwSH{o)F7a1|VPuVi_O~0b*_-?g3&D*a5^wK)e%(MS%DX5Q_paBO^q;IFJ?q z@=buWB#?Fm(h5Kv55y`!eghK&gE)|03Zy~udx5k%kiHJ2f%cd&{D&&wW(FDxlmK!W lSb!J?*nkY66xe|vF;);U@vix11;(9>lm9V^PyWl44gj1x6jA^H diff --git a/tests/locale/de/LC_MESSAGES/django.po b/tests/locale/de/LC_MESSAGES/django.po index aa71356a..7d9ee72b 100644 --- a/tests/locale/de/LC_MESSAGES/django.po +++ b/tests/locale/de/LC_MESSAGES/django.po @@ -39,4 +39,10 @@ msgid "Internationalization" msgstr "Internätiönalisierung" msgid "Internationalizations" -msgstr "Internätiönalisierungen" \ No newline at end of file +msgstr "Internätiönalisierungen" + +msgid "Car" +msgstr "Auto" + +msgid "Bicycle" +msgstr "Fahrrad" \ No newline at end of file diff --git a/tests/test_i18n.py b/tests/test_i18n.py index 0864dd9c..15b771a1 100644 --- a/tests/test_i18n.py +++ b/tests/test_i18n.py @@ -14,9 +14,15 @@ from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView from tests import assert_schema, generate_schema +TRANSPORT_CHOICES = ( + ('car', _('Car')), + ('bicycle', _('Bicycle')), +) + class I18nModel(models.Model): field_str = models.TextField() + field_choice = models.CharField(max_length=10, choices=TRANSPORT_CHOICES) class Meta: verbose_name = _("Internationalization") @@ -90,3 +96,15 @@ def test_i18n_schema(no_warnings, url, header, translated): def test_i18n_schema_ui(no_warnings): response = APIClient().get('/api/schema/swagger-ui/?lang=de') assert b'/api/schema/?lang\\u003Dde' in response.content + + +@mock.patch('drf_spectacular.settings.spectacular_settings.ENUM_NAME_OVERRIDES', { + 'SpecialLanguageEnum': TRANSPORT_CHOICES +}) +@pytest.mark.urls(__name__) +def test_lazily_translated_enum_overrides(no_warnings, clear_caches): + schema_de = yaml.load(APIClient().get('/api/schema/?lang=de').content, Loader=yaml.SafeLoader) + schema_en = yaml.load(APIClient().get('/api/schema/').content, Loader=yaml.SafeLoader) + + assert 'SpecialLanguageEnum' in schema_de['components']['schemas'] + assert 'SpecialLanguageEnum' in schema_en['components']['schemas'] diff --git a/tests/test_i18n.yml b/tests/test_i18n.yml index 69396a4c..b5a8d022 100644 --- a/tests/test_i18n.yml +++ b/tests/test_i18n.yml @@ -123,6 +123,14 @@ paths: description: '' components: schemas: + FieldChoiceEnum: + enum: + - car + - bicycle + type: string + description: |- + * `car` - Auto + * `bicycle` - Fahrrad X: type: object properties: @@ -131,7 +139,10 @@ components: readOnly: true field_str: type: string + field_choice: + $ref: '#/components/schemas/FieldChoiceEnum' required: + - field_choice - field_str - id securitySchemes: diff --git a/tests/test_postprocessing.py b/tests/test_postprocessing.py index 1f08e06d..23a58290 100644 --- a/tests/test_postprocessing.py +++ b/tests/test_postprocessing.py @@ -15,7 +15,7 @@ TextChoices = object # type: ignore # django < 3.0 handling IntegerChoices = object # type: ignore # django < 3.0 handling -from drf_spectacular.plumbing import list_hash, load_enum_name_overrides +from drf_spectacular.plumbing import _load_enum_name_overrides, list_hash, load_enum_name_overrides from drf_spectacular.utils import OpenApiParameter, extend_schema from tests import assert_schema, generate_schema @@ -264,7 +264,7 @@ def test_enum_override_variations(no_warnings): 'drf_spectacular.settings.spectacular_settings.ENUM_NAME_OVERRIDES', {'LanguageEnum': f'tests.test_postprocessing.{variation}'} ): - load_enum_name_overrides.cache_clear() + _load_enum_name_overrides.cache_clear() assert list_hash(expected_hashed_keys) in load_enum_name_overrides() @@ -286,7 +286,7 @@ def test_enum_override_variations_with_blank_and_null(no_warnings): 'drf_spectacular.settings.spectacular_settings.ENUM_NAME_OVERRIDES', {'LanguageEnum': f'tests.test_postprocessing.{variation}'} ): - load_enum_name_overrides.cache_clear() + _load_enum_name_overrides.cache_clear() # Should match after None and blank strings are removed assert list_hash(expected_hashed_keys) in load_enum_name_overrides()