words2num2 0.3.0.dev2__tar.gz → 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. {words2num2-0.3.0.dev2 → words2num2-0.3.1}/PKG-INFO +76 -28
  2. words2num2-0.3.0.dev2/words2num2.egg-info/PKG-INFO → words2num2-0.3.1/README.rst +62 -44
  3. words2num2-0.3.1/pyproject.toml +94 -0
  4. words2num2-0.3.1/rust/Cargo.lock +287 -0
  5. words2num2-0.3.1/rust/Cargo.toml +16 -0
  6. words2num2-0.3.1/rust/words2num2-core/Cargo.toml +18 -0
  7. words2num2-0.3.1/rust/words2num2-core/src/lib.rs +242 -0
  8. words2num2-0.3.1/rust/words2num2-core/src/w2n_formats.rs +1056 -0
  9. words2num2-0.3.1/rust/words2num2-core/src/w2n_lang_en.rs +1011 -0
  10. words2num2-0.3.1/rust/words2num2-core/src/w2n_sentence.rs +2336 -0
  11. words2num2-0.3.1/rust/words2num2-py/Cargo.toml +14 -0
  12. words2num2-0.3.1/rust/words2num2-py/src/lib.rs +312 -0
  13. words2num2-0.3.1/words2num2/__init__.py +140 -0
  14. words2num2-0.3.1/words2num2/_version.py +5 -0
  15. words2num2-0.3.1/words2num2/base.py +19 -0
  16. words2num2-0.3.1/words2num2/converters/auto.py +43 -0
  17. words2num2-0.3.0.dev2/.flake8 +0 -11
  18. words2num2-0.3.0.dev2/.github/workflows/aur-publish.yml +0 -104
  19. words2num2-0.3.0.dev2/.github/workflows/ci.yml +0 -68
  20. words2num2-0.3.0.dev2/.github/workflows/codeql-analysis.yml +0 -38
  21. words2num2-0.3.0.dev2/.github/workflows/e2e-tests.yml +0 -73
  22. words2num2-0.3.0.dev2/.github/workflows/lint.yml +0 -47
  23. words2num2-0.3.0.dev2/.github/workflows/manual-publish.yml +0 -66
  24. words2num2-0.3.0.dev2/.github/workflows/manual-release.yml +0 -81
  25. words2num2-0.3.0.dev2/.github/workflows/pr-size.yml +0 -67
  26. words2num2-0.3.0.dev2/.github/workflows/publish-pypi.yml +0 -76
  27. words2num2-0.3.0.dev2/.github/workflows/python-publish.yml +0 -61
  28. words2num2-0.3.0.dev2/.github/workflows/release.yml +0 -166
  29. words2num2-0.3.0.dev2/.github/workflows/scheduled-test.yml +0 -44
  30. words2num2-0.3.0.dev2/.gitignore +0 -18
  31. words2num2-0.3.0.dev2/CHANGELOG.md +0 -152
  32. words2num2-0.3.0.dev2/CONTRIBUTING.md +0 -123
  33. words2num2-0.3.0.dev2/LOCAL_TESTING.md +0 -173
  34. words2num2-0.3.0.dev2/MANIFEST.in +0 -5
  35. words2num2-0.3.0.dev2/Makefile +0 -50
  36. words2num2-0.3.0.dev2/README.rst +0 -360
  37. words2num2-0.3.0.dev2/REFERENCE.md +0 -450
  38. words2num2-0.3.0.dev2/bin/words2num2 +0 -28
  39. words2num2-0.3.0.dev2/packaging/aur/python-words2num2/.SRCINFO +0 -20
  40. words2num2-0.3.0.dev2/packaging/aur/python-words2num2/PKGBUILD +0 -33
  41. words2num2-0.3.0.dev2/packaging/aur/python-words2num2/README.md +0 -88
  42. words2num2-0.3.0.dev2/pyproject.toml +0 -88
  43. words2num2-0.3.0.dev2/setup.cfg +0 -4
  44. words2num2-0.3.0.dev2/setup.py +0 -63
  45. words2num2-0.3.0.dev2/tests/__init__.py +0 -0
  46. words2num2-0.3.0.dev2/tests/test_auto_parse.py +0 -252
  47. words2num2-0.3.0.dev2/tests/test_dispatch.py +0 -28
  48. words2num2-0.3.0.dev2/tests/test_lang_EN.py +0 -113
  49. words2num2-0.3.0.dev2/tests/test_multilang.py +0 -49
  50. words2num2-0.3.0.dev2/words2num2/__init__.py +0 -360
  51. words2num2-0.3.0.dev2/words2num2/_version.py +0 -3
  52. words2num2-0.3.0.dev2/words2num2/base.py +0 -155
  53. words2num2-0.3.0.dev2/words2num2/compat.py +0 -9
  54. words2num2-0.3.0.dev2/words2num2/converters/auto.py +0 -586
  55. words2num2-0.3.0.dev2/words2num2/converters/sentence.py +0 -116
  56. words2num2-0.3.0.dev2/words2num2/formats.py +0 -212
  57. words2num2-0.3.0.dev2/words2num2/lang_AF.py +0 -15
  58. words2num2-0.3.0.dev2/words2num2/lang_AM.py +0 -15
  59. words2num2-0.3.0.dev2/words2num2/lang_AR.py +0 -15
  60. words2num2-0.3.0.dev2/words2num2/lang_AS.py +0 -15
  61. words2num2-0.3.0.dev2/words2num2/lang_AZ.py +0 -15
  62. words2num2-0.3.0.dev2/words2num2/lang_BA.py +0 -15
  63. words2num2-0.3.0.dev2/words2num2/lang_BE.py +0 -15
  64. words2num2-0.3.0.dev2/words2num2/lang_BG.py +0 -15
  65. words2num2-0.3.0.dev2/words2num2/lang_BN.py +0 -15
  66. words2num2-0.3.0.dev2/words2num2/lang_BO.py +0 -15
  67. words2num2-0.3.0.dev2/words2num2/lang_BR.py +0 -15
  68. words2num2-0.3.0.dev2/words2num2/lang_BS.py +0 -15
  69. words2num2-0.3.0.dev2/words2num2/lang_CA.py +0 -15
  70. words2num2-0.3.0.dev2/words2num2/lang_CE.py +0 -15
  71. words2num2-0.3.0.dev2/words2num2/lang_CS.py +0 -15
  72. words2num2-0.3.0.dev2/words2num2/lang_CY.py +0 -15
  73. words2num2-0.3.0.dev2/words2num2/lang_DA.py +0 -15
  74. words2num2-0.3.0.dev2/words2num2/lang_DE.py +0 -15
  75. words2num2-0.3.0.dev2/words2num2/lang_EL.py +0 -15
  76. words2num2-0.3.0.dev2/words2num2/lang_EN.py +0 -242
  77. words2num2-0.3.0.dev2/words2num2/lang_EN_IN.py +0 -15
  78. words2num2-0.3.0.dev2/words2num2/lang_EN_NG.py +0 -15
  79. words2num2-0.3.0.dev2/words2num2/lang_EO.py +0 -15
  80. words2num2-0.3.0.dev2/words2num2/lang_ES.py +0 -15
  81. words2num2-0.3.0.dev2/words2num2/lang_ES_CO.py +0 -15
  82. words2num2-0.3.0.dev2/words2num2/lang_ES_CR.py +0 -15
  83. words2num2-0.3.0.dev2/words2num2/lang_ES_GT.py +0 -15
  84. words2num2-0.3.0.dev2/words2num2/lang_ES_NI.py +0 -15
  85. words2num2-0.3.0.dev2/words2num2/lang_ES_VE.py +0 -15
  86. words2num2-0.3.0.dev2/words2num2/lang_ET.py +0 -15
  87. words2num2-0.3.0.dev2/words2num2/lang_EU.py +0 -15
  88. words2num2-0.3.0.dev2/words2num2/lang_FA.py +0 -15
  89. words2num2-0.3.0.dev2/words2num2/lang_FI.py +0 -15
  90. words2num2-0.3.0.dev2/words2num2/lang_FO.py +0 -15
  91. words2num2-0.3.0.dev2/words2num2/lang_FR.py +0 -15
  92. words2num2-0.3.0.dev2/words2num2/lang_FR_BE.py +0 -15
  93. words2num2-0.3.0.dev2/words2num2/lang_FR_CH.py +0 -15
  94. words2num2-0.3.0.dev2/words2num2/lang_FR_DZ.py +0 -15
  95. words2num2-0.3.0.dev2/words2num2/lang_GL.py +0 -15
  96. words2num2-0.3.0.dev2/words2num2/lang_GU.py +0 -15
  97. words2num2-0.3.0.dev2/words2num2/lang_HA.py +0 -15
  98. words2num2-0.3.0.dev2/words2num2/lang_HAW.py +0 -15
  99. words2num2-0.3.0.dev2/words2num2/lang_HE.py +0 -15
  100. words2num2-0.3.0.dev2/words2num2/lang_HI.py +0 -15
  101. words2num2-0.3.0.dev2/words2num2/lang_HR.py +0 -15
  102. words2num2-0.3.0.dev2/words2num2/lang_HT.py +0 -15
  103. words2num2-0.3.0.dev2/words2num2/lang_HU.py +0 -15
  104. words2num2-0.3.0.dev2/words2num2/lang_HY.py +0 -15
  105. words2num2-0.3.0.dev2/words2num2/lang_ID.py +0 -15
  106. words2num2-0.3.0.dev2/words2num2/lang_IS.py +0 -15
  107. words2num2-0.3.0.dev2/words2num2/lang_IT.py +0 -15
  108. words2num2-0.3.0.dev2/words2num2/lang_JA.py +0 -15
  109. words2num2-0.3.0.dev2/words2num2/lang_JW.py +0 -15
  110. words2num2-0.3.0.dev2/words2num2/lang_KA.py +0 -15
  111. words2num2-0.3.0.dev2/words2num2/lang_KK.py +0 -15
  112. words2num2-0.3.0.dev2/words2num2/lang_KM.py +0 -15
  113. words2num2-0.3.0.dev2/words2num2/lang_KN.py +0 -15
  114. words2num2-0.3.0.dev2/words2num2/lang_KO.py +0 -15
  115. words2num2-0.3.0.dev2/words2num2/lang_KZ.py +0 -15
  116. words2num2-0.3.0.dev2/words2num2/lang_LA.py +0 -15
  117. words2num2-0.3.0.dev2/words2num2/lang_LB.py +0 -15
  118. words2num2-0.3.0.dev2/words2num2/lang_LN.py +0 -15
  119. words2num2-0.3.0.dev2/words2num2/lang_LO.py +0 -15
  120. words2num2-0.3.0.dev2/words2num2/lang_LT.py +0 -15
  121. words2num2-0.3.0.dev2/words2num2/lang_LV.py +0 -15
  122. words2num2-0.3.0.dev2/words2num2/lang_MG.py +0 -15
  123. words2num2-0.3.0.dev2/words2num2/lang_MI.py +0 -15
  124. words2num2-0.3.0.dev2/words2num2/lang_MK.py +0 -15
  125. words2num2-0.3.0.dev2/words2num2/lang_ML.py +0 -15
  126. words2num2-0.3.0.dev2/words2num2/lang_MN.py +0 -15
  127. words2num2-0.3.0.dev2/words2num2/lang_MR.py +0 -15
  128. words2num2-0.3.0.dev2/words2num2/lang_MS.py +0 -15
  129. words2num2-0.3.0.dev2/words2num2/lang_MT.py +0 -15
  130. words2num2-0.3.0.dev2/words2num2/lang_MY.py +0 -15
  131. words2num2-0.3.0.dev2/words2num2/lang_NE.py +0 -15
  132. words2num2-0.3.0.dev2/words2num2/lang_NL.py +0 -15
  133. words2num2-0.3.0.dev2/words2num2/lang_NN.py +0 -15
  134. words2num2-0.3.0.dev2/words2num2/lang_NO.py +0 -15
  135. words2num2-0.3.0.dev2/words2num2/lang_OC.py +0 -15
  136. words2num2-0.3.0.dev2/words2num2/lang_PA.py +0 -15
  137. words2num2-0.3.0.dev2/words2num2/lang_PL.py +0 -15
  138. words2num2-0.3.0.dev2/words2num2/lang_PS.py +0 -15
  139. words2num2-0.3.0.dev2/words2num2/lang_PT.py +0 -15
  140. words2num2-0.3.0.dev2/words2num2/lang_PT_BR.py +0 -15
  141. words2num2-0.3.0.dev2/words2num2/lang_RO.py +0 -15
  142. words2num2-0.3.0.dev2/words2num2/lang_RU.py +0 -15
  143. words2num2-0.3.0.dev2/words2num2/lang_SA.py +0 -15
  144. words2num2-0.3.0.dev2/words2num2/lang_SD.py +0 -15
  145. words2num2-0.3.0.dev2/words2num2/lang_SI.py +0 -15
  146. words2num2-0.3.0.dev2/words2num2/lang_SK.py +0 -15
  147. words2num2-0.3.0.dev2/words2num2/lang_SL.py +0 -15
  148. words2num2-0.3.0.dev2/words2num2/lang_SN.py +0 -15
  149. words2num2-0.3.0.dev2/words2num2/lang_SO.py +0 -15
  150. words2num2-0.3.0.dev2/words2num2/lang_SQ.py +0 -15
  151. words2num2-0.3.0.dev2/words2num2/lang_SR.py +0 -15
  152. words2num2-0.3.0.dev2/words2num2/lang_SU.py +0 -15
  153. words2num2-0.3.0.dev2/words2num2/lang_SV.py +0 -15
  154. words2num2-0.3.0.dev2/words2num2/lang_SW.py +0 -15
  155. words2num2-0.3.0.dev2/words2num2/lang_TA.py +0 -15
  156. words2num2-0.3.0.dev2/words2num2/lang_TE.py +0 -15
  157. words2num2-0.3.0.dev2/words2num2/lang_TET.py +0 -15
  158. words2num2-0.3.0.dev2/words2num2/lang_TG.py +0 -15
  159. words2num2-0.3.0.dev2/words2num2/lang_TH.py +0 -15
  160. words2num2-0.3.0.dev2/words2num2/lang_TK.py +0 -15
  161. words2num2-0.3.0.dev2/words2num2/lang_TL.py +0 -15
  162. words2num2-0.3.0.dev2/words2num2/lang_TR.py +0 -15
  163. words2num2-0.3.0.dev2/words2num2/lang_TT.py +0 -15
  164. words2num2-0.3.0.dev2/words2num2/lang_UK.py +0 -15
  165. words2num2-0.3.0.dev2/words2num2/lang_UR.py +0 -15
  166. words2num2-0.3.0.dev2/words2num2/lang_UZ.py +0 -15
  167. words2num2-0.3.0.dev2/words2num2/lang_VI.py +0 -15
  168. words2num2-0.3.0.dev2/words2num2/lang_WO.py +0 -15
  169. words2num2-0.3.0.dev2/words2num2/lang_YI.py +0 -15
  170. words2num2-0.3.0.dev2/words2num2/lang_YO.py +0 -15
  171. words2num2-0.3.0.dev2/words2num2/lang_ZH.py +0 -15
  172. words2num2-0.3.0.dev2/words2num2/lang_ZH_CN.py +0 -15
  173. words2num2-0.3.0.dev2/words2num2/lang_ZH_HK.py +0 -15
  174. words2num2-0.3.0.dev2/words2num2/lang_ZH_TW.py +0 -15
  175. words2num2-0.3.0.dev2/words2num2/utils.py +0 -23
  176. words2num2-0.3.0.dev2/words2num2.egg-info/SOURCES.txt +0 -167
  177. words2num2-0.3.0.dev2/words2num2.egg-info/dependency_links.txt +0 -1
  178. words2num2-0.3.0.dev2/words2num2.egg-info/entry_points.txt +0 -2
  179. words2num2-0.3.0.dev2/words2num2.egg-info/requires.txt +0 -2
  180. words2num2-0.3.0.dev2/words2num2.egg-info/top_level.txt +0 -1
  181. {words2num2-0.3.0.dev2 → words2num2-0.3.1}/COPYING +0 -0
  182. {words2num2-0.3.0.dev2 → words2num2-0.3.1}/words2num2/__main__.py +0 -0
  183. {words2num2-0.3.0.dev2 → words2num2-0.3.1}/words2num2/converters/__init__.py +0 -0
