File tree Expand file tree Collapse file tree
couchers/migrations/versions Expand file tree Collapse file tree Original file line number Diff line number Diff line change 11[
2- {
3- "code" : " _tw" ,
4- "name" : " Taiwanese"
5- },
62 {
73 "code" : " aao" ,
84 "name" : " Arabic (Algerian)"
5551 "code" : " afr" ,
5652 "name" : " Afrikaans"
5753 },
58- {
59- "code" : " ajp" ,
60- "name" : " Arabic (Levantine South)"
61- },
6254 {
6355 "code" : " aka" ,
6456 "name" : " Akan"
947939 "code" : " slv" ,
948940 "name" : " Slovenian"
949941 },
950- {
951- "code" : " smi" ,
952- "name" : " Sámi"
953- },
954942 {
955943 "code" : " smo" ,
956944 "name" : " Samoan"
Original file line number Diff line number Diff line change 1+ """Fix invalid/deprecated ISO 639-3 language codes
2+
3+ Revision ID: 0170
4+ Revises: 0169
5+ Create Date: 2026-06-29 00:00:00.000000
6+
7+ """
8+
9+ from alembic import op
10+ from sqlalchemy .orm .session import Session
11+
12+ from couchers .resources import copy_resources_to_database
13+
14+ # revision identifiers, used by Alembic.
15+ revision = "0170"
16+ down_revision = "0169"
17+ branch_labels = None
18+ depends_on = None
19+
20+
21+ def upgrade () -> None :
22+ session = Session (bind = op .get_bind ())
23+ # Reload languages table (removes _tw, ajp, smi from the static table)
24+ copy_resources_to_database (session )
25+ # _tw ("Taiwanese") is an invented code; official equivalent is nan ("Chinese (Southern Min)")
26+ # Dedupe first: drop _tw for users who already have nan
27+ op .execute (
28+ "DELETE FROM language_abilities WHERE language_code='_tw' AND user_id IN "
29+ "(SELECT user_id FROM language_abilities WHERE language_code='nan');"
30+ )
31+ op .execute ("UPDATE language_abilities SET language_code='nan' WHERE language_code='_tw';" )
32+ # ajp ("Arabic (Levantine South)") is deprecated; ISO merged it into apc ("Arabic (Levantine North)")
33+ # Dedupe first: drop ajp for users who already have apc
34+ op .execute (
35+ "DELETE FROM language_abilities WHERE language_code='ajp' AND user_id IN "
36+ "(SELECT user_id FROM language_abilities WHERE language_code='apc');"
37+ )
38+ op .execute ("UPDATE language_abilities SET language_code='apc' WHERE language_code='ajp';" )
39+ # smi ("Sámi") is an ISO 639-2 group code with no individual equivalent; drop it
40+ op .execute ("DELETE FROM language_abilities WHERE language_code='smi';" )
41+ session .commit ()
42+
43+
44+ def downgrade () -> None :
45+ pass
Original file line number Diff line number Diff line change 11import pytest
22from google .protobuf import empty_pb2
3+ from sqlalchemy import select
34
5+ from couchers .db import session_scope
6+ from couchers .models import Language
7+ from couchers .resources import copy_resources_to_database
48from tests .fixtures .sessions import resources_session
59
610
@@ -57,6 +61,21 @@ def test_GetLanguages(db):
5761 assert ("swe" , "Swedish" ) not in languages_list
5862
5963
64+ def test_languages_resource_excludes_invalid_codes (db ):
65+ # Load the real languages.json (not the hardcoded testing fixture) so a future bad code is caught.
66+ # Mirrors test_add_dummy_data's pattern of calling copy_resources_to_database directly.
67+ with session_scope () as session :
68+ copy_resources_to_database (session )
69+ codes = set (session .execute (select (Language .code )).scalars ().all ())
70+ # Codes removed in #9172: invalid/deprecated ISO 639-3 entries
71+ assert "_tw" not in codes # invented code; use nan (Chinese Southern Min) instead
72+ assert "ajp" not in codes # deprecated; ISO merged into apc (Arabic Levantine North)
73+ assert "smi" not in codes # ISO 639-2 group code with no individual equivalent
74+ # Remap targets must remain present
75+ assert "nan" in codes
76+ assert "apc" in codes
77+
78+
6079def test_GetBadges (db ):
6180 with resources_session () as api :
6281 badges = api .GetBadges (empty_pb2 .Empty ()).badges
You can’t perform that action at this time.
0 commit comments