rapydscript-ns 0.8.4 → 0.9.0

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 (132) hide show
  1. package/.agignore +1 -1
  2. package/.github/workflows/ci.yml +38 -38
  3. package/=template.pyj +5 -5
  4. package/CHANGELOG.md +18 -0
  5. package/HACKING.md +103 -103
  6. package/LICENSE +24 -24
  7. package/README.md +715 -169
  8. package/TODO.md +9 -2
  9. package/add-toc-to-readme +2 -2
  10. package/bin/export +75 -75
  11. package/bin/rapydscript +70 -70
  12. package/bin/web-repl-export +102 -102
  13. package/build +2 -2
  14. package/language-service/index.js +36 -27
  15. package/package.json +1 -1
  16. package/publish.py +37 -37
  17. package/release/baselib-plain-pretty.js +2358 -168
  18. package/release/baselib-plain-ugly.js +73 -3
  19. package/release/compiler.js +6282 -3092
  20. package/release/signatures.json +31 -30
  21. package/session.vim +4 -4
  22. package/setup.cfg +2 -2
  23. package/src/ast.pyj +1 -0
  24. package/src/baselib-builtins.pyj +340 -2
  25. package/src/baselib-bytes.pyj +664 -0
  26. package/src/baselib-errors.pyj +1 -1
  27. package/src/baselib-internal.pyj +267 -60
  28. package/src/baselib-itertools.pyj +110 -97
  29. package/src/baselib-str.pyj +22 -4
  30. package/src/compiler.pyj +36 -36
  31. package/src/errors.pyj +30 -30
  32. package/src/lib/abc.pyj +317 -0
  33. package/src/lib/aes.pyj +646 -646
  34. package/src/lib/copy.pyj +120 -120
  35. package/src/lib/dataclasses.pyj +532 -0
  36. package/src/lib/elementmaker.pyj +83 -83
  37. package/src/lib/encodings.pyj +126 -126
  38. package/src/lib/enum.pyj +125 -0
  39. package/src/lib/gettext.pyj +569 -569
  40. package/src/lib/itertools.pyj +580 -580
  41. package/src/lib/math.pyj +193 -193
  42. package/src/lib/operator.pyj +11 -11
  43. package/src/lib/pythonize.pyj +20 -20
  44. package/src/lib/random.pyj +118 -118
  45. package/src/lib/re.pyj +504 -470
  46. package/src/lib/react.pyj +74 -74
  47. package/src/lib/traceback.pyj +63 -63
  48. package/src/lib/typing.pyj +577 -0
  49. package/src/lib/uuid.pyj +77 -77
  50. package/src/monaco-language-service/builtins.js +14 -4
  51. package/src/monaco-language-service/diagnostics.js +19 -20
  52. package/src/monaco-language-service/dts.js +550 -550
  53. package/src/output/classes.pyj +62 -26
  54. package/src/output/comments.pyj +45 -45
  55. package/src/output/exceptions.pyj +201 -201
  56. package/src/output/functions.pyj +78 -5
  57. package/src/output/jsx.pyj +164 -164
  58. package/src/output/loops.pyj +5 -2
  59. package/src/output/operators.pyj +100 -34
  60. package/src/output/treeshake.pyj +182 -182
  61. package/src/output/utils.pyj +72 -72
  62. package/src/parse.pyj +80 -16
  63. package/src/string_interpolation.pyj +72 -72
  64. package/src/tokenizer.pyj +9 -4
  65. package/src/unicode_aliases.pyj +576 -576
  66. package/src/utils.pyj +192 -192
  67. package/test/_import_one.pyj +37 -37
  68. package/test/_import_two/__init__.pyj +11 -11
  69. package/test/_import_two/level2/deep.pyj +4 -4
  70. package/test/_import_two/other.pyj +6 -6
  71. package/test/_import_two/sub.pyj +13 -13
  72. package/test/abc.pyj +291 -0
  73. package/test/aes_vectors.pyj +421 -421
  74. package/test/annotations.pyj +80 -80
  75. package/test/arithmetic_nostrict.pyj +88 -0
  76. package/test/arithmetic_types.pyj +169 -0
  77. package/test/baselib.pyj +91 -0
  78. package/test/bytes.pyj +467 -0
  79. package/test/classes.pyj +1 -0
  80. package/test/comparison_ops.pyj +173 -0
  81. package/test/dataclasses.pyj +253 -0
  82. package/test/decorators.pyj +77 -77
  83. package/test/docstrings.pyj +39 -39
  84. package/test/elementmaker_test.pyj +45 -45
  85. package/test/enum.pyj +134 -0
  86. package/test/eval_exec.pyj +56 -0
  87. package/test/format.pyj +148 -0
  88. package/test/functions.pyj +151 -151
  89. package/test/generators.pyj +41 -41
  90. package/test/generic.pyj +370 -370
  91. package/test/imports.pyj +72 -72
  92. package/test/internationalization.pyj +73 -73
  93. package/test/lint.pyj +164 -164
  94. package/test/loops.pyj +85 -85
  95. package/test/numpy.pyj +734 -734
  96. package/test/object.pyj +64 -0
  97. package/test/omit_function_metadata.pyj +20 -20
  98. package/test/python_compat.pyj +17 -15
  99. package/test/python_features.pyj +70 -15
  100. package/test/regexp.pyj +83 -55
  101. package/test/repl.pyj +121 -121
  102. package/test/scoped_flags.pyj +76 -76
  103. package/test/tuples.pyj +96 -0
  104. package/test/typing.pyj +469 -0
  105. package/test/unit/index.js +116 -7
  106. package/test/unit/language-service-dts.js +543 -543
  107. package/test/unit/language-service-hover.js +455 -455
  108. package/test/unit/language-service.js +84 -0
  109. package/test/unit/web-repl.js +804 -1
  110. package/test/vars_locals_globals.pyj +94 -0
  111. package/tools/cli.js +558 -547
  112. package/tools/compile.js +224 -219
  113. package/tools/completer.js +131 -131
  114. package/tools/embedded_compiler.js +262 -251
  115. package/tools/gettext.js +185 -185
  116. package/tools/ini.js +65 -65
  117. package/tools/lint.js +16 -19
  118. package/tools/msgfmt.js +187 -187
  119. package/tools/repl.js +223 -223
  120. package/tools/test.js +118 -118
  121. package/tools/utils.js +128 -128
  122. package/tools/web_repl.js +95 -95
  123. package/try +41 -41
  124. package/web-repl/env.js +196 -196
  125. package/web-repl/index.html +163 -163
  126. package/web-repl/main.js +252 -252
  127. package/web-repl/prism.css +139 -139
  128. package/web-repl/prism.js +113 -113
  129. package/web-repl/rapydscript.js +224 -224
  130. package/web-repl/sha1.js +25 -25
  131. package/PYTHON_DIFFERENCES_REPORT.md +0 -291
  132. package/PYTHON_FEATURE_COVERAGE.md +0 -200