@@ -1,18 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: words2num2
3
- Version: 0.3.0.dev2
4
- Summary: Inverse of num2words2: convert spoken-form numbers back to numeric values across 100+ languages.
5
- Home-page: https://github.com/jqueguiner/words2num2
6
- Author: Jean-Louis Queguiner
7
- Author-email: Jean-Louis Queguiner <jlqueguiner@gladia.io>
8
- Maintainer: Jean-Louis Queguiner
9
- Maintainer-email: Jean-Louis Queguiner <jlqueguiner@gladia.io>
10
- License: LGPL-2.1
11
- Project-URL: Homepage, https://github.com/jqueguiner/words2num2
12
- Project-URL: Documentation, https://github.com/jqueguiner/words2num2/wiki
13
- Project-URL: Repository, https://github.com/jqueguiner/words2num2.git
14
- Project-URL: Bug Tracker, https://github.com/jqueguiner/words2num2/issues
15
- Keywords: number,word,numbers,words,parse,parser,convert,conversion,i18n,localisation,localization,internationalisation,internationalization,asr,speech,llm
3
+ Version: 0.3.1
16
4
  Classifier: Development Status :: 4 - Beta
17
5
  Classifier: Intended Audience :: Developers
18
6
  Classifier: Programming Language :: Python :: 3
