diff --git a/normalization/languages/french/number_normalizer.py b/normalization/languages/french/number_normalizer.py new file mode 100644 index 0000000..af840b8 --- /dev/null +++ b/normalization/languages/french/number_normalizer.py @@ -0,0 +1,72 @@ +"""French number normalizer using text2num's alpha2digit. + +Converts spelled-out numbers to digits (e.g. vingt trois → 23) and handles +mixed digit+word forms (e.g. 3 milliards → trois milliards) before conversion +so alpha2digit does not misinterpret them. +""" + +import re + +try: + from text_to_num import alpha2digit +except ImportError: + alpha2digit = None + + +# Digit-to-French word mapping for normalizing "3 milliards" → "trois milliards". +_DIGIT_TO_FRENCH: dict[str, str] = { + "0": "zéro", + "1": "un", + "2": "deux", + "3": "trois", + "4": "quatre", + "5": "cinq", + "6": "six", + "7": "sept", + "8": "huit", + "9": "neuf", +} + +# Pattern: digit(s) followed by millions/milliards (French) or billions/trillions. +_RE_MIXED_NUMBER = re.compile( + r"\b(\d+)\s+(millions?|milliards?|billions?|trillions?)\b", + re.IGNORECASE, +) + + +def _normalize_mixed_numbers(text: str) -> str: + """Convert '3 milliards' → 'trois milliards' so alpha2digit yields 3e9, not 31e9. + + alpha2digit may concatenate a lone digit with the following word; converting + the digit to a word avoids that (e.g. 'trois milliards' → 3000000000). + """ + + def replace(match: re.Match) -> str: + number = match.group(1) + multiplier = match.group(2) + if len(number) == 1 and number in _DIGIT_TO_FRENCH: + return f"{_DIGIT_TO_FRENCH[number]} {multiplier}" + # Multi-digit: keep as-is; alpha2digit will handle or leave unchanged + return match.group(0) + + return _RE_MIXED_NUMBER.sub(replace, text) + + +class FrenchNumberNormalizer: + """Convert French spelled-out numbers to digits via text2num.alpha2digit. + + Applies a pre-pass to normalize mixed digit+word forms (e.g. 3 milliards) + before calling alpha2digit. + """ + + def __init__(self) -> None: + if alpha2digit is None: + raise ImportError( + "French number normalization requires the text2num package. " + "Install it with: uv add text2num" + ) + self._alpha2digit = alpha2digit + + def __call__(self, text: str) -> str: + text = _normalize_mixed_numbers(text) + return self._alpha2digit(text, "fr") diff --git a/normalization/languages/french/operators.py b/normalization/languages/french/operators.py index 8cee281..face0d1 100644 --- a/normalization/languages/french/operators.py +++ b/normalization/languages/french/operators.py @@ -1,9 +1,30 @@ +import re + from normalization.languages.base import ( LanguageConfig, LanguageOperators, ) +from normalization.languages.french.number_normalizer import FrenchNumberNormalizer +from normalization.languages.french.replacements import FRENCH_REPLACEMENTS +from normalization.languages.french.sentence_replacements import ( + FRENCH_SENTENCE_REPLACEMENTS, +) from normalization.languages.registry import register_language +# French digit words (0-9) for steps that need digit-word recognition. +_FRENCH_DIGIT_WORDS: dict[str, str] = { + "zéro": "0", + "un": "1", + "deux": "2", + "trois": "3", + "quatre": "4", + "cinq": "5", + "six": "6", + "sept": "7", + "huit": "8", + "neuf": "9", +} + FRENCH_CONFIG = LanguageConfig( code="fr", decimal_separator=",", @@ -29,10 +50,89 @@ "¥": "yens", }, filler_words=["euh", "hum", "beh", "bah", "ben", "hein"], + digit_words=_FRENCH_DIGIT_WORDS, + sentence_replacements=FRENCH_SENTENCE_REPLACEMENTS, + number_words=[ + "zéro", + "un", + "deux", + "trois", + "quatre", + "cinq", + "six", + "sept", + "huit", + "neuf", + "dix", + "onze", + "douze", + "treize", + "quatorze", + "quinze", + "seize", + "vingt", + "trente", + "quarante", + "cinquante", + "soixante", + "septante", + "octante", + "huitante", + "nonante", + "cent", + "mille", + "million", + "millions", + "milliard", + "milliards", + "billion", + "billions", + "trillion", + "trillions", + ], + plus_word="plus", ) @register_language class FrenchOperators(LanguageOperators): - def __init__(self): + """French language operators: contractions, written numbers, word replacements.""" + + def __init__(self) -> None: super().__init__(FRENCH_CONFIG) + self._number_normalizer = FrenchNumberNormalizer() + + def expand_contractions(self, text: str) -> str: + """Expand French informal spoken contractions before consonants only. + + French elision (apostrophe before a vowel or h) is the standard written form and + must be preserved: j'ai, c'est, l'ami, d'accord stay as-is because expanding them + would produce adjacent vowels that are incorrect in written French. + + Only expand when the apostrophe is followed by a consonant — those are informal + spoken reductions (j'veux → je veux, j'suis → je suis, s'pas → se pas). + """ + # Vowels + h: elision before these is standard written French — do not expand. + vowels = "aàâeéèêiîïoôuùûyh" + _V = rf"(?![{vowels}{vowels.upper()}])" + text = re.sub(rf"\bj'{_V}", "je ", text, flags=re.IGNORECASE) + text = re.sub(rf"\bc'{_V}", "ce ", text, flags=re.IGNORECASE) + text = re.sub(rf"\bd'{_V}", "de ", text, flags=re.IGNORECASE) + text = re.sub(rf"\bqu'{_V}", "que ", text, flags=re.IGNORECASE) + text = re.sub(rf"\bn'{_V}", "ne ", text, flags=re.IGNORECASE) + text = re.sub(rf"\bs'{_V}", "se ", text, flags=re.IGNORECASE) + text = re.sub(rf"\bm'{_V}", "me ", text, flags=re.IGNORECASE) + text = re.sub(rf"\bt'{_V}", "te ", text, flags=re.IGNORECASE) + text = re.sub(rf"\bl'{_V}", "le ", text, flags=re.IGNORECASE) + return text + + def expand_written_numbers(self, text: str) -> str: + """Convert French spelled-out numbers to digits (vingt trois → 23). + + Uses FrenchNumberNormalizer, which normalizes mixed forms (3 milliards → trois milliards) + then text2num.alpha2digit. + """ + return self._number_normalizer(text) + + def get_word_replacements(self) -> dict[str, str]: + return FRENCH_REPLACEMENTS diff --git a/normalization/languages/french/replacements.py b/normalization/languages/french/replacements.py index 704d68a..4d8f8c8 100644 --- a/normalization/languages/french/replacements.py +++ b/normalization/languages/french/replacements.py @@ -1 +1,28 @@ -FRENCH_REPLACEMENTS: dict[str, str] = {} +FRENCH_REPLACEMENTS = { + # contractions in titles/prefixes + "mme": "madame", + "mlle": "mademoiselle", + "mr": "monsieur", + "st": "saint", + "dr": "docteur", + "prof": "professeur", + "pr": "professeur", + # sports + "volley-ball": "volleyball", + "basket-ball": "basketball", + "water-polo": "waterpolo", + "ping-pong": "pingpong", + "hand-ball": "handball", + # Tech / quotidien + "wi-fi": "wifi", + "cd-rom": "cdrom", + "t-shirt": "tshirt", + "chat-bot": "chatbot", + "blogue": "blog", + "e-mail": "email", + "week-end": "weekend", + "week-ends": "weekends", + "porte-monnaie": "portemonnaie", + "porte-feuille": "portefeuille", + "extra-terrestre": "extraterrestre", +} diff --git a/normalization/languages/french/sentence_replacements.py b/normalization/languages/french/sentence_replacements.py new file mode 100644 index 0000000..71a3168 --- /dev/null +++ b/normalization/languages/french/sentence_replacements.py @@ -0,0 +1,13 @@ +FRENCH_SENTENCE_REPLACEMENTS: dict[str, str] = { + "super predateur": "superprédateur", + "ping pong": "pingpong", + "hand ball": "handball", + "water polo": "waterpolo", + "basket ball": "basketball", + "volley ball": "volleyball", + "wi fi": "wifi", + "cd rom": "cdrom", + "t shirt": "tshirt", + "pour 100": "pourcent", + "pour cent": "pourcent", +} diff --git a/pyproject.toml b/pyproject.toml index 9050466..fcae854 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,14 @@ classifiers = [ ] license = { file = "LICENSE" } requires-python = ">=3.10" -dependencies = ["contractions>=0.1.73", "pyyaml>=6.0.3"] +dependencies = [ + "contractions>=0.1.73", + "pyyaml>=6.0.3", + "text2num>=3.0.0", +] + +[tool.setuptools.package-data] +normalization = ["presets/*.yaml"] [project.urls] Homepage = "https://github.com/gladiaio/normalization" diff --git a/tests/e2e/files/gladia-3.csv b/tests/e2e/files/gladia-3.csv index 85c749b..b0b689b 100644 --- a/tests/e2e/files/gladia-3.csv +++ b/tests/e2e/files/gladia-3.csv @@ -123,4 +123,57 @@ x = 5,x equals 5,en ¥1000,1000 yens,en ø in Danish,o in danish,en €20 or €30,20 euros or 30 euros,en -my name is bob,my name is bob,en \ No newline at end of file +my name is bob,my name is bob,en +j'ai dit c'est bien,j ai dit c est bien,fr +vingt trois pommes,23 pommes,fr +3 milliards d euros,3000000000 d euros,fr +euh alors hein bah oui,alors oui,fr +"12,5 degrés",12 virgule 5 degres,fr +pour 100 de réduction,pourcent de reduction,fr +pour cent de réduction,pourcent de reduction,fr +"Hello, world!",hello world,default +ça va?!,ca va,default +$100,$100,default +80 €,80 €,default +test@example.com,test@example.com,default ++1234567890,+1234567890,default +one two three,one two three,default +5:30 pm,5:30 pm,default +d'accord,d accord,fr +qu'il vient,qu il vient,fr +n'est pas,n est pas,fr +l'ordinateur,l ordinateur,fr +m'appelle,m appelle,fr +s'il vous plait,s il vous plait,fr +t'as vu,t as vu,fr +cent euros,100 euros,fr +mille deux cents,1200,fr +cinquante trois,53,fr +contact@exemple.fr,contact arobase exemple point fr,fr +"2 < 5",2 plus petit que 5,fr +50°C,50 degres celsius,fr +ca coute €50,ca coute 50 euros,fr +euh bonjour hein,bonjour,fr +mme dupont,madame dupont,fr +mlle dubois,mademoiselle dubois,fr +dr martin,docteur martin,fr +prof dupont,professeur dupont,fr +st jean,saint jean,fr +ping pong,pingpong,fr +volley ball,volleyball,fr +basket ball,basketball,fr +hand ball,handball,fr +water polo,waterpolo,fr +t shirt,tshirt,fr +cd rom,cdrom,fr +super predateur,superpredateur,fr +"3,14 pi",3 virgule 14 pi,fr +soixante-dix,70,fr +quatre-vingts,80,fr +quatre-vingt-un,81,fr +nonante-neuf,99,fr +septante et un,71,fr +x = 5,x egal a 5,fr +test@example.com,test arobase example point com,fr +bonjour (euh) ami,bonjour ami,fr +ça date d'hier,ca date d hier,fr \ No newline at end of file diff --git a/tests/unit/steps/text/apply_sentence_level_replacements_test.py b/tests/unit/steps/text/apply_sentence_level_replacements_test.py new file mode 100644 index 0000000..306541c --- /dev/null +++ b/tests/unit/steps/text/apply_sentence_level_replacements_test.py @@ -0,0 +1,18 @@ +from normalization.languages.french import FrenchOperators +from normalization.steps.text.apply_sentence_level_replacements import ( + ApplySentenceLevelReplacementsStep, +) + +from .conftest import assert_text_step_registered + + +def test_step_is_registered(): + assert_text_step_registered(ApplySentenceLevelReplacementsStep) + + +def test_apply_sentence_level_replacements_step_french_pour_100( + french_operators: FrenchOperators, +): + text = "pour 100 de réduction" + formatted_text = ApplySentenceLevelReplacementsStep()(text, french_operators) + assert formatted_text == "pourcent de réduction" diff --git a/tests/unit/steps/text/conftest.py b/tests/unit/steps/text/conftest.py index 89361c6..81c4f15 100644 --- a/tests/unit/steps/text/conftest.py +++ b/tests/unit/steps/text/conftest.py @@ -2,6 +2,7 @@ from normalization.languages.base import LanguageOperators from normalization.languages.english import EnglishOperators +from normalization.languages.french import FrenchOperators from normalization.steps import get_step_registry @@ -15,6 +16,11 @@ def english_operators(): return EnglishOperators() +@pytest.fixture +def french_operators(): + return FrenchOperators() + + def assert_text_step_registered(step_cls): """Verify a text step is properly registered under its name.""" registry = get_step_registry() diff --git a/tests/unit/steps/text/expand_contractions_test.py b/tests/unit/steps/text/expand_contractions_test.py new file mode 100644 index 0000000..ce90c76 --- /dev/null +++ b/tests/unit/steps/text/expand_contractions_test.py @@ -0,0 +1,21 @@ +from normalization.languages.english import EnglishOperators +from normalization.languages.french import FrenchOperators +from normalization.steps.text.expand_contractions import ExpandContractionsStep + +from .conftest import assert_text_step_registered + + +def test_step_is_registered(): + assert_text_step_registered(ExpandContractionsStep) + + +def test_expand_contractions_step_english(english_operators: EnglishOperators): + text = "he ain't gonna" + formatted_text = ExpandContractionsStep()(text, english_operators) + assert formatted_text == "he is not going to" + + +def test_expand_contractions_step_french(french_operators: FrenchOperators): + text = "j'ai dit c'est bien" + formatted_text = ExpandContractionsStep()(text, french_operators) + assert formatted_text == "j'ai dit c'est bien" diff --git a/uv.lock b/uv.lock index a1dfc63..7f8141e 100644 --- a/uv.lock +++ b/uv.lock @@ -77,6 +77,7 @@ source = { editable = "." } dependencies = [ { name = "contractions" }, { name = "pyyaml" }, + { name = "text2num" }, ] [package.dev-dependencies] @@ -91,6 +92,7 @@ dev = [ requires-dist = [ { name = "contractions", specifier = ">=0.1.73" }, { name = "pyyaml", specifier = ">=6.0.3" }, + { name = "text2num", specifier = ">=3.0.0" }, ] [package.metadata.requires-dev] @@ -320,6 +322,100 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6d/78/097c0798b1dab9f8affe73da9642bb4500e098cb27fd8dc9724816ac747b/ruff-0.15.2-py3-none-win_arm64.whl", hash = "sha256:cabddc5822acdc8f7b5527b36ceac55cc51eec7b1946e60181de8fe83ca8876e", size = 10941649, upload-time = "2026-02-19T22:32:18.108Z" }, ] +[[package]] +name = "text2num" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/ec/d7e5d70049df4ab438de4d2126b8c80e216e70afd79835f8432c531e2d5d/text2num-3.0.1.tar.gz", hash = "sha256:3342ef371abcffc795785197168b40404b721bfabaa34b97fc8395eaa198c68e", size = 17449, upload-time = "2026-03-09T11:09:24.725Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b2/a0/a495e489e943de342b6f25f223558bfdca6c25c4b35202e39b44bf236479/text2num-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a176879dc950ff88097cfa7ff6f3e218dbdba8e3bac69d02fd140b21529addb", size = 391951, upload-time = "2026-03-09T11:07:09.701Z" }, + { url = "https://files.pythonhosted.org/packages/c1/0f/3558e58041916c1e9dc95e938640cf1767d30fa7f51ec2c9ee344beacef4/text2num-3.0.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60a4da11b74365c701b2fb3118ef15eef513b756ad61d6904d2700477debccff", size = 400644, upload-time = "2026-03-09T11:07:24.644Z" }, + { url = "https://files.pythonhosted.org/packages/ec/7c/33031d0f1d7e70416f3a237944200d256e989085cfea3c392848fb658b74/text2num-3.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:291c8ef4375ca28cc95b92c8aee02e7f9b09e838ffdc0cb8d3c4c86bf8006036", size = 510046, upload-time = "2026-03-09T11:07:36.534Z" }, + { url = "https://files.pythonhosted.org/packages/90/08/dc603a176b57769f3ec63c9d1390fe178aff0dbf82357d646253e54cc6ec/text2num-3.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b9e2e5e9e50b107486069f1ad089b518d39fd9b16c90a26f434ad19128cae9a", size = 418148, upload-time = "2026-03-09T11:07:49.135Z" }, + { url = "https://files.pythonhosted.org/packages/e7/e5/db9755ba9c94c36e99cd5ea37c26f0066aa11ef5ff7eed608f6bd49a1e2a/text2num-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad0fffebd174e90f2fa7ed0ef7974db45e7fd2099dcab7f8d29278fef57c4fc7", size = 391566, upload-time = "2026-03-09T11:08:11.921Z" }, + { url = "https://files.pythonhosted.org/packages/11/85/cf285b1e5b35da2185e763458e6d95757088d0a09ad5fd89bed098317de5/text2num-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1e9a2a1724560c854fb94dbfd25c4f3833c0c80f943f8f8c6aa343fff200f07d", size = 421018, upload-time = "2026-03-09T11:08:02.506Z" }, + { url = "https://files.pythonhosted.org/packages/63/29/6428ffdae7eb6a04951b8f1672d256f3622c13cfd2cd7bc2131029cb410b/text2num-3.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a754b4543e180fc1296fc57103335621cc354953bed57fd9e8b9573b72f96429", size = 567117, upload-time = "2026-03-09T11:08:29.584Z" }, + { url = "https://files.pythonhosted.org/packages/ce/87/e233b4db24a6875dd1f5fa80ceb655a6f295b20fb96a5c9ac75ea6cdd526/text2num-3.0.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:291b7ab8a5315d60105bf5d8b8d4a69fb6344e1b6e5189fe31a18cf302174f23", size = 675548, upload-time = "2026-03-09T11:08:43.717Z" }, + { url = "https://files.pythonhosted.org/packages/55/3f/0812e94384c3ef5dcab3b6ac031c5827df64691925da4948aa6987dba43d/text2num-3.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b7042378f19006f39d1ef12e8bde6ed8fc198193f9066d1c877853c5dfbc7239", size = 635948, upload-time = "2026-03-09T11:08:56.4Z" }, + { url = "https://files.pythonhosted.org/packages/f4/2e/c89eff26886346b03bca23a58b694a3a7e91e58c2b4c186e95fbdda3192e/text2num-3.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15816ba6c866ad300a5c0c0c294c5a09162767e8b4cb66e64c02fe2c7705d35c", size = 599960, upload-time = "2026-03-09T11:09:11.343Z" }, + { url = "https://files.pythonhosted.org/packages/bf/66/e5db28604d91f921f61991bee5206ed426f497a89df701f410928ae5c061/text2num-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:ae542dcd8ee276e596be784389bf311eaab3d4ab22f2c4ba9e5b4fbe0e785f0f", size = 233126, upload-time = "2026-03-09T11:09:25.417Z" }, + { url = "https://files.pythonhosted.org/packages/81/d0/cda19117cb0f1b2c17cc34f3cfd986750e86cf35a998ec03dda3afa0afe3/text2num-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:780e0f6c5a748da3ffa0701dda273c19653cc78fb45495e358ece3c2c6ada02f", size = 350346, upload-time = "2026-03-09T11:08:24.654Z" }, + { url = "https://files.pythonhosted.org/packages/f9/9b/8ec7a13932eea20da93276f920cba9b1aedfa851772f2dac680a5de9d023/text2num-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3753f1a8fc015655fac5a0d612d92c9614547540c789e5e114edf3fe77caf5e7", size = 391885, upload-time = "2026-03-09T11:07:11.348Z" }, + { url = "https://files.pythonhosted.org/packages/e1/ba/e904f61834c0e89e9b899e1c1c2b86d7b3ae098be839864e611fce42d90d/text2num-3.0.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:047443dbde4ba8eebe9fafb67c2359e5b19d3e044bfeaa8e62cc7f5ee9d603bd", size = 400666, upload-time = "2026-03-09T11:07:25.736Z" }, + { url = "https://files.pythonhosted.org/packages/08/3c/e38db3b03f7069866cb0150908c2e166074729ef16bdbb36e5ce63bb9c8c/text2num-3.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94ae9c05f9343ccfa4f4eb4ffe918e8513a702d00086c53e582cc5f321588d06", size = 510353, upload-time = "2026-03-09T11:07:37.92Z" }, + { url = "https://files.pythonhosted.org/packages/9c/ff/312d15fc11aa1f4334706cf1bb0cdecd52eeb7d601eabeee0e0ea6b8ae8c/text2num-3.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15ac7705f7172903d51465295b3d843270411420824916c0314eb6f5fee63364", size = 418053, upload-time = "2026-03-09T11:07:50.205Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a4/7f5aa18f2315b059e9a7d5108c2cff9a42bc2dce799eda80d68166ea612e/text2num-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f85cb45341bd535b8477dd0d5caecac021989d681f4604ba3f31e246dc5dadd", size = 391652, upload-time = "2026-03-09T11:08:13.178Z" }, + { url = "https://files.pythonhosted.org/packages/26/4c/eb73c8df24e36d72ee4c6e8e3dcbdda17bd60e92b868b4efa0164587192d/text2num-3.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0c2002618681d3065706fdafbe99f9f047afee76a4fe6e8366782a43535649d5", size = 421131, upload-time = "2026-03-09T11:08:03.583Z" }, + { url = "https://files.pythonhosted.org/packages/32/71/ca13f46b2bd13736900456f3e086b55c4eb81172070dce298b17fbcc6a2b/text2num-3.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6d27696e075b0881bcf282b4e0f6d03c6ad8b3ea3a2654964b281113569e170", size = 567100, upload-time = "2026-03-09T11:08:31Z" }, + { url = "https://files.pythonhosted.org/packages/00/3e/a0332a3b7fad9b7e39d51136d9dc56a690aa9ad2995c6feb8177030f9a8f/text2num-3.0.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:de0101cda5ae4d8367204cd938234f7c2152ef6a3253baddbc5ed78c9810e2b9", size = 675521, upload-time = "2026-03-09T11:08:44.856Z" }, + { url = "https://files.pythonhosted.org/packages/91/7c/c76ab11004ae48dc158c5cd5f065a1498626f8f168ef123c08c5b70f83f1/text2num-3.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ad2ab25bcd90ffcab07d3512fb71cc08b0b4209c06cca3bab04844bd3be12e8d", size = 635972, upload-time = "2026-03-09T11:08:57.59Z" }, + { url = "https://files.pythonhosted.org/packages/cf/2a/806907d3af3a1b85e9e4b23bff83796d13cf5ff3fc296504b78867b5d97f/text2num-3.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:367c9feccb62801c2f58160f3ca658c6c0811ce0b8c4d323006b9f5d64e94da2", size = 600105, upload-time = "2026-03-09T11:09:13.465Z" }, + { url = "https://files.pythonhosted.org/packages/ca/09/be2e74b796eb58997638773e41237509f9761876b65f469a0431145b899c/text2num-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9cb38f63dadff3f2bee2c06e9213c4836fcf73ca12e313c873e5359af72ee878", size = 233211, upload-time = "2026-03-09T11:09:26.79Z" }, + { url = "https://files.pythonhosted.org/packages/8c/91/b973b87d5c6226559a5444eead0b8399170973951907b6499e38eb877ed0/text2num-3.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a88f962944875edf62393b0c098c365953ba5b5b1f68a10f343876e853551589", size = 348826, upload-time = "2026-03-09T11:08:25.853Z" }, + { url = "https://files.pythonhosted.org/packages/af/32/cae4683fc0d72ebb1825001b8f6ac11dd86044dd3ec92bb729c5f4cb7f6c/text2num-3.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6435ace5b1d88abb9205d3f7e6a3a47b3ede4ef8c4d94cd6344ea7039dc997bf", size = 390040, upload-time = "2026-03-09T11:07:12.787Z" }, + { url = "https://files.pythonhosted.org/packages/e2/54/838866990d9fe07d224df0d1b2e8ad92b104cedcdf35a9ac2f459ea69b5e/text2num-3.0.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42766d19650a94ec1e7c05375ac2f444d8f5a0d031f46bbc1d9d565d843ca4aa", size = 398551, upload-time = "2026-03-09T11:07:26.857Z" }, + { url = "https://files.pythonhosted.org/packages/fd/3b/a0203f30d526dca96383be32840d2a4aa1a191de440cc6dea6d8dd95ff84/text2num-3.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4aedface5a98526747f4e04dc1bafebd9ee2308a311d5df958ac923f0f2e1d29", size = 508468, upload-time = "2026-03-09T11:07:39.291Z" }, + { url = "https://files.pythonhosted.org/packages/0f/35/6279b506d48710f6dbd333267897cc5f98a1c2343fa71769b9cabcf6ec10/text2num-3.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de342a057b447e29cb0ab6aeac7440e6c54e0bde87c222335fe890ed3a87f877", size = 416802, upload-time = "2026-03-09T11:07:51.413Z" }, + { url = "https://files.pythonhosted.org/packages/23/0b/d19b870990ac4ae0264c2abd282fd1bb19b4bfb1ba18f6d2c2cc2b24190c/text2num-3.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c979d81abb44576c874a7fab54fe6d923a86532cb161ecd214345e74196c7e20", size = 388321, upload-time = "2026-03-09T11:08:14.392Z" }, + { url = "https://files.pythonhosted.org/packages/ef/25/fbe880aec964af0bcf464b801ef162e4f71d4c802be0c67c4446a943e029/text2num-3.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:141af64a3e89f9f68654d8db82e2a6155f67ec11ceb952ab38bf27a6979a799c", size = 418440, upload-time = "2026-03-09T11:08:05.041Z" }, + { url = "https://files.pythonhosted.org/packages/12/eb/fda6edfd67f802f9d1a516106cbd9959221045a46680d84781d362f1aee7/text2num-3.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3150f6838be27d4d62661e7879df2530c1e6e59e584bd30b4d4e724f2284ba5a", size = 565313, upload-time = "2026-03-09T11:08:32.498Z" }, + { url = "https://files.pythonhosted.org/packages/00/25/dd5a30ff5b1a1c2e09c5e88f9d336b3b75c9a614fe71a9c414b0ea48e894/text2num-3.0.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:4d4fdd8610272e3583357aff808cb03a77983916395f1e9ba872066199d6a560", size = 673512, upload-time = "2026-03-09T11:08:46.353Z" }, + { url = "https://files.pythonhosted.org/packages/76/01/5f3d166697b73eb93062f2459614768d7ce08a0ecf2e1627621c3c7cd509/text2num-3.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1b9a27e2d39c1c3f27b52ccbb98e56b984ab19c3b081312a1b01b5b20343aeed", size = 632842, upload-time = "2026-03-09T11:08:58.916Z" }, + { url = "https://files.pythonhosted.org/packages/97/53/ee4effafd9c55cd3bc981478b9c499dd992038da80e721f8923ca4e56443/text2num-3.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83a9a4c951b260ac2ee73d27e2b8187a8760c9b3c91c11dc5017dcbc11558c2a", size = 597185, upload-time = "2026-03-09T11:09:15.513Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/cb1d2b05031066b94c44b313f1706fb96c60f196e229d609eca732613a8c/text2num-3.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:b0299703b6ee6b74547a1ab9154a174916dc0e0c6f8e224d528fd488fa836f3c", size = 232049, upload-time = "2026-03-09T11:09:27.822Z" }, + { url = "https://files.pythonhosted.org/packages/c6/c5/f0ef87c451977837215d43eee6b56cc4c7b898979a9dcaaeed0f738d1404/text2num-3.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e642eda81046e26b2f21cc7215d8f432658add33abc3eef90af4f10317e6083", size = 348512, upload-time = "2026-03-09T11:08:26.891Z" }, + { url = "https://files.pythonhosted.org/packages/d5/18/0ebec5f84af65002982fc5fd621103d77ed1628f87554cc9359b73ae8f12/text2num-3.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32af165fc9477305ff065d6aa0d1012e30ccd6926ad9ec96fc2f50ec3280b79a", size = 389376, upload-time = "2026-03-09T11:07:14.137Z" }, + { url = "https://files.pythonhosted.org/packages/37/f9/50fa298060e9a58a994e6bcc3dd2b4bbba0fc84d0156614f747a4eab725c/text2num-3.0.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1fb0504db70078e27fd0031a381fe0f56fa8088386be323f2ebe42277df9bc38", size = 397933, upload-time = "2026-03-09T11:07:28.342Z" }, + { url = "https://files.pythonhosted.org/packages/48/c4/879633d92f317bdae66da15df1f1eb00c86df72c2fa50b69043293bf7568/text2num-3.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92b0c46da44aeb688643af4ead17d54f2cebc62f44da25062280fb1de62cd58c", size = 506789, upload-time = "2026-03-09T11:07:40.743Z" }, + { url = "https://files.pythonhosted.org/packages/26/88/75227847926aa3883195ff3d70eb4de615ed41c6405acf3745764f22a94d/text2num-3.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3f88b2edafac51423f02a656ab9dabee5dcf2da5c829f95b713cfca374012cb6", size = 416619, upload-time = "2026-03-09T11:07:52.551Z" }, + { url = "https://files.pythonhosted.org/packages/af/9e/e5491fd7eb74029f4920caacccf85fac5e0806f3e33ceab46db008e0c515/text2num-3.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:866e79cd7b0b55da4c82d6c077ad2837089b3d40730a3ba0e71ec53072686540", size = 387826, upload-time = "2026-03-09T11:08:15.449Z" }, + { url = "https://files.pythonhosted.org/packages/a0/5d/9f5860d6d02b9d492f63af4e93eb3c3c7d85043bb0ecba28d55c0ea96ece/text2num-3.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e38c37afe0382b32863cf5aab60124abc7a6bae697cfffd902dff2874556cbd0", size = 417483, upload-time = "2026-03-09T11:08:06.111Z" }, + { url = "https://files.pythonhosted.org/packages/6b/e3/5b927d93b3cf5eb285a913ce18edd2a7c1a710928bc26245bb1660274424/text2num-3.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:98a543c2e07fc2ff49744094b04fa03d6d2f3cd3e6bc8bd3fe020e9500615fa2", size = 564985, upload-time = "2026-03-09T11:08:34.033Z" }, + { url = "https://files.pythonhosted.org/packages/ce/a0/a15562c3d40dfd9c32189e779d625e9bec0a32806e5ec224f2355eb065df/text2num-3.0.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4e028ff2d8208df6d1f499b49fa09f99c39921e670dff5a19f04bc3a5d17b5f9", size = 673036, upload-time = "2026-03-09T11:08:47.531Z" }, + { url = "https://files.pythonhosted.org/packages/03/14/9d28b27a84e5924751d91c3dd039470a43b9aa46ec48d76f9f99af9e24d5/text2num-3.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c2648cf5b744bd3d207bfcc6f9de9d8aec8258d13827812b6ae011961d51f78a", size = 632174, upload-time = "2026-03-09T11:09:00.172Z" }, + { url = "https://files.pythonhosted.org/packages/d9/f7/7b9a986405d60b2e963004fccb2bc114b90abb3b94dadeed406a7aa1e080/text2num-3.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:56e09cfeb35213928bc1e3539a53835cb2ddb25e2fdd97336373441f6e5b23ff", size = 596605, upload-time = "2026-03-09T11:09:16.87Z" }, + { url = "https://files.pythonhosted.org/packages/8a/98/4367fd650de09a606bee0918d31d9b1a9089c7bbd4990e2e7f2f9975dd38/text2num-3.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:2ea4666427654af4c43a183e400a572f2d792fa96cb65a1c34c94f23454fc3df", size = 231610, upload-time = "2026-03-09T11:09:28.895Z" }, + { url = "https://files.pythonhosted.org/packages/98/d8/a9f47dcf7d7cc3c4c536deb9d1fcd9e2f6dc5e6c8137929190e6d3b0f6b9/text2num-3.0.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62a1abe2eb41eb3322599c78a78aa530375fa69d079157cd4afda583c56ec6af", size = 388105, upload-time = "2026-03-09T11:07:15.634Z" }, + { url = "https://files.pythonhosted.org/packages/58/00/3df91c9f09ffed38687b307dbf63f600132608c1178f25b841caceb606a4/text2num-3.0.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d8307fac698acda19eed629996e7438de65f41e8106f77e6cf02bb7de8d64b91", size = 397573, upload-time = "2026-03-09T11:07:29.468Z" }, + { url = "https://files.pythonhosted.org/packages/31/72/f1a4a7f415b829b902a9701487fd79c5127db8e9ac21fb576c6152c5d536/text2num-3.0.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aad32df3254a3a887580c62ce6755fe3f62c0c99b424be73f6ab72a02b84c0c0", size = 507935, upload-time = "2026-03-09T11:07:42.093Z" }, + { url = "https://files.pythonhosted.org/packages/77/49/84dcc96a024c2bd1fa9398da129c516805aecddeaf1dfa7ed0f100082e44/text2num-3.0.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:534b624d8525acda7b0c0e09c6c014430692cd20bfec2268880a486a8c6d8311", size = 416176, upload-time = "2026-03-09T11:07:53.992Z" }, + { url = "https://files.pythonhosted.org/packages/dc/42/fd64a5d09086ed43dbee7a20bcff594995cc0897d10467440d78e0ca92a5/text2num-3.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:171db3ae93da7cf848a2fdbb2799d0b63b64ccd9acc96640c2d56203a837e552", size = 564780, upload-time = "2026-03-09T11:08:35.511Z" }, + { url = "https://files.pythonhosted.org/packages/2c/05/576bb8da8638e7b53f3e5f6157bcc635f23813299066b39e9c35a05aed6b/text2num-3.0.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:7f6431c2c78800ee5e7e9771b9d849c7b2d4f43d6e54b0acd753faabf7b71e12", size = 672709, upload-time = "2026-03-09T11:08:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/11/13/cb59392cb01038bea236d584c2b90c36aa51977bf3f5e0c6682cdb9e5631/text2num-3.0.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ca97aace211b8d7107a850bd4e8b93107316faa03fac5919f693a8487a14cd4c", size = 631637, upload-time = "2026-03-09T11:09:01.802Z" }, + { url = "https://files.pythonhosted.org/packages/44/4d/869869a9898b69ae6d53b3ba0fb456f56c301897dc156b7c3d1d87723af7/text2num-3.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d7c2d9e81d0759a7bcc4ff8ee5cd860203cb141b6ffc8effdfbd63351e3494eb", size = 596355, upload-time = "2026-03-09T11:09:18.032Z" }, + { url = "https://files.pythonhosted.org/packages/2b/a9/ddb3038990fc5b4d6a1672b266053a992605efc0866465ce2014c8d1aad1/text2num-3.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:298fa80e4a5e139dc355ffeeaec0028363a8514259a51e13df8a26a85cd76cab", size = 348417, upload-time = "2026-03-09T11:08:28Z" }, + { url = "https://files.pythonhosted.org/packages/95/c6/641bf9e6ca1b39253709c57790beb2077005470677ba81d4aae76ab2984f/text2num-3.0.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aceff51b9c540dcd2fe1563c1afd3d61fb6a46e55c512983d4c731efe3d03ca6", size = 389617, upload-time = "2026-03-09T11:07:18.483Z" }, + { url = "https://files.pythonhosted.org/packages/fc/4d/e64e797622c1c1d85fb4e1900e12e92edea3f43df244d68ff11d13685c01/text2num-3.0.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9b039bbac313c5a75fa4df4235889d6414ecb39ad0ee630b11a664e23c7a737a", size = 397981, upload-time = "2026-03-09T11:07:30.57Z" }, + { url = "https://files.pythonhosted.org/packages/53/42/98568349294825d15dbd1779256dab2a5d3d41a22129b097c49e732b3960/text2num-3.0.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:698937bf05e1d3f967b324e073c841f94b9381cd64711b0ae06ac2b4b302aabb", size = 508736, upload-time = "2026-03-09T11:07:43.233Z" }, + { url = "https://files.pythonhosted.org/packages/78/98/bd40c9d8e85518dde09a11bf70072b5688df38e4d44d26c1a7de1372dd4d/text2num-3.0.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf8d0433c4ce32c4a27ebdf303849767d2286b4b0f562f821225348e39c51891", size = 416848, upload-time = "2026-03-09T11:07:55.084Z" }, + { url = "https://files.pythonhosted.org/packages/e7/06/d07761db1147e1699c4e8d0b32445de3b1a11ed228b494d09dd58a1eccd8/text2num-3.0.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4faa45f795f6c674cf05060403a6e9ecc48a3b0d9da9eee74dbfef6c88a14f2", size = 387788, upload-time = "2026-03-09T11:08:18.298Z" }, + { url = "https://files.pythonhosted.org/packages/1b/07/d6988e85154a6c2f23f467b1363b4bd1c30868fe1a053fa5eafe7c18ec79/text2num-3.0.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4da03e61ccb73476a68190a46a0057ea7e781796a286564c713c3d0941fa7940", size = 417762, upload-time = "2026-03-09T11:08:07.132Z" }, + { url = "https://files.pythonhosted.org/packages/99/a4/f578d55e2ad89f8545c368ffa956fe8aa73bd8bcea0eeb09697dc8d878b9/text2num-3.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:43e739ce09fe77064c27e8bdb5c2db5880db7a3d7f5ca350b7a897ea3800cd61", size = 565151, upload-time = "2026-03-09T11:08:36.968Z" }, + { url = "https://files.pythonhosted.org/packages/55/6f/1531700a0814dbd3e9644143bb3ae1ce30a32f96a6a9d54926a9d5c7a1ba/text2num-3.0.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:0a0d6a3d347c73a07a7580b710381fdec0a4d423cd57623fe584cd819d41bb0f", size = 673090, upload-time = "2026-03-09T11:08:50.256Z" }, + { url = "https://files.pythonhosted.org/packages/c1/21/9e4570238945218e9d04ae63c8b47c0f1d03195754228b42322f679bb3b3/text2num-3.0.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:2a63507166f9e9cf3e0cd036a00ab0fe613768ec3f1941232206b4546ffdb1c9", size = 632577, upload-time = "2026-03-09T11:09:03.517Z" }, + { url = "https://files.pythonhosted.org/packages/9b/46/5cb5d49fe5fa0c23f5ae4ae21ed84d4136fde806283fb8dd3721cd5a8b48/text2num-3.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5f1bfcc161ce5ac69b152993635e238069f9ba68b6ad0d5a89508a530b6287a9", size = 596667, upload-time = "2026-03-09T11:09:19.134Z" }, + { url = "https://files.pythonhosted.org/packages/b9/45/0dcfcf2465ef2f0b1ae43cb44825b36b43164139698efb6a3f13bb10d5da/text2num-3.0.1-cp314-cp314-win32.whl", hash = "sha256:e2713f72891871556cd3947506279581cedb52461031fea06732acf996c6ee87", size = 228440, upload-time = "2026-03-09T11:09:32.042Z" }, + { url = "https://files.pythonhosted.org/packages/8f/71/73ad464573c4f486de5ca0cb2c965cdb46bd2aae788c61baf5b94b4de6fa/text2num-3.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:493ebc4df9e354b3f4e555efb3150af3d199d9a54f2c55a45445113200f8e147", size = 231896, upload-time = "2026-03-09T11:09:30.623Z" }, + { url = "https://files.pythonhosted.org/packages/4c/ed/659de83da1a8099d0feb90c9651b24b136abef0cca900460e4e5481388c3/text2num-3.0.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f8aef8746f4022900e680a89974de2474915b5e14ebde100175b4c4e9914ef8", size = 388049, upload-time = "2026-03-09T11:07:19.603Z" }, + { url = "https://files.pythonhosted.org/packages/ca/52/5914e3cabfcd232ef0a763c28f75a879197d314885c533779d2f8686a203/text2num-3.0.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:593507f0a87a5dbd7632c63e4d463183f5d0a3ad42164dd06471a60327ed0027", size = 396976, upload-time = "2026-03-09T11:07:31.801Z" }, + { url = "https://files.pythonhosted.org/packages/2d/d6/81c17b431f5563967229ba0c5bf36c25356bdb0737808ca3aea4675c0b4d/text2num-3.0.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:350fe2f095f85eed9f815af0b61e908f2fe94b6f8aace9a11a2e2e6f71f61755", size = 507885, upload-time = "2026-03-09T11:07:44.441Z" }, + { url = "https://files.pythonhosted.org/packages/16/a2/696cc4960c71f012a7a69f57e125bf518d2e8973f4b95de2079777944ed1/text2num-3.0.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec2dc473eb9319cdac73f1635508273a2ca2ba98a220d715120e505357a786a2", size = 416292, upload-time = "2026-03-09T11:07:56.385Z" }, + { url = "https://files.pythonhosted.org/packages/06/b1/200d97fdeb3f5023b8e84bd1a810a347853913695ee1478bb077d33ff06d/text2num-3.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9c593f75be149d9257d162d437919a73e0abc8559cd155639089dd09d1b7296", size = 564583, upload-time = "2026-03-09T11:08:38.468Z" }, + { url = "https://files.pythonhosted.org/packages/19/a5/0714da9a503d09297ec367ebfc4d7963f4450ea3ce26a79cd7ae2f7adf33/text2num-3.0.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:18a66549ffabc7cf9979d478e50dda2041b814087f4d36adb231c6df88636185", size = 672749, upload-time = "2026-03-09T11:08:51.769Z" }, + { url = "https://files.pythonhosted.org/packages/6c/79/a68454e6ca45d2c0c126a2e9c35eaa96205cf677c016ed0f80d62b531b10/text2num-3.0.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:43f9dadea3e628152e23cd7b1db42a3aae27b68d68b59a9e61e4dbbbee17b8cc", size = 631525, upload-time = "2026-03-09T11:09:04.641Z" }, + { url = "https://files.pythonhosted.org/packages/3d/13/ff305edf26824ad69fa08f2fb0677a88901418711c5cbdd4f14d5bb97876/text2num-3.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ef9918c84f50f936c1b88fe815cd7e90129dd4799cedf328815d40472a933446", size = 596220, upload-time = "2026-03-09T11:09:20.211Z" }, + { url = "https://files.pythonhosted.org/packages/e3/be/6f18bc112fa88da3b817b721cfbe4f4a1937c95e7e5a04eeaaf5ef8b2501/text2num-3.0.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f2c46361ecce5070131ece663e5eeea9ce365c9d65d0a3a01fa65dd22413fd", size = 394651, upload-time = "2026-03-09T11:07:23.02Z" }, + { url = "https://files.pythonhosted.org/packages/6f/10/e1ca0056de99789bfc922f6908821e0a9911638c8c26b032679f69b070d6/text2num-3.0.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00def0abc84bc9a007885052753ff1ef4fc50c3055c88ad368161714dfd5de09", size = 403564, upload-time = "2026-03-09T11:07:35.167Z" }, + { url = "https://files.pythonhosted.org/packages/ae/94/f0bd226219e560ccaf52856a54fa646d0b53d5d2930e4d77d049d70a4da4/text2num-3.0.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8fffd46241fbcead57b2d261625dcf2eaac55be1cab8ba4e2cb5aaef77d02f45", size = 512861, upload-time = "2026-03-09T11:07:48.101Z" }, + { url = "https://files.pythonhosted.org/packages/eb/75/1c48ca14f1a071b6e4e900d8a381e2af665b7b049b302483c586b5965b35/text2num-3.0.1-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:325222e5ce1c3d43beff762235eab92310a3b947f480082e55bb199e646347bc", size = 421379, upload-time = "2026-03-09T11:08:00.021Z" }, + { url = "https://files.pythonhosted.org/packages/de/a7/6215833bbdcc1bbe90ca4ea9b725e394a52b639ef00f14f0d82521107299/text2num-3.0.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e65ff1da65f8015c5899021bdcab3830932bff3bf67f32ff465ea6802ce5e0ae", size = 394346, upload-time = "2026-03-09T11:08:23.49Z" }, + { url = "https://files.pythonhosted.org/packages/2c/fb/95a50d4b16ea21ab20ff2579b767df2e75173e0d030e6e100e5b4741f418/text2num-3.0.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:955e5bcd65dbcab9519ebf0af0886781d84c75e7f5cbad5a8d83c88d798f89ec", size = 423307, upload-time = "2026-03-09T11:08:10.819Z" }, + { url = "https://files.pythonhosted.org/packages/91/7b/a11864e341bdb8a499aa6761647a8de44273a0b81ad622c88c654d61835b/text2num-3.0.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:05af036c5481760b63a293e0c90c8d7a7035ef63b5377fe7ffe3fb07de715911", size = 570223, upload-time = "2026-03-09T11:08:42.498Z" }, + { url = "https://files.pythonhosted.org/packages/1d/8d/300542c8be78e93bb8ef337f75c1543f3a9b103a852d1de531e2a1e80eb9/text2num-3.0.1-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:bf7e24aa01cf63c2d65cc62ff2ddded3f6b16f69170c736aba994ee9f48c6b0c", size = 678489, upload-time = "2026-03-09T11:08:55.292Z" }, + { url = "https://files.pythonhosted.org/packages/ff/f8/f8d5484cf0212367a075c42ad1824c8d737fca8d73892a309130f102fc9d/text2num-3.0.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:a0c71bf8be81612f58935fb09c2a15cad42ecbb2b876943dbf8474344c77ecfe", size = 638647, upload-time = "2026-03-09T11:09:09.16Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e7/2b14b9e947ba17bab06c55adbae5ce87b76480fda8652e41d0f48fdf6663/text2num-3.0.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e0c6310ba535e8f6f541cf57dd41405082ae73e0924e4e8ebdb92bcd8cbe26dd", size = 602192, upload-time = "2026-03-09T11:09:23.692Z" }, +] + [[package]] name = "textsearch" version = "0.0.24"