types-bits 0.1.0__py3-none-any.whl
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.
- types_bits/__init__.py +25 -0
- types_bits/__init__.pyi +27 -0
- types_bits/__main__.py +39 -0
- types_bits/_generate.py +216 -0
- types_bits/_spec.py +6 -0
- types_bits/py.typed +0 -0
- types_bits-0.1.0.dist-info/METADATA +222 -0
- types_bits-0.1.0.dist-info/RECORD +10 -0
- types_bits-0.1.0.dist-info/WHEEL +4 -0
- types_bits-0.1.0.dist-info/licenses/LICENSE +21 -0
types_bits/__init__.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Rust-style sized integer types.
|
|
2
|
+
|
|
3
|
+
``__init__.pyi`` shadows this module for type checkers; this is the runtime tier.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from types_bits._spec import MAX_BITS
|
|
7
|
+
|
|
8
|
+
__all__ = [ # pyright: ignore[reportUnsupportedDunderAll]
|
|
9
|
+
f"{prefix}{bits}" for prefix in ("u", "i") for bits in range(1, MAX_BITS + 1)
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def __getattr__(name: str) -> object:
|
|
14
|
+
if name not in __all__:
|
|
15
|
+
msg = f"module {__name__!r} has no attribute {name!r}"
|
|
16
|
+
raise AttributeError(msg)
|
|
17
|
+
|
|
18
|
+
from typing import Annotated
|
|
19
|
+
|
|
20
|
+
from annotated_types import Ge, Le
|
|
21
|
+
|
|
22
|
+
from types_bits._generate import Signed, Unsigned
|
|
23
|
+
|
|
24
|
+
width = Unsigned(int(name[1:])) if name[0] == "u" else Signed(int(name[1:]))
|
|
25
|
+
return Annotated[int, Ge(width.lo), Le(width.hi)]
|
types_bits/__init__.pyi
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Generated by types_bits._generate — do not edit.
|
|
2
|
+
# variant=flat bits=10 kind=both
|
|
3
|
+
|
|
4
|
+
from typing import Literal
|
|
5
|
+
|
|
6
|
+
__all__ = ['u1', 'u2', 'u3', 'u4', 'u5', 'u6', 'u7', 'u8', 'u9', 'u10', 'i1', 'i2', 'i3', 'i4', 'i5', 'i6', 'i7', 'i8', 'i9', 'i10']
|
|
7
|
+
|
|
8
|
+
type u1 = Literal[0, 1]
|
|
9
|
+
type u2 = Literal[0, 1, 2, 3]
|
|
10
|
+
type u3 = Literal[0, 1, 2, 3, 4, 5, 6, 7]
|
|
11
|
+
type u4 = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
|
12
|
+
type u5 = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
|
|
13
|
+
type u6 = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63]
|
|
14
|
+
type u7 = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127]
|
|
15
|
+
type u8 = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255]
|
|
16
|
+
type u9 = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511]
|
|
17
|
+
type u10 = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023]
|
|
18
|
+
type i1 = Literal[-1, 0]
|
|
19
|
+
type i2 = Literal[-2, -1, 0, 1]
|
|
20
|
+
type i3 = Literal[-4, -3, -2, -1, 0, 1, 2, 3]
|
|
21
|
+
type i4 = Literal[-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7]
|
|
22
|
+
type i5 = Literal[-16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
|
23
|
+
type i6 = Literal[-32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
|
|
24
|
+
type i7 = Literal[-64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63]
|
|
25
|
+
type i8 = Literal[-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114, -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99, -98, -97, -96, -95, -94, -93, -92, -91, -90, -89, -88, -87, -86, -85, -84, -83, -82, -81, -80, -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, -69, -68, -67, -66, -65, -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127]
|
|
26
|
+
type i9 = Literal[-256, -255, -254, -253, -252, -251, -250, -249, -248, -247, -246, -245, -244, -243, -242, -241, -240, -239, -238, -237, -236, -235, -234, -233, -232, -231, -230, -229, -228, -227, -226, -225, -224, -223, -222, -221, -220, -219, -218, -217, -216, -215, -214, -213, -212, -211, -210, -209, -208, -207, -206, -205, -204, -203, -202, -201, -200, -199, -198, -197, -196, -195, -194, -193, -192, -191, -190, -189, -188, -187, -186, -185, -184, -183, -182, -181, -180, -179, -178, -177, -176, -175, -174, -173, -172, -171, -170, -169, -168, -167, -166, -165, -164, -163, -162, -161, -160, -159, -158, -157, -156, -155, -154, -153, -152, -151, -150, -149, -148, -147, -146, -145, -144, -143, -142, -141, -140, -139, -138, -137, -136, -135, -134, -133, -132, -131, -130, -129, -128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114, -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99, -98, -97, -96, -95, -94, -93, -92, -91, -90, -89, -88, -87, -86, -85, -84, -83, -82, -81, -80, -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, -69, -68, -67, -66, -65, -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255]
|
|
27
|
+
type i10 = Literal[-512, -511, -510, -509, -508, -507, -506, -505, -504, -503, -502, -501, -500, -499, -498, -497, -496, -495, -494, -493, -492, -491, -490, -489, -488, -487, -486, -485, -484, -483, -482, -481, -480, -479, -478, -477, -476, -475, -474, -473, -472, -471, -470, -469, -468, -467, -466, -465, -464, -463, -462, -461, -460, -459, -458, -457, -456, -455, -454, -453, -452, -451, -450, -449, -448, -447, -446, -445, -444, -443, -442, -441, -440, -439, -438, -437, -436, -435, -434, -433, -432, -431, -430, -429, -428, -427, -426, -425, -424, -423, -422, -421, -420, -419, -418, -417, -416, -415, -414, -413, -412, -411, -410, -409, -408, -407, -406, -405, -404, -403, -402, -401, -400, -399, -398, -397, -396, -395, -394, -393, -392, -391, -390, -389, -388, -387, -386, -385, -384, -383, -382, -381, -380, -379, -378, -377, -376, -375, -374, -373, -372, -371, -370, -369, -368, -367, -366, -365, -364, -363, -362, -361, -360, -359, -358, -357, -356, -355, -354, -353, -352, -351, -350, -349, -348, -347, -346, -345, -344, -343, -342, -341, -340, -339, -338, -337, -336, -335, -334, -333, -332, -331, -330, -329, -328, -327, -326, -325, -324, -323, -322, -321, -320, -319, -318, -317, -316, -315, -314, -313, -312, -311, -310, -309, -308, -307, -306, -305, -304, -303, -302, -301, -300, -299, -298, -297, -296, -295, -294, -293, -292, -291, -290, -289, -288, -287, -286, -285, -284, -283, -282, -281, -280, -279, -278, -277, -276, -275, -274, -273, -272, -271, -270, -269, -268, -267, -266, -265, -264, -263, -262, -261, -260, -259, -258, -257, -256, -255, -254, -253, -252, -251, -250, -249, -248, -247, -246, -245, -244, -243, -242, -241, -240, -239, -238, -237, -236, -235, -234, -233, -232, -231, -230, -229, -228, -227, -226, -225, -224, -223, -222, -221, -220, -219, -218, -217, -216, -215, -214, -213, -212, -211, -210, -209, -208, -207, -206, -205, -204, -203, -202, -201, -200, -199, -198, -197, -196, -195, -194, -193, -192, -191, -190, -189, -188, -187, -186, -185, -184, -183, -182, -181, -180, -179, -178, -177, -176, -175, -174, -173, -172, -171, -170, -169, -168, -167, -166, -165, -164, -163, -162, -161, -160, -159, -158, -157, -156, -155, -154, -153, -152, -151, -150, -149, -148, -147, -146, -145, -144, -143, -142, -141, -140, -139, -138, -137, -136, -135, -134, -133, -132, -131, -130, -129, -128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114, -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99, -98, -97, -96, -95, -94, -93, -92, -91, -90, -89, -88, -87, -86, -85, -84, -83, -82, -81, -80, -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, -69, -68, -67, -66, -65, -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511]
|
types_bits/__main__.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""``python -m types_bits`` -- materialize a stub."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import TYPE_CHECKING, cast
|
|
8
|
+
|
|
9
|
+
from types_bits._generate import KINDS, VARIANTS, write
|
|
10
|
+
from types_bits._spec import MAX_BITS
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from collections.abc import Sequence
|
|
14
|
+
|
|
15
|
+
from types_bits._generate import Kind, Variant
|
|
16
|
+
|
|
17
|
+
DEFAULT_OUT = Path(__file__).with_name("__init__.pyi")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def main(argv: Sequence[str] | None = None) -> int:
|
|
21
|
+
parser = argparse.ArgumentParser(prog="python -m types_bits", description=__doc__)
|
|
22
|
+
parser.add_argument("--bits", type=int, default=MAX_BITS)
|
|
23
|
+
parser.add_argument("--variant", choices=VARIANTS, default="flat")
|
|
24
|
+
parser.add_argument("--kind", choices=KINDS, default="both")
|
|
25
|
+
parser.add_argument("--out", type=Path, default=DEFAULT_OUT)
|
|
26
|
+
args = parser.parse_args(argv)
|
|
27
|
+
|
|
28
|
+
path = write(
|
|
29
|
+
cast("Path", args.out),
|
|
30
|
+
cast("int", args.bits),
|
|
31
|
+
cast("Variant", args.variant),
|
|
32
|
+
cast("Kind", args.kind),
|
|
33
|
+
)
|
|
34
|
+
print(f"wrote {path} ({path.stat().st_size:,} bytes)") # noqa: T201
|
|
35
|
+
return 0
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
if __name__ == "__main__":
|
|
39
|
+
raise SystemExit(main())
|
types_bits/_generate.py
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"""Render exhaustive ``Literal`` stubs for Rust-style sized integer types.
|
|
2
|
+
|
|
3
|
+
Imported lazily by the runtime tier for the width algebra; never eagerly.
|
|
4
|
+
See ``python -m types_bits --help``.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
from typing import TYPE_CHECKING, Final, Literal, NamedTuple, assert_never
|
|
11
|
+
|
|
12
|
+
from types_bits._spec import MAX_BITS
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from collections.abc import Iterable
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Unsigned(NamedTuple):
|
|
20
|
+
"""A ``uN`` width.
|
|
21
|
+
|
|
22
|
+
>>> Unsigned(8).name, Unsigned(8).lo, Unsigned(8).hi
|
|
23
|
+
('u8', 0, 255)
|
|
24
|
+
>>> Unsigned(4) == Signed(4)
|
|
25
|
+
False
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
bits: int
|
|
29
|
+
signed: Literal[False] = False
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def name(self) -> str:
|
|
33
|
+
return f"u{self.bits}"
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def lo(self) -> int:
|
|
37
|
+
return 0
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def hi(self) -> int:
|
|
41
|
+
return (1 << self.bits) - 1
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class Signed(NamedTuple):
|
|
45
|
+
"""An ``iN`` width, two's complement.
|
|
46
|
+
|
|
47
|
+
>>> Signed(8).name, Signed(8).lo, Signed(8).hi
|
|
48
|
+
('i8', -128, 127)
|
|
49
|
+
>>> Signed(1).lo, Signed(1).hi
|
|
50
|
+
(-1, 0)
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
bits: int
|
|
54
|
+
signed: Literal[True] = True
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def name(self) -> str:
|
|
58
|
+
return f"i{self.bits}"
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def lo(self) -> int:
|
|
62
|
+
return -(1 << (self.bits - 1))
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def hi(self) -> int:
|
|
66
|
+
return (1 << (self.bits - 1)) - 1
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
type Width = Unsigned | Signed
|
|
70
|
+
|
|
71
|
+
type Variant = Literal["flat", "nested", "union", "annotated", "opaque"]
|
|
72
|
+
type Kind = Literal["both", "u", "i"]
|
|
73
|
+
|
|
74
|
+
VARIANTS: Final[tuple[Variant, ...]] = ("flat", "nested", "union", "annotated", "opaque")
|
|
75
|
+
KINDS: Final[tuple[Kind, ...]] = ("both", "u", "i")
|
|
76
|
+
|
|
77
|
+
BANNER: Final = "# Generated by types_bits._generate — do not edit."
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def members(width: Width) -> range:
|
|
81
|
+
"""Every value the width can hold.
|
|
82
|
+
|
|
83
|
+
>>> tuple(members(Signed(2)))
|
|
84
|
+
(-2, -1, 0, 1)
|
|
85
|
+
"""
|
|
86
|
+
return range(width.lo, width.hi + 1)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def narrower(width: Width) -> Width | None:
|
|
90
|
+
"""Step down one bit, keeping the signedness; ``None`` at the floor.
|
|
91
|
+
|
|
92
|
+
>>> narrower(Unsigned(3)), narrower(Unsigned(1))
|
|
93
|
+
(Unsigned(bits=2, signed=False), None)
|
|
94
|
+
"""
|
|
95
|
+
if width.bits == 1:
|
|
96
|
+
return None
|
|
97
|
+
match width:
|
|
98
|
+
case Unsigned():
|
|
99
|
+
return Unsigned(width.bits - 1)
|
|
100
|
+
case Signed():
|
|
101
|
+
return Signed(width.bits - 1)
|
|
102
|
+
case _ as unreachable: # pyright: ignore[reportUnnecessaryComparison]
|
|
103
|
+
assert_never(unreachable)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def added(width: Width) -> tuple[int, ...]:
|
|
107
|
+
"""Take the members a width contributes over the next-narrower one.
|
|
108
|
+
|
|
109
|
+
>>> added(Unsigned(3))
|
|
110
|
+
(4, 5, 6, 7)
|
|
111
|
+
>>> added(Signed(3))
|
|
112
|
+
(-4, -3, 2, 3)
|
|
113
|
+
"""
|
|
114
|
+
prev = narrower(width)
|
|
115
|
+
if prev is None:
|
|
116
|
+
return tuple(members(width))
|
|
117
|
+
return tuple(value for value in members(width) if value not in members(prev))
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def widths(bits: int, kind: Kind = "both") -> tuple[Width, ...]:
|
|
121
|
+
"""Widen from one bit up to ``bits``, unsigned before signed.
|
|
122
|
+
|
|
123
|
+
>>> tuple(w.name for w in widths(2))
|
|
124
|
+
('u1', 'u2', 'i1', 'i2')
|
|
125
|
+
"""
|
|
126
|
+
unsigned = tuple(Unsigned(n) for n in range(1, bits + 1))
|
|
127
|
+
signed = tuple(Signed(n) for n in range(1, bits + 1))
|
|
128
|
+
match kind:
|
|
129
|
+
case "both":
|
|
130
|
+
return unsigned + signed
|
|
131
|
+
case "u":
|
|
132
|
+
return unsigned
|
|
133
|
+
case "i":
|
|
134
|
+
return signed
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _literal(values: Iterable[int]) -> str:
|
|
138
|
+
return f"Literal[{', '.join(map(str, values))}]"
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _rhs(width: Width, variant: Variant) -> str:
|
|
142
|
+
prev = narrower(width)
|
|
143
|
+
match variant:
|
|
144
|
+
case "flat":
|
|
145
|
+
return _literal(members(width))
|
|
146
|
+
case "nested":
|
|
147
|
+
if prev is None:
|
|
148
|
+
return _literal(members(width))
|
|
149
|
+
return f"Literal[{prev.name}, {', '.join(map(str, added(width)))}]"
|
|
150
|
+
case "union":
|
|
151
|
+
if prev is None:
|
|
152
|
+
return _literal(members(width))
|
|
153
|
+
return f"{prev.name} | {_literal(added(width))}"
|
|
154
|
+
case "annotated":
|
|
155
|
+
return f"Annotated[{_literal(members(width))}, Ge({width.lo}), Le({width.hi})]"
|
|
156
|
+
case "opaque":
|
|
157
|
+
return "int"
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def alias(width: Width, variant: Variant) -> str:
|
|
161
|
+
"""Render one PEP 695 alias statement.
|
|
162
|
+
|
|
163
|
+
>>> alias(Unsigned(2), "flat")
|
|
164
|
+
'type u2 = Literal[0, 1, 2, 3]'
|
|
165
|
+
>>> alias(Signed(2), "union")
|
|
166
|
+
'type i2 = i1 | Literal[-2, 1]'
|
|
167
|
+
>>> alias(Unsigned(1), "annotated")
|
|
168
|
+
'type u1 = Annotated[Literal[0, 1], Ge(0), Le(1)]'
|
|
169
|
+
"""
|
|
170
|
+
return f"type {width.name} = {_rhs(width, variant)}"
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _imports(variant: Variant) -> tuple[str, ...]:
|
|
174
|
+
match variant:
|
|
175
|
+
case "flat" | "nested" | "union":
|
|
176
|
+
return ("from typing import Literal",)
|
|
177
|
+
case "annotated":
|
|
178
|
+
return ("from typing import Annotated, Literal", "from annotated_types import Ge, Le")
|
|
179
|
+
case "opaque":
|
|
180
|
+
return ()
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _dunder_all(names: Iterable[str]) -> str:
|
|
184
|
+
return f"__all__ = [{', '.join(f'{name!r}' for name in names)}]"
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def module(bits: int, variant: Variant = "flat", kind: Kind = "both") -> str:
|
|
188
|
+
"""Render a whole stub module.
|
|
189
|
+
|
|
190
|
+
>>> print(module(1, kind="u"))
|
|
191
|
+
# Generated by types_bits._generate — do not edit.
|
|
192
|
+
# variant=flat bits=1 kind=u
|
|
193
|
+
<BLANKLINE>
|
|
194
|
+
from typing import Literal
|
|
195
|
+
<BLANKLINE>
|
|
196
|
+
__all__ = ['u1']
|
|
197
|
+
<BLANKLINE>
|
|
198
|
+
type u1 = Literal[0, 1]
|
|
199
|
+
<BLANKLINE>
|
|
200
|
+
"""
|
|
201
|
+
selected = widths(bits, kind)
|
|
202
|
+
sections = (
|
|
203
|
+
(BANNER, f"# variant={variant} bits={bits} kind={kind}"),
|
|
204
|
+
_imports(variant),
|
|
205
|
+
(_dunder_all([width.name for width in selected]),),
|
|
206
|
+
tuple(alias(width, variant) for width in selected),
|
|
207
|
+
)
|
|
208
|
+
return "\n\n".join("\n".join(section) for section in sections if section) + "\n"
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def write(path: Path, bits: int = MAX_BITS, variant: Variant = "flat", kind: Kind = "both") -> Path:
|
|
212
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
213
|
+
scratch = path.with_name(f"{path.name}.{os.getpid()}.tmp")
|
|
214
|
+
scratch.write_text(module(bits, variant, kind), encoding="utf-8")
|
|
215
|
+
scratch.replace(path)
|
|
216
|
+
return path
|
types_bits/_spec.py
ADDED
types_bits/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: types-bits
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Sized integer types: exhaustive Literal unions statically, Annotated bounds at runtime
|
|
5
|
+
Author-email: JP Hutchins <jphutchins@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.12
|
|
9
|
+
Provides-Extra: rt
|
|
10
|
+
Requires-Dist: annotated-types>=0.7; extra == 'rt'
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# types-bits
|
|
14
|
+
|
|
15
|
+
`u1`..`u10` and `i1`..`i10` as fully materialized `Literal` unions. Generated `.pyi`, zero
|
|
16
|
+
runtime cost, exhaustively checked.
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from typing import TYPE_CHECKING
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from types_bits import u4
|
|
23
|
+
|
|
24
|
+
x: u4 = 15 # ok
|
|
25
|
+
y: u4 = 16 # error, on every checker
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`camas` runs the gate; `camas --list` enumerates it. CI fans the same tree out over a
|
|
29
|
+
runner axis, with both matrix axes emitted from `tasks.py`. `camas bench` and
|
|
30
|
+
`camas bench_shapes` regenerate everything below into `bench/results/`.
|
|
31
|
+
|
|
32
|
+
## Runtime cost
|
|
33
|
+
|
|
34
|
+
Zero. The stub is a [PEP 484][pep484] `.pyi` behind `TYPE_CHECKING`. `import types_bits`
|
|
35
|
+
loads two modules and no stdlib (`tests/test_runtime.py`). Every number below is
|
|
36
|
+
type-checker wall clock, per check run.
|
|
37
|
+
|
|
38
|
+
## Check cost by width
|
|
39
|
+
|
|
40
|
+
Seconds, cold, best of one, Python 3.14.1 / WSL2. Encoding `flat`
|
|
41
|
+
(`type uN = Literal[0, ..., 2**N-1]`), declaring `u1..uN` (so a probe at N bits holds 2^(N+1)-2 literals) and widening each
|
|
42
|
+
into the next.
|
|
43
|
+
|
|
44
|
+
| bits | mypy | pyright | basedpyright | ty | pyrefly | zuban |
|
|
45
|
+
|---:|---:|---:|---:|---:|---:|---:|
|
|
46
|
+
| 8 | 2.30 | 0.68 | 0.71 | 0.08 | 0.32 | 0.10 |
|
|
47
|
+
| 10 | 1.98 | 0.75 | 0.83 | 0.09 | 0.38 | 0.12 |
|
|
48
|
+
| 12 | 2.22 | 0.79 | 0.85 | 0.11 | 0.31 | 0.33 |
|
|
49
|
+
| 14 | 3.10 | 0.59 | 0.64 | 0.17 | 0.27 | 3.23 |
|
|
50
|
+
| 16 | 3.85 | 0.70 | 0.79 | 0.41 | 0.46 | 51.26 |
|
|
51
|
+
|
|
52
|
+
Shipped library (`u1..u10` + `i1..i10`): mypy 2.05, basedpyright 1.43,
|
|
53
|
+
pyright 1.13, pyrefly 0.24, zuban 0.08, ty 0.06 — matching the `type uN = int` control.
|
|
54
|
+
|
|
55
|
+
```mermaid
|
|
56
|
+
xychart-beta
|
|
57
|
+
title "16 bits"
|
|
58
|
+
x-axis [zuban, mypy, basedpyright, pyright, pyrefly, ty]
|
|
59
|
+
y-axis "seconds" 0 --> 55
|
|
60
|
+
bar [51.26, 3.85, 0.79, 0.70, 0.46, 0.41]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
zuban, same sweep — roughly 16x per extra 2 bits past 12:
|
|
64
|
+
|
|
65
|
+
```mermaid
|
|
66
|
+
xychart-beta
|
|
67
|
+
title "zuban vs width"
|
|
68
|
+
x-axis "bits" [8, 10, 12, 14, 16]
|
|
69
|
+
y-axis "seconds" 0 --> 55
|
|
70
|
+
line [0.10, 0.12, 0.33, 3.23, 51.26]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The other five, 0–4s axis. Rising line is mypy; flat cluster is pyright, basedpyright,
|
|
74
|
+
pyrefly, ty:
|
|
75
|
+
|
|
76
|
+
```mermaid
|
|
77
|
+
xychart-beta
|
|
78
|
+
title "mypy, pyright, basedpyright, pyrefly, ty"
|
|
79
|
+
x-axis "bits" [8, 10, 12, 14, 16]
|
|
80
|
+
y-axis "seconds" 0 --> 4
|
|
81
|
+
line [2.30, 1.98, 2.22, 3.10, 3.85]
|
|
82
|
+
line [0.68, 0.75, 0.79, 0.59, 0.70]
|
|
83
|
+
line [0.71, 0.83, 0.85, 0.64, 0.79]
|
|
84
|
+
line [0.32, 0.38, 0.31, 0.27, 0.46]
|
|
85
|
+
line [0.08, 0.09, 0.11, 0.17, 0.41]
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Fixed vs marginal cost
|
|
89
|
+
|
|
90
|
+
`u(N-1)` and `u(N)` declared in every row; only the use count varies. Italic rows are the
|
|
91
|
+
`type uN = int` control.
|
|
92
|
+
|
|
93
|
+
10 bits — indistinguishable from `int`:
|
|
94
|
+
|
|
95
|
+
| uses | mypy | pyright | basedpyright | ty | pyrefly | zuban |
|
|
96
|
+
|---|---:|---:|---:|---:|---:|---:|
|
|
97
|
+
| declared, unused | 1.64 | 0.55 | 0.60 | 0.05 | 0.23 | 0.10 |
|
|
98
|
+
| *control* | *1.64* | *0.60* | *0.59* | *0.06* | *0.23* | *0.08* |
|
|
99
|
+
| 1 widening | 1.50 | 0.56 | 0.64 | 0.06 | 0.26 | 0.09 |
|
|
100
|
+
| 10 widenings | 1.75 | 0.65 | 0.90 | 0.08 | 0.29 | 0.20 |
|
|
101
|
+
|
|
102
|
+
16 bits — 98,304 literals:
|
|
103
|
+
|
|
104
|
+
| uses | mypy | pyright | basedpyright | ty | pyrefly | zuban |
|
|
105
|
+
|---|---:|---:|---:|---:|---:|---:|
|
|
106
|
+
| declared, unused | 2.79 | 0.66 | 0.64 | 0.18 | 0.29 | 0.20 |
|
|
107
|
+
| *control* | *1.57* | *0.62* | *0.59* | *0.05* | *0.28* | *0.08* |
|
|
108
|
+
| 1 assignment | 2.77 | 0.62 | 0.65 | 0.19 | 0.33 | 0.21 |
|
|
109
|
+
| 1 widening | 2.81 | 0.64 | 0.65 | 0.22 | 0.37 | **35.66** |
|
|
110
|
+
| 10 widenings | 3.31 | 0.56 | 0.58 | 0.20 | 0.31 | **timeout (>180s)** |
|
|
111
|
+
|
|
112
|
+
- Declaration: fixed per check run, ~linear in literals (~12 µs/literal on mypy). Not per
|
|
113
|
+
importing file, not per use.
|
|
114
|
+
- Assignment: free. Enumerated membership is a hash lookup.
|
|
115
|
+
- Widening: free except zuban at width.
|
|
116
|
+
|
|
117
|
+
## Widening
|
|
118
|
+
|
|
119
|
+
Cost tracks the *narrow* operand, not the wide one. Wide side fixed at `u16`, one widening:
|
|
120
|
+
|
|
121
|
+
| narrow | zuban | mypy | ty |
|
|
122
|
+
|---|---:|---:|---:|
|
|
123
|
+
| u1 | 0.18 | 2.54 | 0.20 |
|
|
124
|
+
| u4 | 0.18 | 2.46 | 0.15 |
|
|
125
|
+
| u8 | 0.16 | 2.67 | 0.21 |
|
|
126
|
+
| u12 | 0.76 | 2.50 | 0.17 |
|
|
127
|
+
| u15 | 35.21 | 2.80 | 0.18 |
|
|
128
|
+
|
|
129
|
+
Both operands must be large. At the 10-bit ceiling the worst case (`u9` → `u10`) is 0.09s.
|
|
130
|
+
Annotating a boundary at one width, so callers assign literals rather than widen between
|
|
131
|
+
adjacent wide aliases, avoids the shape entirely.
|
|
132
|
+
|
|
133
|
+
## Encodings
|
|
134
|
+
|
|
135
|
+
| encoding | form | result |
|
|
136
|
+
|---|---|---|
|
|
137
|
+
| `flat` | `Literal[0, ..., 2**N-1]` | shipped; fastest, portable |
|
|
138
|
+
| `nested` | `Literal[u9, 512, ...]` | legal per [PEP 586][pep586]; pyrefly rejects past ~10 levels (`Invalid type inside literal, int`, 1 error at 10 bits → 7 at 16), ty at 16 |
|
|
139
|
+
| `union` | `u9 \| Literal[512, ...]` | ty 44.24s at 14 bits vs 0.17s flat |
|
|
140
|
+
| `annotated` | `Annotated[Literal[...], Ge, Le]` | tracks `flat` within noise to 14 bits |
|
|
141
|
+
| `opaque` | `int` | control |
|
|
142
|
+
|
|
143
|
+
```mermaid
|
|
144
|
+
xychart-beta
|
|
145
|
+
title "ty at 14 bits by encoding"
|
|
146
|
+
x-axis [union, nested, annotated, flat]
|
|
147
|
+
y-axis "seconds" 0 --> 46
|
|
148
|
+
bar [44.24, 0.23, 0.22, 0.17]
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Runtime tier
|
|
152
|
+
|
|
153
|
+
[PEP 562][pep562] module `__getattr__` resolves the same names to
|
|
154
|
+
`Annotated[int, Ge(lo), Le(hi)]` ([PEP 593][pep593]), the shape
|
|
155
|
+
[`annotated-types`][at] consumers read. `tests/test_runtime.py` pins it against the static
|
|
156
|
+
bounds for all 20 widths. Needs the `rt` extra; `annotated_types` imports on first
|
|
157
|
+
attribute access.
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from pydantic import TypeAdapter
|
|
161
|
+
from types_bits import u8 # Annotated[int, Ge(0), Le(255)] at runtime
|
|
162
|
+
|
|
163
|
+
TypeAdapter(u8).validate_python(256) # ValidationError
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Prior art
|
|
167
|
+
|
|
168
|
+
[`range-typed-integers`][rti] defines `u8 = NewType('u8', Annotated[int, ValueRange(0, 255)])`
|
|
169
|
+
for the byte widths `u8`..`u64` / `i8`..`i64`.
|
|
170
|
+
|
|
171
|
+
| | range-typed-integers | types-bits |
|
|
172
|
+
|---|---|---|
|
|
173
|
+
| carrier | `NewType` over `Annotated[int, ValueRange]` | `Literal` enumeration |
|
|
174
|
+
| bound enforced by | runtime `u8_checked()` / `check_int()`, raising `IntegerBoundError` | the type checker |
|
|
175
|
+
| `a: u8 = 12` | mypy error — `int` is not `u8`; requires `u8(12)` | ok |
|
|
176
|
+
| `a: u8 = 900` | mypy error, *identical* to the line above | error, and distinguished |
|
|
177
|
+
| `u8(900)` | accepted statically | n/a |
|
|
178
|
+
| widths | u8..u64 | u1..u10 |
|
|
179
|
+
|
|
180
|
+
Verified against every checker in the gate: mypy reports the same `Incompatible types in assignment
|
|
181
|
+
(expression has type "int", variable has type "u8")` on the in-range and out-of-range
|
|
182
|
+
lines alike. The range is metadata no checker reads ([PEP 746][pep746] would not change
|
|
183
|
+
this). `ValueRange` is O(1) per type, so it reaches u64; enumeration is O(2^N), so it
|
|
184
|
+
stops at u10.
|
|
185
|
+
|
|
186
|
+
## PEPs
|
|
187
|
+
|
|
188
|
+
No PEP provides bounded integers.
|
|
189
|
+
|
|
190
|
+
| PEP | Status | Relevance |
|
|
191
|
+
|---|---|---|
|
|
192
|
+
| [586 – Literal Types][pep586] | Final | The mechanism. Calls `Literal` insufficient for numpy-style numeric code and defers integer generics. Permits the `nested` form pyrefly rejects. |
|
|
193
|
+
| [593 – `Annotated`][pep593] | Final | Metadata channel for the runtime tier. |
|
|
194
|
+
| [695 – Type Parameter Syntax][pep695] | Final | `type uN = ...` in the stub. |
|
|
195
|
+
| [561 – Packaging Type Information][pep561] | Final | `py.typed`; why the stub ships in the wheel. |
|
|
196
|
+
| [562 – Module `__getattr__`][pep562] | Final | One name, two tiers. |
|
|
197
|
+
| [649][pep649] / [749][pep749] – Deferred Annotations | Final (3.14) | Guarded import gets cheaper. |
|
|
198
|
+
| [746 – Type checking `Annotated` metadata][pep746] | Draft, targets 3.15 | Lets a checker verify metadata suits its type. Does not make any checker enforce `Ge`/`Le`. |
|
|
199
|
+
|
|
200
|
+
- [python/typing#554, "Support for Range Types?"][i554] — closed. Requested an Ada-style
|
|
201
|
+
`RangeType`.
|
|
202
|
+
- [discuss.python.org, "Use type hinting with bound constraints, e.g. `int[0:15]`"][thread]
|
|
203
|
+
— no resolution. Objections: most constraints are not statically validatable; ranges need
|
|
204
|
+
new type-system machinery; arithmetic is not closed. Landed on `Annotated` +
|
|
205
|
+
`annotated-types` with runtime validation.
|
|
206
|
+
|
|
207
|
+
`fixtures/reject.py` covers the arithmetic case: every checker rejects `u4 + u4` where a
|
|
208
|
+
`u4` is required. mypy widens the sum to `int`; ty and zuban widen it to `Literal[0, ..., 30]`.
|
|
209
|
+
|
|
210
|
+
[pep484]: https://peps.python.org/pep-0484/
|
|
211
|
+
[pep561]: https://peps.python.org/pep-0561/
|
|
212
|
+
[pep562]: https://peps.python.org/pep-0562/
|
|
213
|
+
[pep586]: https://peps.python.org/pep-0586/
|
|
214
|
+
[pep593]: https://peps.python.org/pep-0593/
|
|
215
|
+
[pep649]: https://peps.python.org/pep-0649/
|
|
216
|
+
[pep695]: https://peps.python.org/pep-0695/
|
|
217
|
+
[pep746]: https://peps.python.org/pep-0746/
|
|
218
|
+
[pep749]: https://peps.python.org/pep-0749/
|
|
219
|
+
[at]: https://github.com/annotated-types/annotated-types
|
|
220
|
+
[i554]: https://github.com/python/typing/issues/554
|
|
221
|
+
[thread]: https://discuss.python.org/t/use-type-hinting-with-bound-constraints-e-g-int-0-15/38820
|
|
222
|
+
[rti]: https://github.com/theCapypara/range-typed-integers
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
types_bits/__init__.py,sha256=KWjhWzFBU_AlRFYmGX4Ivpj2Vetkjcp3lHC5vB1hiGM,735
|
|
2
|
+
types_bits/__init__.pyi,sha256=fhsSIyAQ5WfQagJGnygKxLGMCeH8UrU58pJ3a6F4rk0,20513
|
|
3
|
+
types_bits/__main__.py,sha256=capR_YPj4T2SphzQxaEOOu_zGMMD8jjwHOPuJzs8A8s,1178
|
|
4
|
+
types_bits/_generate.py,sha256=toXd2w9rZjcXBoNkANdkdhzilCm9GJr36Iv9uP3jK9o,6006
|
|
5
|
+
types_bits/_spec.py,sha256=IxO5nKnXEjBCJM_EAmxR0FjyKKJDS-h8whR6oGFisAY,109
|
|
6
|
+
types_bits/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
types_bits-0.1.0.dist-info/METADATA,sha256=7GttperlGHPHYlWPmFntzAFfNDPleNdn_GkmEkWv1DA,8874
|
|
8
|
+
types_bits-0.1.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
9
|
+
types_bits-0.1.0.dist-info/licenses/LICENSE,sha256=WqlOTEeKt2qflqeLgs0Gl4FCfY0_mSc0BbwEbD8b8jM,1068
|
|
10
|
+
types_bits-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 JP Hutchins
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|