@@ -21,21 +9,23 @@ Classifier: Programming Language :: Python :: 3.11
21
9
  Classifier: Programming Language :: Python :: 3.12
22
10
  Classifier: Programming Language :: Python :: 3.13
23
11
  Classifier: Programming Language :: Python :: 3.14
24
- Classifier: Programming Language :: Python :: 3.15
12
+ Classifier: Programming Language :: Rust
25
13
  Classifier: Topic :: Software Development :: Internationalization
26
14
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
15
  Classifier: Topic :: Software Development :: Localization
28
16
  Classifier: Topic :: Text Processing :: Linguistic
29
- Requires-Python: >=3.10
30
- Description-Content-Type: text/x-rst
31
17
  License-File: COPYING
32
- Requires-Dist: docopt>=0.6.2
33
- Requires-Dist: num2words2>=0.1.0.dev0
34
- Dynamic: author
35
- Dynamic: home-page
36
- Dynamic: license
37
- Dynamic: license-file
38
- Dynamic: maintainer
18
+ Summary: Rust-powered inverse of num2words2: parse spoken-form numbers back to numeric values across 100+ languages, optimized for ASR/LLM/speech.
19
+ Keywords: number,word,numbers,words,parse,parser,convert,conversion,i18n,localisation,localization,internationalisation,internationalization,asr,speech,llm,rust
20
+ Author-email: Jean-Louis Queguiner <jean-louis.queguiner@gmail.com>
21
+ Maintainer-email: Jean-Louis Queguiner <jean-louis.queguiner@gmail.com>
22
+ License-Expression: LGPL-2.1-only
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/x-rst; charset=UTF-8
25
+ Project-URL: Bug Tracker, https://github.com/jqueguiner/words2num2/issues
26
+ Project-URL: Documentation, https://github.com/jqueguiner/words2num2/wiki
27
+ Project-URL: Homepage, https://github.com/jqueguiner/words2num2
28
+ Project-URL: Repository, https://github.com/jqueguiner/words2num2.git
39
29
 
