Skip to content

Commit 2fdcdb3

Browse files
committed
Make functions private and deprecate public aliases in i18n module
Prior to this change, the `Unit` enum and the `abs_timedelta` and `date_and_delta` functions were listed as public functions in the documentation but were not available from the root package: >>> import humanize >>> humanize.gettext Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: module 'humanize' has no attribute 'gettext' >>> humanize.ngettext Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: module 'humanize' has no attribute 'ngettext' This change makes these members private. In order to preserve backwards compatibility after this change, we provide aliases for these members which emit deprecation warnings.
1 parent 2482af7 commit 2fdcdb3

3 files changed

Lines changed: 153 additions & 30 deletions

File tree

src/humanize/i18n.py

Lines changed: 132 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Activate, get and deactivate translations."""
22
import gettext as gettext_module
33
import os.path
4+
import warnings
45
from threading import local
56

67
__all__ = ["activate", "deactivate", "gettext", "ngettext", "thousands_separator"]
@@ -66,7 +67,7 @@ def deactivate():
6667
_CURRENT.locale = None
6768

6869

69-
def gettext(message):
70+
def _gettext(message):
7071
"""Get translation.
7172
7273
Args:
@@ -78,7 +79,27 @@ def gettext(message):
7879
return get_translation().gettext(message)
7980

8081

81-
def pgettext(msgctxt, message):
82+
def gettext(message):
83+
"""Get translation.
84+
85+
Args:
86+
message (str): Text to translate.
87+
88+
Returns:
89+
str: Translated text.
90+
91+
WARNING: This function has been deprecated. It is still available as the private
92+
member `_gettext`.
93+
"""
94+
warnings.warn(
95+
"`gettext` has been deprecated. "
96+
"It is still available as the private member `_gettext`.",
97+
DeprecationWarning,
98+
)
99+
return _gettext(message)
100+
101+
102+
def _pgettext(msgctxt, message):
82103
"""Fetches a particular translation.
83104
84105
It works with `msgctxt` .po modifiers and allows duplicate keys with different
@@ -103,8 +124,32 @@ def pgettext(msgctxt, message):
103124
return message if translation == key else translation
104125

105126

106-
def ngettext(message, plural, num):
107-
"""Plural version of gettext.
127+
def pgettext(msgctxt, message):
128+
"""Fetches a particular translation.
129+
130+
It works with `msgctxt` .po modifiers and allows duplicate keys with different
131+
translations.
132+
133+
Args:
134+
msgctxt (str): Context of the translation.
135+
message (str): Text to translate.
136+
137+
Returns:
138+
str: Translated text.
139+
140+
WARNING: This function has been deprecated. It is still available as the private
141+
member `_pgettext`.
142+
"""
143+
warnings.warn(
144+
"`pgettext` has been deprecated. "
145+
"It is still available as the private member `_pgettext`.",
146+
DeprecationWarning,
147+
)
148+
return _pgettext(msgctxt, message)
149+
150+
151+
def _ngettext(message, plural, num):
152+
"""Plural version of _gettext.
108153
109154
Args:
110155
message (str): Singular text to translate.
@@ -118,14 +163,37 @@ def ngettext(message, plural, num):
118163
return get_translation().ngettext(message, plural, num)
119164

120165

121-
def gettext_noop(message):
166+
def ngettext(msgctxt, message):
167+
"""Plural version of gettext.
168+
169+
Args:
170+
message (str): Singular text to translate.
171+
plural (str): Plural text to translate.
172+
num (str): The number (e.g. item count) to determine translation for the
173+
respective grammatical number.
174+
175+
Returns:
176+
str: Translated text.
177+
178+
WARNING: This function has been deprecated. It is still available as the private
179+
member `_ngettext`.
180+
"""
181+
warnings.warn(
182+
"`ngettext` has been deprecated. "
183+
"It is still available as the private member `_ngettext`.",
184+
DeprecationWarning,
185+
)
186+
return _ngettext(msgctxt, message)
187+
188+
189+
def _gettext_noop(message):
122190
"""Mark a string as a translation string without translating it.
123191
124192
Example usage:
125193
```python
126-
CONSTANTS = [gettext_noop('first'), gettext_noop('second')]
194+
CONSTANTS = [_gettext_noop('first'), _gettext_noop('second')]
127195
def num_name(n):
128-
return gettext(CONSTANTS[n])
196+
return _gettext(CONSTANTS[n])
129197
```
130198
131199
Args:
@@ -137,14 +205,41 @@ def num_name(n):
137205
return message
138206