@@ -0,0 +1,577 @@
1
+ # vim:fileencoding=utf-8
2
+ # License: BSD
3
+ # RapydScript implementation of Python's typing standard library.
4
+ #
5
+ # Supported:
6
+ # TYPE_CHECKING, Any, Union, Optional, ClassVar, Final, Literal, NoReturn,
7
+ # List, Dict, Set, FrozenSet, Tuple, Type, Callable,
8
+ # Iterator, Iterable, Generator, Sequence, MutableSequence,
9
+ # Mapping, MutableMapping, Awaitable, Coroutine,
10
+ # AsyncGenerator, AsyncIterator, AsyncIterable,
11
+ # IO, TextIO, BinaryIO, Pattern, Match,
12
+ # TypeVar, Generic, Protocol,
13
+ # cast, overload, no_type_check, no_type_check_decorator,
14
+ # runtime_checkable, get_type_hints,
15
+ # TypedDict, NamedTuple, AnyStr, ByteString, Text
16
+ #
17
+ # Type annotations are not enforced at runtime. All typing constructs
18
+ # transpile to lightweight JavaScript objects that carry the same
19
+ # introspection attributes (__origin__, __args__, _name) as their
20
+ # CPython equivalents, so that annotation-aware code works identically.
21
+
22
+
23
+ # ── Constants ──────────────────────────────────────────────────────────────────
24
+
25
+ # Always False at runtime; True only when a static type-checker is running.
26
+ TYPE_CHECKING = False
27
+
28
+
29
+ # ── Internal representation ────────────────────────────────────────────────────
30
+
31
+ class _GenericAlias:
32
+ """Represents a parameterized generic type such as List[int] or Dict[str, int].
33
+
34
+ Attributes:
35
+ __origin__ The origin type (list, dict, …) or None for abstract types.
36
+ __args__ Tuple of type arguments; empty tuple when not parameterised.
37
+ _name Display name used in repr().
38
+ """
39
+
40
+ def __init__(self, origin, args, name=None):
41
+ self.__origin__ = origin
42
+ if args is None:
43
+ self.__args__ = []
44
+ elif Array.isArray(args):
45
+ self.__args__ = args
46
+ else:
47
+ self.__args__ = [args]
48
+ self._name = name
49
+ # Allow _GenericAlias to be used as a base class in `class Foo(Generic[T])`.
50
+ # ρσ_extends reads parent.prototype, so we proxy it to the origin's prototype.
51
+ if origin and jstype(origin.prototype) is not 'undefined':
52
+ self.prototype = origin.prototype
53
+
54
+ def __repr__(self):
55
+ if self._name:
56
+ base = 'typing.' + self._name
57
+ else:
58
+ base = 'typing._GenericAlias'
59
+ if self.__args__:
60
+ parts = []
61
+ for a in self.__args__:
62
+ if a is None:
63
+ parts.append('None')
64
+ elif jstype(a.__name__) is 'string' and a.__name__:
65
+ parts.append(a.__name__)
66
+ else:
67
+ parts.append(repr(a))
68
+ return base + '[' + parts.join(', ') + ']'
69
+ return base
70
+
71
+
72
+ # ── Special forms ──────────────────────────────────────────────────────────────
73
+
74
+ class Any:
75
+ """Special form: matches any type. Every type is compatible with Any."""
76
+
77
+ def __repr__(self):
78
+ return 'typing.Any'
79
+
80
+
81
+ class Union:
82
+ """Union[X, Y] means either type X or type Y.
83
+
84
+ Example::
85
+
86
+ from typing import Union
87
+ def f(x: Union[str, int]) -> None: ...
88
+ """
89
+
90
+ def __class_getitem__(cls, params):
91
+ if not Array.isArray(params):
92
+ params = [params]
93
+ return _GenericAlias(None, params, 'Union')
94
+
95
+
96
+ class Optional:
97
+ """Optional[X] is shorthand for Union[X, None].
98
+
99
+ Example::
100
+
101
+ from typing import Optional
102
+ def f(x: Optional[str] = None) -> Optional[int]: ...
103
+ """
104
+
105
+ def __class_getitem__(cls, params):
106
+ return _GenericAlias(None, [params, None], 'Optional')
107
+
108
+
109
+ class ClassVar:
110
+ """ClassVar[T] marks that a variable is intended as a class variable."""
111
+
112
+ def __class_getitem__(cls, params):
113
+ if not Array.isArray(params):
114
+ params = [params]
115
+ return _GenericAlias(None, params, 'ClassVar')
116
+
117
+
118
+ class Final:
119
+ """Final[T] marks that a variable may not be reassigned after first assignment."""
120
+
121
+ def __class_getitem__(cls, params):
122
+ if not Array.isArray(params):
123
+ params = [params]
124
+ return _GenericAlias(None, params, 'Final')
125
+
126
+
127
+ class Literal:
128
+ """Literal[v, …] marks a type that may only take one of the given literal values.
129
+
130
+ Example::
131
+
132
+ from typing import Literal
133
+ Mode = Literal['r', 'w', 'a']
134
+ """
135
+
136
+ def __class_getitem__(cls, params):
137
+ if not Array.isArray(params):
138
+ params = [params]
139
+ return _GenericAlias(None, params, 'Literal')
140
+
141
+
142
+ class NoReturn:
143
+ """NoReturn marks a function that never returns normally."""
144
+ pass
145
+
146
+
147
+ # ── Concrete generic aliases ───────────────────────────────────────────────────
148
+
149
+ class List:
150
+ """Generic alias for the built-in list type.
151
+
152
+ Example::
153
+
154
+ from typing import List
155
+ def f(xs: List[int]) -> List[str]: ...
156
+ """
157
+
158
+ def __class_getitem__(cls, params):
159
+ if not Array.isArray(params):
160
+ params = [params]
161
+ return _GenericAlias(list, params, 'List')
162
+
163
+
164
+ class Dict:
165
+ """Generic alias for the built-in dict type."""
166
+
167
+ def __class_getitem__(cls, params):
168
+ if not Array.isArray(params):
169
+ params = [params]
170
+ return _GenericAlias(dict, params, 'Dict')
171
+
172
+
173
+ class Set:
174
+ """Generic alias for the built-in set type."""
175
+
176
+ def __class_getitem__(cls, params):
177
+ if not Array.isArray(params):
178
+ params = [params]
179
+ return _GenericAlias(set, params, 'Set')
180
+
181
+
182
+ class FrozenSet:
183
+ """Generic alias for the built-in frozenset type."""
184
+
185
+ def __class_getitem__(cls, params):
186
+ if not Array.isArray(params):
187
+ params = [params]
188
+ return _GenericAlias(frozenset, params, 'FrozenSet')
189
+
190
+
191
+ class Tuple:
192
+ """Generic alias for the built-in tuple type.
193
+
194
+ Use Tuple[X, Y] for a two-element tuple or Tuple[X, ...] for a
195
+ variable-length homogeneous tuple.
196
+ """
197
+
198
+ def __class_getitem__(cls, params):
199
+ if not Array.isArray(params):
200
+ params = [params]
201
+ return _GenericAlias(tuple, params, 'Tuple')
202
+
203
+
204
+ class Type:
205
+ """Type[C] represents the class C itself rather than an instance of C."""
206
+
207
+ def __class_getitem__(cls, params):
208
+ if not Array.isArray(params):
209
+ params = [params]
210
+ return _GenericAlias(type, params, 'Type')
211
+
212
+
213
+ class Callable:
214
+ """Callable[[ArgType, …], ReturnType] — any callable object.
215
+
216
+ Example::
217
+
218
+ from typing import Callable
219
+ f: Callable[[int, str], bool]
220
+ """
221
+
222
+ def __class_getitem__(cls, params):
223
+ if not Array.isArray(params):
224
+ params = [params]
225
+ return _GenericAlias(None, params, 'Callable')
226
+
227
+
228
+ # ── Abstract-base / protocol aliases ──────────────────────────────────────────
229
+
230
+ class Iterator:
231
+ """Generic alias for an iterator (has __next__)."""
232
+
233
+ def __class_getitem__(cls, params):
234
+ if not Array.isArray(params):
235
+ params = [params]
236
+ return _GenericAlias(None, params, 'Iterator')
237
+
238
+
239
+ class Iterable:
240
+ """Generic alias for an iterable (has __iter__)."""
241
+
242
+ def __class_getitem__(cls, params):
243
+ if not Array.isArray(params):
244
+ params = [params]
245
+ return _GenericAlias(None, params, 'Iterable')
246
+
247
+
248
+ class Generator:
249
+ """Generic alias for a generator (yield / send / throw)."""
250
+
251
+ def __class_getitem__(cls, params):
252
+ if not Array.isArray(params):
253
+ params = [params]
254
+ return _GenericAlias(None, params, 'Generator')
255
+
256
+
257
+ class Sequence:
258
+ """Generic alias for a read-only sequence."""
259
+
260
+ def __class_getitem__(cls, params):
261
+ if not Array.isArray(params):
262
+ params = [params]
263
+ return _GenericAlias(None, params, 'Sequence')
264
+
265
+
266
+ class MutableSequence:
267
+ """Generic alias for a mutable sequence."""
268
+
269
+ def __class_getitem__(cls, params):
270
+ if not Array.isArray(params):
271
+ params = [params]
272
+ return _GenericAlias(None, params, 'MutableSequence')
273
+
274
+
275
+ class Mapping:
276
+ """Generic alias for a read-only key-value mapping."""
277
+
278
+ def __class_getitem__(cls, params):
279
+ if not Array.isArray(params):
280
+ params = [params]
281
+ return _GenericAlias(None, params, 'Mapping')
282
+
283
+
284
+ class MutableMapping:
285
+ """Generic alias for a mutable key-value mapping."""
286
+
287
+ def __class_getitem__(cls, params):
288
+ if not Array.isArray(params):
289
+ params = [params]
290
+ return _GenericAlias(None, params, 'MutableMapping')
291
+
292
+
293
+ class Awaitable:
294
+ """Generic alias for an awaitable object."""
295
+
296
+ def __class_getitem__(cls, params):
297
+ if not Array.isArray(params):
298
+ params = [params]
299
+ return _GenericAlias(None, params, 'Awaitable')
300
+
301
+
302
+ class Coroutine:
303
+ """Generic alias for a coroutine."""
304
+
305
+ def __class_getitem__(cls, params):
306
+ if not Array.isArray(params):
307
+ params = [params]
308
+ return _GenericAlias(None, params, 'Coroutine')
309
+
310
+
311
+ class AsyncGenerator:
312
+ """Generic alias for an async generator."""
313
+
314
+ def __class_getitem__(cls, params):
315
+ if not Array.isArray(params):
316
+ params = [params]
317
+ return _GenericAlias(None, params, 'AsyncGenerator')
318
+
319
+
320
+ class AsyncIterator:
321
+ """Generic alias for an async iterator."""
322
+
323
+ def __class_getitem__(cls, params):
324
+ if not Array.isArray(params):
325
+ params = [params]
326
+ return _GenericAlias(None, params, 'AsyncIterator')
327
+
328
+
329
+ class AsyncIterable:
330
+ """Generic alias for an async iterable."""
331
+
332
+ def __class_getitem__(cls, params):
333
+ if not Array.isArray(params):
334
+ params = [params]
335
+ return _GenericAlias(None, params, 'AsyncIterable')
336
+
337
+
338
+ # ── IO type aliases ────────────────────────────────────────────────────────────
339
+
340
+ class IO:
341
+ """Generic IO type; IO[str] for text or IO[bytes] for binary."""
342
+
343
+ def __class_getitem__(cls, params):
344
+ if not Array.isArray(params):
345
+ params = [params]
346
+ return _GenericAlias(None, params, 'IO')
347
+
348
+
349
+ class TextIO:
350
+ """Text-mode IO stream (IO[str])."""
351
+ pass
352
+
353
+
354
+ class BinaryIO:
355
+ """Binary-mode IO stream (IO[bytes])."""
356
+ pass
357
+
358
+
359
+ # ── Pattern / Match aliases (for re module) ────────────────────────────────────
360
+
361
+ class Pattern:
362
+ """Generic alias for compiled regular-expression pattern objects."""
363
+
364
+ def __class_getitem__(cls, params):
365
+ if not Array.isArray(params):
366
+ params = [params]
367
+ return _GenericAlias(None, params, 'Pattern')
368
+
369
+
370
+ class Match:
371
+ """Generic alias for regular-expression match objects."""
372
+
373
+ def __class_getitem__(cls, params):
374
+ if not Array.isArray(params):
375
+ params = [params]
376
+ return _GenericAlias(None, params, 'Match')
377
+
378
+
379
+ # ── TypeVar ────────────────────────────────────────────────────────────────────
380
+
381
+ class TypeVar:
382
+ """Type variable. Used to parameterise generic classes and functions.
383
+
384
+ Example::
385
+
386
+ from typing import TypeVar
387
+ T = TypeVar('T')
388
+ S = TypeVar('S', str, bytes) # constrained TypeVar
389
+ """
390
+
391
+ def __init__(self, name, *constraints):
392
+ self.__name__ = name
393
+ self.__constraints__ = constraints
394
+ self.__bound__ = None
395
+ self.__covariant__ = False
396
+ self.__contravariant__ = False
397
+
398
+ def __repr__(self):
399
+ return '~' + self.__name__
400
+
401
+
402
+ # ── Generic and Protocol base classes ─────────────────────────────────────────
403
+
404
+ class Generic:
405
+ """Base class for generic classes.
406
+
407
+ Example::
408
+
409
+ from typing import Generic, TypeVar
410
+ T = TypeVar('T')
411
+ class Stack(Generic[T]):
412
+ def push(self, item: T) -> None: ...
413
+ def pop(self) -> T: ...
414
+ """
415
+
416
+ def __class_getitem__(cls, params):
417
+ if not Array.isArray(params):
418
+ params = [params]
419
+ return _GenericAlias(cls, params)
420
+
421
+
422
+ class Protocol:
423
+ """Base class for protocol classes (structural subtyping).
424
+
425
+ Example::
426
+
427
+ from typing import Protocol, runtime_checkable
428
+ @runtime_checkable
429
+ class Drawable(Protocol):
430
+ def draw(self) -> None: ...
431
+ """
432
+
433
+ def __class_getitem__(cls, params):
434
+ if not Array.isArray(params):
435
+ params = [params]
436
+ return _GenericAlias(cls, params)
437
+
438
+
439
+ # ── Utility functions and decorators ──────────────────────────────────────────
440
+
441
+ def cast(typ, val):
442
+ """Cast *val* to type *typ*.
443
+
444
+ At runtime this is a no-op: *val* is returned unchanged. Type checkers
445
+ treat the result as having type *typ*.
446
+ """
447
+ return val
448
+
449
+
450
+ def overload(func):
451
+ """Decorator for overloaded function definitions.
452
+
453
+ Returns *func* unchanged; the last non-``@overload``-decorated definition
454
+ is the one called at runtime.
455
+ """
456
+ return func
457
+
458
+
459
+ def no_type_check(arg):
460
+ """Decorator to opt a function or class out of type checking."""
461
+ return arg
462
+
463
+
464
+ def no_type_check_decorator(decorator):
465
+ """Decorator that disables type checking for the decorated decorator."""
466
+ return decorator
467
+
468
+
469
+ def runtime_checkable(cls):
470
+ """Decorator to mark a Protocol as runtime-checkable via isinstance()."""
471
+ return cls
472
+
473
+
474
+ def get_type_hints(obj, globalns=None, localns=None):
475
+ """Return the type hints for *obj* (a function, method, module, or class).
476
+
477
+ Returns a copy of ``obj.__annotations__``, or an empty dict when the
478
+ object carries no annotations.
479
+ """
480
+ a = obj.__annotations__
481
+ if jstype(a) is 'undefined' or a is None:
482
+ return {}
483
+ result = {}
484
+ keys = Object.keys(a)
485
+ for i in range(keys.length):
486
+ k = keys[i]
487
+ result[k] = a[k]
488
+ return result
489
+
490
+
491
+ # ── TypedDict ──────────────────────────────────────────────────────────────────
492
+
493
+ class TypedDict:
494
+ """Base class for typed dictionaries (class-based syntax).
495
+
496
+ Example::
497
+
498
+ from typing import TypedDict
499
+
500
+ class Movie(TypedDict):
501
+ name: str
502
+ year: int
503
+
504
+ At runtime, TypedDict subclasses are plain classes; no type enforcement
505
+ occurs. Fields are declared via class-body annotations and accessible
506
+ via normal attribute access on instances.
507
+ """
508
+ pass
509
+
510
+
511
+ # ── NamedTuple factory (functional form) ───────────────────────────────────────
512
+
513
+ def NamedTuple(typename, fields):
514
+ """Create a typed named-tuple class (functional form).
515
+
516
+ *fields* is a list of (name, type) pairs::
517
+
518
+ from typing import NamedTuple
519
+ Point = NamedTuple('Point', [('x', float), ('y', float)])
520
+ p = Point(1.0, 2.0)
521
+ print(p.x) # 1.0
522
+ print(p.y) # 2.0
523
+
524
+ The returned class stores fields as plain attributes, carries a
525
+ ``__annotations__`` dict of name → type, and supports positional
526
+ construction.
527
+ """
528
+ field_names = [f[0] for f in fields]
529
+ annotations = {f[0]: f[1] for f in fields}
530
+ n = len(field_names)
531
+
532
+ class _NT:
533
+ def __init__(self, *args):
534
+ for i in range(n):
535
+ name = field_names[i]
536
+ val = args[i] if i < args.length else None
537
+ v'this[name] = val'
538
+
539
+ def __getitem__(self, idx):
540
+ if idx < 0:
541
+ idx = n + idx
542
+ if idx < 0 or idx >= n:
543
+ raise IndexError('tuple index out of range')
544
+ return v'this[field_names[idx]]'
545
+
546
+ def __repr__(self):
547
+ parts = []
548
+ for i in range(n):
549
+ val = v'this[field_names[i]]'
550
+ parts.append(repr(val))
551
+ return typename + '(' + ', '.join(parts) + ')'
552
+
553
+ _NT.__name__ = typename
554
+ _NT.__annotations__ = annotations
555
+ return _NT
556
+
557
+
558
+ # ── ByteString ─────────────────────────────────────────────────────────────────
559
+
560
+ class ByteString:
561
+ """Type covering bytes-like objects: bytes and bytearray.
562
+
563
+ Use as a type annotation when a function accepts any bytes-like object::
564
+
565
+ from typing import ByteString
566
+ def process(data: ByteString) -> None: ...
567
+ """
568
+ pass
569
+
570
+
571
+ # ── Convenience aliases ────────────────────────────────────────────────────────
572
+
573
+ # AnyStr: a TypeVar constrained to str or bytes
574
+ AnyStr = TypeVar('AnyStr', str, bytes)
575
+
576
+ # Python 2 → Python 3 compatibility alias
577
+ Text = str