40
30
  words2num2 — words to numbers
41
31
  =============================
@@ -105,11 +95,21 @@ entries**) and adds a free-text *auto-parse* mode that handles
105
95
  currencies, units, configurable thousands/decimal separators, and
106
96
  ASR/LLM-style mixed text.
107
97
 
98
+ It is **Rust-powered with a thin Python binder**. The whole parsing engine —
99
+ the English grammar, the generic reverse-lookup backend, the sentence walker,
100
+ number-format parsing and auto-parse — runs in a compiled Rust core
101
+ (PyO3/``abi3``); Python only shapes arguments and results. The core embeds the
102
+ num2words2 conversion engine natively, so ``words2num2`` is **self-contained
103
+ and has no runtime dependencies**, while running several times faster than the
104
+ former pure-Python implementation. Output is unchanged — validated against a
105
+ frozen corpus of ~11,000 round-trip cases.
106
+
108
107
  The project is hosted on GitHub_, and the full documentation is available
109
108
  in the Wiki_. Contributions are welcome.
110
109
 
111
110
  .. _GitHub: https://github.com/jqueguiner/words2num2
112
111
  .. _Wiki: https://github.com/jqueguiner/words2num2/wiki
112
+ .. _GitHub Releases: https://github.com/jqueguiner/words2num2/releases
113
113
 
114
114
  Why this library
115
115
  ----------------
@@ -133,13 +133,59 @@ the forward direction. ``words2num2``:
133
133
  * Pluralizes long-form units in expand mode (``5 dollars`` /
134
134
  ``1 dollar``, ``5 feet`` / ``1 foot``, ``5 yen`` / ``1 yen``).
135
135
 
136
+ Performance
137
+ -----------
138
+
139
+ The parsing engine is compiled Rust (PyO3/``abi3``), so there is no
140
+ Python-level tokenising or table walking on the hot path. Typical native
141
+ throughput (Apple M-series, nanoseconds per call, after warmup):
142
+
143
+ .. list-table::
144
+ :header-rows: 1
145
+ :widths: 60 20
146
+
147
+ * - Operation
148
+ - ns/call
149
+ * - English cardinal (``"eight thousand seven hundred sixty-five"``)
150
+ - ~5,900
151
+ * - English ordinal (``"forty-second"``)
152
+ - ~4,100
153
+ * - French cardinal (``"trois cent quatre"``)
154
+ - ~1,900
155
+ * - Russian cardinal (``"сорок два"``)
156
+ - ~1,700
157
+ * - ``parse_number_string("1.234.567,89", lang="de")``
158
+ - ~240
159
+ * - ``auto_parse("$12,345.00")``
160
+ - ~990
161
+
162
+ For the 100+ generic locales, the first call in a given language builds the
163
+ ``{words → number}`` reverse table once (~35 ms) and caches it in the core;
164
+ every call after that is a native lookup. Output is byte-for-byte identical to
165
+ the former pure-Python implementation, validated against a frozen corpus of
166
+ ~11,000 round-trip cases and the full test suite.
167
+
136
168
  Installation