139207

140-
def ngettext_noop(singular, plural):
208+
def gettext_noop(message):
209+
"""Mark a string as a translation string without translating it.
210+
211+
Example usage:
212+
```python
213+
CONSTANTS = [_gettext_noop('first'), _gettext_noop('second')]
214+
def num_name(n):
215+
return _gettext(CONSTANTS[n])
216+
```
217+
218+
Args:
219+
message (str): Text to translate in the future.
220+
221+
Returns:
222+
str: Original text, unchanged.
223+
224+
WARNING: This function has been deprecated. It is still available as the private
225+
member `_gettext_noop`.
226+
"""
227+
warnings.warn(
228+
"`gettext_noop` has been deprecated. "
229+
"It is still available as the private member `_gettext_noop`.",
230+
DeprecationWarning,
231+
)
232+
return _gettext_noop(message)
233+
234+
235+
def _ngettext_noop(singular, plural):
141236
"""Mark two strings as pluralized translations without translating them.
142237
143238
Example usage:
144239
```python
145240
CONSTANTS = [ngettext_noop('first', 'firsts'), ngettext_noop('second', 'seconds')]
146241
def num_name(n):
147-
return ngettext(*CONSTANTS[n])
242+
return _ngettext(*CONSTANTS[n])
148243
```
149244
150245
Args:
@@ -157,6 +252,34 @@ def num_name(n):
157252
return (singular, plural)
158253

159254

255+
def ngettext_noop(singular, plural):
256+
"""Mark two strings as pluralized translations without translating them.
257+
258+
Example usage:
259+
```python
260+
CONSTANTS = [ngettext_noop('first', 'firsts'), ngettext_noop('second', 'seconds')]
261+
def num_name(n):
262+
return _ngettext(*CONSTANTS[n])
263+
```
264+
265+
Args:
266+
singular (str): Singular text to translate in the future.
267+
plural (str): Plural text to translate in the future.
268+
269+
Returns:
270+
tuple: Original text, unchanged.
271+
272+
WARNING: This function has been deprecated. It is still available as the private
273+
member `_ngettext_noop`.
274+
"""
275+
warnings.warn(
276+
"`ngettext_noop` has been deprecated. "
277+
"It is still available as the private member `_ngettext_noop`.",
278+
DeprecationWarning,
279+
)
280+
return _ngettext_noop(singular, plural)
281+
282+
160283
def thousands_separator() -> str:
161284
"""Return the thousands separator for a locale, default to comma.
162285

src/humanize/number.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
import re
77
from fractions import Fraction
88

9-
from .i18n import gettext as _
10-
from .i18n import ngettext
11-
from .i18n import ngettext_noop as NS_
12-
from .i18n import pgettext as P_
9+
from .i18n import _gettext as _
10+
from .i18n import _ngettext
11+
from .i18n import _ngettext_noop as NS_
12+
from .i18n import _pgettext as P_
1313
from .i18n import thousands_separator
1414

1515

@@ -201,12 +201,12 @@ def intword(value, format="%.1f"):
201201
chopped = value / float(powers[ordinal])
202202
singular, plural = human_powers[ordinal]
203203
return (
204-
" ".join([format, ngettext(singular, plural, math.ceil(chopped))])
204+
" ".join([format, _ngettext(singular, plural, math.ceil(chopped))])
205205
) % chopped
206206
else:
207207
singular, plural = human_powers[ordinal - 1]
208208
return (
209-
" ".join([format, ngettext(singular, plural, math.ceil(chopped))])
209+
" ".join([format, _ngettext(singular, plural, math.ceil(chopped))])
210210
) % chopped
211211
return str(value)
212212

