1212import decimal
1313import re
1414from collections .abc import Iterable , Mapping
15- from typing import Any
15+ from typing import TYPE_CHECKING , Any , Callable
1616
1717if TYPE_CHECKING :
1818 from typing_extensions import Literal
@@ -111,7 +111,7 @@ def __init__(self, rules: Mapping[str, str] | Iterable[tuple[str, str]]):
111111 and expressions as values.
112112 :raise RuleError: if the expression is malformed
113113 """
114- if isinstance (rules , dict ):
114+ if isinstance (rules , Mapping ):
115115 rules = rules .items ()
116116 found = set ()
117117 self .abstract : list [tuple [str , Any ]] = []
@@ -173,7 +173,7 @@ def __call__(self, n: float | decimal.Decimal) -> str:
173173 return self ._func (n )
174174
175175
176- def to_javascript (rule ) :
176+ def to_javascript (rule : Mapping [ str , str ] | Iterable [ tuple [ str , str ]] | PluralRule ) -> str :
177177 """Convert a list/dict of rules or a `PluralRule` object into a JavaScript
178178 function. This function depends on no external library:
179179
@@ -196,7 +196,7 @@ def to_javascript(rule):
196196 return '' .join (result )
197197
198198
199- def to_python (rule ) :
199+ def to_python (rule : Mapping [ str , str ] | Iterable [ tuple [ str , str ]] | PluralRule ) -> Callable [[ float | decimal . Decimal ], str ] :
200200 """Convert a list/dict of rules or a `PluralRule` object into a regular
201201 Python function. This is useful in situations where you need a real
202202 function and don't are about the actual rule object:
@@ -236,7 +236,7 @@ def to_python(rule):
236236 return namespace ['evaluate' ]
237237
238238
239- def to_gettext (rule ) :
239+ def to_gettext (rule : Mapping [ str , str ] | Iterable [ tuple [ str , str ]] | PluralRule ) -> str :
240240 """The plural rule as gettext expression. The gettext expression is
241241 technically limited to integers and returns indices rather than tags.
242242
@@ -259,7 +259,7 @@ def to_gettext(rule):
259259 return '' .join (result )
260260
261261
262- def in_range_list (num , range_list ) :
262+ def in_range_list (num : float | decimal . Decimal , range_list : Iterable [ Iterable [ float | decimal . Decimal ]]) -> bool :
263263 """Integer range list test. This is the callback for the "in" operator
264264 of the UTS #35 pluralization rule language:
265265
@@ -279,7 +279,7 @@ def in_range_list(num, range_list):
279279 return num == int (num ) and within_range_list (num , range_list )
280280
281281
282- def within_range_list (num , range_list ) :
282+ def within_range_list (num : float | decimal . Decimal , range_list : Iterable [ Iterable [ float | decimal . Decimal ]]) -> bool :
283283 """Float range test. This is the callback for the "within" operator
284284 of the UTS #35 pluralization rule language:
285285
@@ -299,7 +299,7 @@ def within_range_list(num, range_list):
299299 return any (num >= min_ and num <= max_ for min_ , max_ in range_list )
300300
301301
302- def cldr_modulo (a , b ) :
302+ def cldr_modulo (a : float , b : float ) -> float :
303303 """Javaish modulo. This modulo operator returns the value with the sign
304304 of the dividend rather than the divisor like Python does:
305305
@@ -336,7 +336,7 @@ class RuleError(Exception):
336336 'e' , # currently, synonym for ‘c’. however, may be redefined in the future.
337337}
338338
339- _RULES = [
339+ _RULES : list [ tuple [ str | None , re . Pattern [ str ]]] = [
340340 (None , re .compile (r'\s+' , re .UNICODE )),
341341 ('word' , re .compile (fr'\b(and|or|is|(?:with)?in|not|mod|[{ "" .join (_VARS )} ])\b' )),
342342 ('value' , re .compile (r'\d+' )),
@@ -345,9 +345,9 @@ class RuleError(Exception):
345345]
346346
347347
348- def tokenize_rule (s ) :
348+ def tokenize_rule (s : str ) -> list [ tuple [ str , str ]] :
349349 s = s .split ('@' )[0 ]
350- result = []
350+ result : list [ tuple [ str , str ]] = []
351351 pos = 0
352352 end = len (s )
353353 while pos < end :
@@ -363,30 +363,29 @@ def tokenize_rule(s):
363363 'Got unexpected %r' % s [pos ])
364364 return result [::- 1 ]
365365
366-
367- def test_next_token (tokens , type_ , value = None ):
366+ def test_next_token (tokens : list [tuple [str , str ]], type_ : str , value : str | None = None ) -> list [tuple [str , str ]] | bool :
368367 return tokens and tokens [- 1 ][0 ] == type_ and \
369368 (value is None or tokens [- 1 ][1 ] == value )
370369
371370
372- def skip_token (tokens , type_ , value = None ):
371+ def skip_token (tokens : list [ tuple [ str , str ]], type_ : str , value : str | None = None ):
373372 if test_next_token (tokens , type_ , value ):
374373 return tokens .pop ()
375374
376375
377- def value_node (value ) :
376+ def value_node (value : int ) -> tuple [ Literal [ 'value' ], tuple [ int ]] :
378377 return 'value' , (value , )
379378
380379
381- def ident_node (name ) :
380+ def ident_node (name : str ) -> tuple [ str , tuple [()]] :
382381 return name , ()
383382
384383
385- def range_list_node (range_list ) :
384+ def range_list_node (range_list : Iterable [ Iterable [ float | decimal . Decimal ]]) -> tuple [ Literal [ 'range_list' ], Iterable [ Iterable [ float | decimal . Decimal ]]] :
386385 return 'range_list' , range_list
387386
388387
389- def negate (rv ) :
388+ def negate (rv : tuple [ Any , ...]) -> tuple [ Literal [ 'not' ], tuple [ tuple [ Any , ...]]] :
390389 return 'not' , (rv ,)
391390
392391
0 commit comments