137
169
  ------------
138
170
 
139
- **pip**::
171
+ **pip** (Python 3.10+)::
140
172
 
141
173
  pip install words2num2
142
174
 
175
+ That's it — the wheel bundles the Python binder and the compiled Rust
176
+ extension, and ``words2num2`` has **no runtime dependencies** (the num2words2
177
+ conversion engine is compiled in, so you do *not* need the num2words2 package).
178
+
179
+ Prebuilt wheels are published for:
180
+
181
+ * **Linux** — x86_64 and aarch64 (manylinux2014)
182
+ * **macOS** — Apple Silicon (arm64); Intel (x86_64) from a later release
183
+ * **Windows** — x86_64
184
+
185
+ On any other platform (or an older release without a matching wheel), pip
186
+ falls back to the source distribution and builds the extension locally — this
187
+ needs a **stable Rust toolchain** (`rustup <https://rustup.rs>`_); nothing else.
188
+
143
189
  **Arch Linux / Manjaro (AUR):**
144
190
 
145
191
  .. code-block:: bash
@@ -153,14 +199,15 @@ Installation
153
199
  cd python-words2num2
154
200
  makepkg -si
155
201
 
156
- **From source**::
202
+ **From source** (needs a stable Rust toolchain and `maturin
203
+ <https://www.maturin.rs>`_)::
157
204
 
158
205
  git clone https://github.com/jqueguiner/words2num2
159
206
  cd words2num2
160
- pip install -e .
207
+ pip install -e . # builds the Rust extension via maturin
208
+ # or, to produce a wheel: maturin build --release
161
209
 
162
- ``num2words2`` is a runtime dependency for the generic multi-language
163
- backend and is installed automatically.
210
+ Wheels for every version are also attached to the `GitHub Releases`_ page.
164
211
 
165
212
  Quickstart
166
213
  ----------
@@ -397,3 +444,4 @@ License
397
444
  -------
398
445
 
399
446
  LGPL-2.1, mirroring ``num2words2``. See `COPYING`.
447
+
@@ -1,42 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: words2num2
3
- Version: 0.3.0.dev2
4
- Summary: Inverse of num2words2: convert spoken-form numbers back to numeric values across 100+ languages.
5
- Home-page: https://github.com/jqueguiner/words2num2
6
- Author: Jean-Louis Queguiner
7
- Author-email: Jean-Louis Queguiner <jlqueguiner@gladia.io>
8
- Maintainer: Jean-Louis Queguiner
9
- Maintainer-email: Jean-Louis Queguiner <jlqueguiner@gladia.io>
10
- License: LGPL-2.1
11
- Project-URL: Homepage, https://github.com/jqueguiner/words2num2
12
- Project-URL: Documentation, https://github.com/jqueguiner/words2num2/wiki
13
- Project-URL: Repository, https://github.com/jqueguiner/words2num2.git
14
- Project-URL: Bug Tracker, https://github.com/jqueguiner/words2num2/issues
15
- Keywords: number,word,numbers,words,parse,parser,convert,conversion,i18n,localisation,localization,internationalisation,internationalization,asr,speech,llm
16
- Classifier: Development Status :: 4 - Beta
17
- Classifier: Intended Audience :: Developers
18
- Classifier: Programming Language :: Python :: 3
19
- Classifier: Programming Language :: Python :: 3.10
20
- Classifier: Programming Language :: Python :: 3.11
21
- Classifier: Programming Language :: Python :: 3.12
22
- Classifier: Programming Language :: Python :: 3.13
23
- Classifier: Programming Language :: Python :: 3.14
24
- Classifier: Programming Language :: Python :: 3.15
25
- Classifier: Topic :: Software Development :: Internationalization
26
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
- Classifier: Topic :: Software Development :: Localization
28
- Classifier: Topic :: Text Processing :: Linguistic
29
- Requires-Python: >=3.10
30
- Description-Content-Type: text/x-rst
31
- License-File: COPYING
32
- Requires-Dist: docopt>=0.6.2
33
- Requires-Dist: num2words2>=0.1.0.dev0
34
- Dynamic: author
35
- Dynamic: home-page
36
- Dynamic: license
37
- Dynamic: license-file
38
- Dynamic: maintainer
39
-
40
1
  words2num2 — words to numbers
41
2
  =============================
42
3
 
@@ -105,11 +66,21 @@ entries**) and adds a free-text *auto-parse* mode that handles
105
66
  currencies, units, configurable thousands/decimal separators, and
106
67
  ASR/LLM-style mixed text.
107
68
 
69
+ It is **Rust-powered with a thin Python binder**. The whole parsing engine —
70
+ the English grammar, the generic reverse-lookup backend, the sentence walker,
71
+ number-format parsing and auto-parse — runs in a compiled Rust core
72
+ (PyO3/``abi3``); Python only shapes arguments and results. The core embeds the
73
+ num2words2 conversion engine natively, so ``words2num2`` is **self-contained
74
+ and has no runtime dependencies**, while running several times faster than the
75
+ former pure-Python implementation. Output is unchanged — validated against a
76
+ frozen corpus of ~11,000 round-trip cases.
77
+
108
78
  The project is hosted on GitHub_, and the full documentation is available
109
79
  in the Wiki_. Contributions are welcome.
110
80
 
111
81
  .. _GitHub: https://github.com/jqueguiner/words2num2
112
82
  .. _Wiki: https://github.com/jqueguiner/words2num2/wiki
83
+ .. _GitHub Releases: https://github.com/jqueguiner/words2num2/releases
113
84
 
114
85
  Why this library
115
86
  ----------------