src/humanize/time.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
from enum import Enum, EnumMeta
1212
from functools import total_ordering
1313

14-
from .i18n import gettext as _
15-
from .i18n import ngettext
14+
from .i18n import _gettext as _
15+
from .i18n import _ngettext
1616

1717
__all__ = [
1818
"naturaldelta",
@@ -209,7 +209,7 @@ def naturaldelta(
209209
if seconds == 0:
210210
if minimum_unit == _Unit.MICROSECONDS and delta.microseconds < 1000:
211211
return (
212-
ngettext("%d microsecond", "%d microseconds", delta.microseconds)
212+
_ngettext("%d microsecond", "%d microseconds", delta.microseconds)
213213
% delta.microseconds
214214
)
215215
elif minimum_unit == _Unit.MILLISECONDS or (
@@ -218,52 +218,52 @@ def naturaldelta(
218218
):
219219
milliseconds = delta.microseconds / 1000
220220
return (
221-
ngettext("%d millisecond", "%d milliseconds", milliseconds)
221+
_ngettext("%d millisecond", "%d milliseconds", milliseconds)
222222
% milliseconds
223223
)
224224
return _("a moment")
225225
elif seconds == 1:
226226
return _("a second")
227227
elif seconds < 60:
228-
return ngettext("%d second", "%d seconds", seconds) % seconds
228+
return _ngettext("%d second", "%d seconds", seconds) % seconds
229229
elif 60 <= seconds < 120:
230230
return _("a minute")
231231
elif 120 <= seconds < 3600:
232232
minutes = seconds // 60
233-
return ngettext("%d minute", "%d minutes", minutes) % minutes
233+
return _ngettext("%d minute", "%d minutes", minutes) % minutes
234234
elif 3600 <= seconds < 3600 * 2:
235235
return _("an hour")
236236
elif 3600 < seconds:
237237
hours = seconds // 3600
238-
return ngettext("%d hour", "%d hours", hours) % hours
238+
return _ngettext("%d hour", "%d hours", hours) % hours
239239
elif years == 0:
240240
if days == 1:
241241
return _("a day")
242242
if not use_months:
243-
return ngettext("%d day", "%d days", days) % days
243+
return _ngettext("%d day", "%d days", days) % days
244244
else:
245245
if not months:
246-
return ngettext("%d day", "%d days", days) % days
246+
return _ngettext("%d day", "%d days", days) % days
247247
elif months == 1:
248248
return _("a month")
249249
else:
250-
return ngettext("%d month", "%d months", months) % months
250+
return _ngettext("%d month", "%d months", months) % months
251251
elif years == 1:
252252
if not months and not days:
253253
return _("a year")
254254
elif not months:
255-
return ngettext("1 year, %d day", "1 year, %d days", days) % days
255+
return _ngettext("1 year, %d day", "1 year, %d days", days) % days
256256
elif use_months:
257257
if months == 1:
258258
return _("1 year, 1 month")
259259
else:
260260
return (
261-
ngettext("1 year, %d month", "1 year, %d months", months) % months
261+
_ngettext("1 year, %d month", "1 year, %d months", months) % months
262262
)
263263
else:
264-
return ngettext("1 year, %d day", "1 year, %d days", days) % days
264+
return _ngettext("1 year, %d day", "1 year, %d days", days) % days
265265
else:
266-
return ngettext("%d year", "%d years", years) % years
266+
return _ngettext("%d year", "%d years", years) % years
267267

268268

269269
def naturaltime(
@@ -601,7 +601,7 @@ def precisedelta(value, minimum_unit="seconds", suppress=(), format="%0.2f") ->
601601
for unit, fmt in zip(reversed(_Unit), fmts):
602602
singular_txt, plural_txt, value = fmt
603603
if value > 0 or (not texts and unit == min_unit):
604-
fmt_txt = ngettext(singular_txt, plural_txt, value)
604+
fmt_txt = _ngettext(singular_txt, plural_txt, value)
605605
if unit == min_unit and math.modf(value)[0] > 0:
606606
fmt_txt = fmt_txt.replace("%d", format)
607607

0 commit comments

Comments
 (0)