@@ -133,13 +104,59 @@ the forward direction. ``words2num2``:
133
104
  * Pluralizes long-form units in expand mode (``5 dollars`` /
134
105
  ``1 dollar``, ``5 feet`` / ``1 foot``, ``5 yen`` / ``1 yen``).
135
106
 
107
+ Performance
108
+ -----------
109
+
110
+ The parsing engine is compiled Rust (PyO3/``abi3``), so there is no
111
+ Python-level tokenising or table walking on the hot path. Typical native
112
+ throughput (Apple M-series, nanoseconds per call, after warmup):
113
+
114
+ .. list-table::
115
+ :header-rows: 1
116
+ :widths: 60 20
117
+
118
+ * - Operation
119
+ - ns/call
120
+ * - English cardinal (``"eight thousand seven hundred sixty-five"``)
121
+ - ~5,900
122
+ * - English ordinal (``"forty-second"``)
123
+ - ~4,100
124
+ * - French cardinal (``"trois cent quatre"``)
125
+ - ~1,900
126
+ * - Russian cardinal (``"сорок два"``)
127
+ - ~1,700
128
+ * - ``parse_number_string("1.234.567,89", lang="de")``
129
+ - ~240
130
+ * - ``auto_parse("$12,345.00")``
131
+ - ~990
132
+
133
+ For the 100+ generic locales, the first call in a given language builds the
134
+ ``{words → number}`` reverse table once (~35 ms) and caches it in the core;
135
+ every call after that is a native lookup. Output is byte-for-byte identical to
136
+ the former pure-Python implementation, validated against a frozen corpus of
137
+ ~11,000 round-trip cases and the full test suite.
138
+
136
139
  Installation
137
140
  ------------
138
141
 
139
- **pip**::
142
+ **pip** (Python 3.10+)::
140
143
 
141
144
  pip install words2num2
142
145
 
146
+ That's it — the wheel bundles the Python binder and the compiled Rust
147
+ extension, and ``words2num2`` has **no runtime dependencies** (the num2words2
148
+ conversion engine is compiled in, so you do *not* need the num2words2 package).
149
+
150
+ Prebuilt wheels are published for:
151
+
152
+ * **Linux** — x86_64 and aarch64 (manylinux2014)
153
+ * **macOS** — Apple Silicon (arm64); Intel (x86_64) from a later release
154
+ * **Windows** — x86_64
155
+
156
+ On any other platform (or an older release without a matching wheel), pip
157
+ falls back to the source distribution and builds the extension locally — this
158
+ needs a **stable Rust toolchain** (`rustup <https://rustup.rs>`_); nothing else.
159
+
143
160
  **Arch Linux / Manjaro (AUR):**
144
161
 
145
162
  .. code-block:: bash
@@ -153,14 +170,15 @@ Installation
153
170
  cd python-words2num2
154
171
  makepkg -si
155
172
 
156
- **From source**::
173
+ **From source** (needs a stable Rust toolchain and `maturin
174
+ <https://www.maturin.rs>`_)::
157
175
 
158
176
  git clone https://github.com/jqueguiner/words2num2
159
177
  cd words2num2
160
- pip install -e .
178
+ pip install -e . # builds the Rust extension via maturin
179
+ # or, to produce a wheel: maturin build --release
161
180
 
162
- ``num2words2`` is a runtime dependency for the generic multi-language
163
- backend and is installed automatically.
181
+ Wheels for every version are also attached to the `GitHub Releases`_ page.
164
182
 
165
183
  Quickstart
166
184
  ----------
@@ -0,0 +1,94 @@
1
+ [build-system]
2
+ requires = ["maturin>=1.5,<2.0"]
3
+ build-backend = "maturin"
4
+
5
+ [project]
6
+ name = "words2num2"
7
+ # Static base version. The release CI overrides it from the pushed git tag
8
+ # (see .github/workflows/release.yml); bump here for local source builds.
9
+ version = "0.3.1"
10
+ license = "LGPL-2.1-only"
11
+ license-files = ["COPYING"]
12
+ description = "Rust-powered inverse of num2words2: parse spoken-form numbers back to numeric values across 100+ languages, optimized for ASR/LLM/speech."
13
+ readme = "README.rst"
14
+ requires-python = ">=3.10"
15
+ # Self-contained: the num2words2 conversion engine is embedded in the compiled
16
+ # core (num2words2-core), so there is no runtime dependency on the num2words2
17
+ # package and no docopt (the CLI uses only the standard library).
18
+ dependencies = []
19
+ authors = [
20
+ {name = "Jean-Louis Queguiner", email = "jean-louis.queguiner@gmail.com"}
21
+ ]
22
+ maintainers = [
23
+ {name = "Jean-Louis Queguiner", email = "jean-louis.queguiner@gmail.com"}
24
+ ]
25
+ keywords = ["number", "word", "numbers", "words", "parse", "parser", "convert",
26
+ "conversion", "i18n", "localisation", "localization",
27
+ "internationalisation", "internationalization", "asr", "speech",
28
+ "llm", "rust"]
29
+ classifiers = [
30
+ "Development Status :: 4 - Beta",
31
+ "Intended Audience :: Developers",
32
+ "Programming Language :: Python :: 3",
33
+ "Programming Language :: Python :: 3.10",
34
+ "Programming Language :: Python :: 3.11",
35
+ "Programming Language :: Python :: 3.12",
36
+ "Programming Language :: Python :: 3.13",
37
+ "Programming Language :: Python :: 3.14",
38
+ "Programming Language :: Rust",
39
+ "Topic :: Software Development :: Internationalization",
40
+ "Topic :: Software Development :: Libraries :: Python Modules",
41
+ "Topic :: Software Development :: Localization",
42
+ "Topic :: Text Processing :: Linguistic",
43
+ ]
44
+
45
+ [project.urls]
46
+ Homepage = "https://github.com/jqueguiner/words2num2"
47
+ Documentation = "https://github.com/jqueguiner/words2num2/wiki"
48
+ Repository = "https://github.com/jqueguiner/words2num2.git"
49
+ "Bug Tracker" = "https://github.com/jqueguiner/words2num2/issues"
50
+
51
+ [project.scripts]
52
+ words2num2 = "words2num2.__main__:main"
53
+
54
+ # ---- maturin: mixed Rust/Python project -------------------------------------
55
+ # The compiled engine lives in ./rust (vendored crates `words2num2-py`, lib
56
+ # `_rust`, plus its `num2words2-core` dependency); the thin Python binder is
57
+ # ./words2num2. maturin bundles both into a single per-platform wheel. The
58
+ # wheel embeds num2words2-core natively — no lingua-rs models, so it stays
59
+ # small (~4MB), and there is only one variant.
60
+ [tool.maturin]
61
+ manifest-path = "rust/words2num2-py/Cargo.toml"
62
+ python-source = "."
63
+ module-name = "words2num2._rust"
64
+ features = ["pyo3/extension-module"]
65
+ strip = true
66
+
67
+ [tool.isort]
68
+ profile = "black"
69
+ line_length = 88
70
+ skip = ["words2num2/_version.py"]
71
+ multi_line_output = 3
72
+ include_trailing_comma = true
73
+ force_grid_wrap = 0
74
+ use_parentheses = true
75
+ ensure_newline_before_comments = true
76
+
77
+ [tool.black]
78
+ line-length = 88
79
+ target-version = ['py310']
80
+ include = '\.pyi?$'
81
+ exclude = '''
82
+ /(
83
+ \.git
84
+ | \.hg
85
+ | \.mypy_cache
86
+ | \.tox
87
+ | \.venv
88
+ | _build
89
+ | buck-out
90
+ | build
91
+ | dist
92
+ | words2num2/_version.py
93
+ )/
94
+ '''
@@ -0,0 +1,287 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "autocfg"
7
+ version = "1.5.1"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
10
+
11
+ [[package]]
12
+ name = "bigdecimal"
13
+ version = "0.4.10"
14
+ source = "registry+https://github.com/rust-lang/crates.io-index"
15
+ checksum = "4d6867f1565b3aad85681f1015055b087fcfd840d6aeee6eee7f2da317603695"
16
+ dependencies = [
17
+ "autocfg",
18
+ "libm",
19
+ "num-bigint",
20
+ "num-integer",
21
+ "num-traits",
22
+ ]
23
+
24
+ [[package]]
25
+ name = "cfg-if"
26
+ version = "1.0.4"
27
+ source = "registry+https://github.com/rust-lang/crates.io-index"
28
+ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
29
+
30
+ [[package]]
31
+ name = "heck"
32
+ version = "0.5.0"
33
+ source = "registry+https://github.com/rust-lang/crates.io-index"
34
+ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
35
+
36
+ [[package]]
37
+ name = "indoc"
38
+ version = "2.0.7"
39
+ source = "registry+https://github.com/rust-lang/crates.io-index"
40
+ checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
41
+ dependencies = [
42
+ "rustversion",
43
+ ]
44
+
45
+ [[package]]
46
+ name = "libc"
47
+ version = "0.2.186"
48
+ source = "registry+https://github.com/rust-lang/crates.io-index"
49
+ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
50
+
51
+ [[package]]
52
+ name = "libm"
53
+ version = "0.2.16"
54
+ source = "registry+https://github.com/rust-lang/crates.io-index"
55
+ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
56
+
57
+ [[package]]
58
+ name = "memoffset"
59
+ version = "0.9.1"
60
+ source = "registry+https://github.com/rust-lang/crates.io-index"
61
+ checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
62
+ dependencies = [
63
+ "autocfg",
64
+ ]
65
+
66
+ [[package]]
67
+ name = "num-bigint"
68
+ version = "0.4.8"
69
+ source = "registry+https://github.com/rust-lang/crates.io-index"
70
+ checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367"
71
+ dependencies = [
72
+ "num-integer",
73
+ "num-traits",
74
+ ]
75
+
76
+ [[package]]
77
+ name = "num-integer"
78
+ version = "0.1.46"
79
+ source = "registry+https://github.com/rust-lang/crates.io-index"
80
+ checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
81
+ dependencies = [
82
+ "num-traits",
83
+ ]
84
+
85
+ [[package]]
86
+ name = "num-traits"
87
+ version = "0.2.19"
88
+ source = "registry+https://github.com/rust-lang/crates.io-index"
89
+ checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
90
+ dependencies = [
91
+ "autocfg",
92
+ ]
93
+
94
+ [[package]]
95
+ name = "num2words2-core"
96
+ version = "0.1.0"
97
+ source = "registry+https://github.com/rust-lang/crates.io-index"
98
+ checksum = "ebe0abf28292c2d0302b42402ecd56b8cda2487d0d764422c2ee754e5ca7f31d"
99
+ dependencies = [
100
+ "bigdecimal",
101
+ "num-bigint",
102
+ "num-integer",
103
+ "num-traits",
104
+ ]
105
+
106
+ [[package]]
107
+ name = "num2words2-core"
108
+ version = "0.1.1"
109
+ dependencies = [
110
+ "bigdecimal",
111
+ "num-bigint",
112
+ "num-integer",
113
+ "num-traits",
114
+ ]
115
+
116
+ [[package]]
117
+ name = "once_cell"
118
+ version = "1.21.4"
119
+ source = "registry+https://github.com/rust-lang/crates.io-index"
120
+ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
121
+
122
+ [[package]]
123
+ name = "portable-atomic"
124
+ version = "1.13.1"
125
+ source = "registry+https://github.com/rust-lang/crates.io-index"
126
+ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
127
+
128
+ [[package]]
129
+ name = "proc-macro2"
130
+ version = "1.0.106"
131
+ source = "registry+https://github.com/rust-lang/crates.io-index"
132
+ checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
133
+ dependencies = [
134
+ "unicode-ident",
135
+ ]
136
+
137
+ [[package]]
138
+ name = "pyo3"
139
+ version = "0.23.5"
140
+ source = "registry+https://github.com/rust-lang/crates.io-index"
141
+ checksum = "7778bffd85cf38175ac1f545509665d0b9b92a198ca7941f131f85f7a4f9a872"
142
+ dependencies = [
143
+ "cfg-if",
144
+ "indoc",
145
+ "libc",
146
+ "memoffset",
147
+ "num-bigint",
148
+ "once_cell",
149
+ "portable-atomic",
150
+ "pyo3-build-config",
151
+ "pyo3-ffi",
152
+ "pyo3-macros",
153
+ "unindent",
154
+ ]
155
+
156
+ [[package]]
157
+ name = "pyo3-build-config"
158
+ version = "0.23.5"
159
+ source = "registry+https://github.com/rust-lang/crates.io-index"
160
+ checksum = "94f6cbe86ef3bf18998d9df6e0f3fc1050a8c5efa409bf712e661a4366e010fb"
161
+ dependencies = [
162
+ "once_cell",
163
+ "target-lexicon",
164
+ ]
165
+
166
+ [[package]]
167
+ name = "pyo3-ffi"
168
+ version = "0.23.5"
169
+ source = "registry+https://github.com/rust-lang/crates.io-index"
170
+ checksum = "e9f1b4c431c0bb1c8fb0a338709859eed0d030ff6daa34368d3b152a63dfdd8d"
171
+ dependencies = [
172
+ "libc",
173
+ "pyo3-build-config",
174
+ ]
175
+
176
+ [[package]]
177
+ name = "pyo3-macros"
178
+ version = "0.23.5"
179
+ source = "registry+https://github.com/rust-lang/crates.io-index"
180
+ checksum = "fbc2201328f63c4710f68abdf653c89d8dbc2858b88c5d88b0ff38a75288a9da"
181
+ dependencies = [
182
+ "proc-macro2",
183
+ "pyo3-macros-backend",
184
+ "quote",
185
+ "syn",
186
+ ]
187
+
188
+ [[package]]
189
+ name = "pyo3-macros-backend"
190
+ version = "0.23.5"
191
+ source = "registry+https://github.com/rust-lang/crates.io-index"
192
+ checksum = "fca6726ad0f3da9c9de093d6f116a93c1a38e417ed73bf138472cf4064f72028"
193
+ dependencies = [
194
+ "heck",
195
+ "proc-macro2",
196
+ "pyo3-build-config",
197
+ "quote",
198
+ "syn",
199
+ ]
200
+
201
+ [[package]]
202
+ name = "quote"
203
+ version = "1.0.46"
204
+ source = "registry+https://github.com/rust-lang/crates.io-index"
205
+ checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
206
+ dependencies = [
207
+ "proc-macro2",
208
+ ]
209
+
210
+ [[package]]
211
+ name = "rustversion"
212
+ version = "1.0.23"
213
+ source = "registry+https://github.com/rust-lang/crates.io-index"
214
+ checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
215
+
216
+ [[package]]
217
+ name = "syn"
218
+ version = "2.0.119"
219
+ source = "registry+https://github.com/rust-lang/crates.io-index"
220
+ checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
221
+ dependencies = [
222
+ "proc-macro2",
223
+ "quote",
224
+ "unicode-ident",
225
+ ]
226
+
227
+ [[package]]
228
+ name = "target-lexicon"
229
+ version = "0.12.16"
230
+ source = "registry+https://github.com/rust-lang/crates.io-index"
231
+ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
232
+
233
+ [[package]]
234
+ name = "tinyvec"
235
+ version = "1.12.0"
236
+ source = "registry+https://github.com/rust-lang/crates.io-index"
237
+ checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f"
238
+ dependencies = [
239
+ "tinyvec_macros",
240
+ ]
241
+
242
+ [[package]]
243
+ name = "tinyvec_macros"
244
+ version = "0.1.1"
245
+ source = "registry+https://github.com/rust-lang/crates.io-index"
246
+ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
247
+
248
+ [[package]]
249
+ name = "unicode-ident"
250
+ version = "1.0.24"
251
+ source = "registry+https://github.com/rust-lang/crates.io-index"
252
+ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
253
+
254
+ [[package]]
255
+ name = "unicode-normalization"
256
+ version = "0.1.25"
257
+ source = "registry+https://github.com/rust-lang/crates.io-index"
258
+ checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8"
259
+ dependencies = [
260
+ "tinyvec",
261
+ ]
262
+
263
+ [[package]]
264
+ name = "unindent"
265
+ version = "0.2.4"
266
+ source = "registry+https://github.com/rust-lang/crates.io-index"
267
+ checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
268
+
269
+ [[package]]
270
+ name = "words2num2-core"
271
+ version = "0.1.1"
272
+ dependencies = [
273
+ "bigdecimal",
274
+ "num-bigint",
275
+ "num2words2-core 0.1.0",
276
+ "unicode-normalization",
277
+ ]
278
+
279
+ [[package]]
280
+ name = "words2num2-py"
281
+ version = "0.1.1"
282
+ dependencies = [
283
+ "bigdecimal",
284
+ "num-bigint",
285
+ "pyo3",
286
+ "words2num2-core",
287
+ ]