]> crepu.dev Git - config.git/blame - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/black/nodes.py
ActualizaciĆ³n de Readme
[config.git] / djavu-asus / elpy / rpc-venv / lib / python3.11 / site-packages / black / nodes.py
CommitLineData
53e6db90
DC
1"""
2blib2to3 Node/Leaf transformation-related utility functions.
3"""
4
5import sys
6from typing import Final, Generic, Iterator, List, Optional, Set, Tuple, TypeVar, Union
7
8if sys.version_info >= (3, 10):
9 from typing import TypeGuard
10else:
11 from typing_extensions import TypeGuard
12
13from mypy_extensions import mypyc_attr
14
15from black.cache import CACHE_DIR
16from black.mode import Mode, Preview
17from black.strings import has_triple_quotes
18from blib2to3 import pygram
19from blib2to3.pgen2 import token
20from blib2to3.pytree import NL, Leaf, Node, type_repr
21
22pygram.initialize(CACHE_DIR)
23syms: Final = pygram.python_symbols
24
25
26# types
27T = TypeVar("T")
28LN = Union[Leaf, Node]
29LeafID = int
30NodeType = int
31
32
33WHITESPACE: Final = {token.DEDENT, token.INDENT, token.NEWLINE}
34STATEMENT: Final = {
35 syms.if_stmt,
36 syms.while_stmt,
37 syms.for_stmt,
38 syms.try_stmt,
39 syms.except_clause,
40 syms.with_stmt,
41 syms.funcdef,
42 syms.classdef,
43 syms.match_stmt,
44 syms.case_block,
45}
46STANDALONE_COMMENT: Final = 153
47token.tok_name[STANDALONE_COMMENT] = "STANDALONE_COMMENT"
48LOGIC_OPERATORS: Final = {"and", "or"}
49COMPARATORS: Final = {
50 token.LESS,
51 token.GREATER,
52 token.EQEQUAL,
53 token.NOTEQUAL,
54 token.LESSEQUAL,
55 token.GREATEREQUAL,
56}
57MATH_OPERATORS: Final = {
58 token.VBAR,
59 token.CIRCUMFLEX,
60 token.AMPER,
61 token.LEFTSHIFT,
62 token.RIGHTSHIFT,
63 token.PLUS,
64 token.MINUS,
65 token.STAR,
66 token.SLASH,
67 token.DOUBLESLASH,
68 token.PERCENT,
69 token.AT,
70 token.TILDE,
71 token.DOUBLESTAR,
72}
73STARS: Final = {token.STAR, token.DOUBLESTAR}
74VARARGS_SPECIALS: Final = STARS | {token.SLASH}
75VARARGS_PARENTS: Final = {
76 syms.arglist,
77 syms.argument, # double star in arglist
78 syms.trailer, # single argument to call
79 syms.typedargslist,
80 syms.varargslist, # lambdas
81}
82UNPACKING_PARENTS: Final = {
83 syms.atom, # single element of a list or set literal
84 syms.dictsetmaker,
85 syms.listmaker,
86 syms.testlist_gexp,
87 syms.testlist_star_expr,
88 syms.subject_expr,
89 syms.pattern,
90}
91TEST_DESCENDANTS: Final = {
92 syms.test,
93 syms.lambdef,
94 syms.or_test,
95 syms.and_test,
96 syms.not_test,
97 syms.comparison,
98 syms.star_expr,
99 syms.expr,
100 syms.xor_expr,
101 syms.and_expr,
102 syms.shift_expr,
103 syms.arith_expr,
104 syms.trailer,
105 syms.term,
106 syms.power,
107}
108TYPED_NAMES: Final = {syms.tname, syms.tname_star}
109ASSIGNMENTS: Final = {
110 "=",
111 "+=",
112 "-=",
113 "*=",
114 "@=",
115 "/=",
116 "%=",
117 "&=",
118 "|=",
119 "^=",
120 "<<=",
121 ">>=",
122 "**=",
123 "//=",
124}
125
126IMPLICIT_TUPLE: Final = {syms.testlist, syms.testlist_star_expr, syms.exprlist}
127BRACKET: Final = {
128 token.LPAR: token.RPAR,
129 token.LSQB: token.RSQB,
130 token.LBRACE: token.RBRACE,
131}
132OPENING_BRACKETS: Final = set(BRACKET.keys())
133CLOSING_BRACKETS: Final = set(BRACKET.values())
134BRACKETS: Final = OPENING_BRACKETS | CLOSING_BRACKETS
135ALWAYS_NO_SPACE: Final = CLOSING_BRACKETS | {token.COMMA, STANDALONE_COMMENT}
136
137RARROW = 55
138
139
140@mypyc_attr(allow_interpreted_subclasses=True)
141class Visitor(Generic[T]):
142 """Basic lib2to3 visitor that yields things of type `T` on `visit()`."""
143
144 def visit(self, node: LN) -> Iterator[T]:
145 """Main method to visit `node` and its children.
146
147 It tries to find a `visit_*()` method for the given `node.type`, like
148 `visit_simple_stmt` for Node objects or `visit_INDENT` for Leaf objects.
149 If no dedicated `visit_*()` method is found, chooses `visit_default()`
150 instead.
151
152 Then yields objects of type `T` from the selected visitor.
153 """
154 if node.type < 256:
155 name = token.tok_name[node.type]
156 else:
157 name = str(type_repr(node.type))
158 # We explicitly branch on whether a visitor exists (instead of
159 # using self.visit_default as the default arg to getattr) in order
160 # to save needing to create a bound method object and so mypyc can
161 # generate a native call to visit_default.
162 visitf = getattr(self, f"visit_{name}", None)
163 if visitf:
164 yield from visitf(node)
165 else:
166 yield from self.visit_default(node)
167
168 def visit_default(self, node: LN) -> Iterator[T]:
169 """Default `visit_*()` implementation. Recurses to children of `node`."""
170 if isinstance(node, Node):
171 for child in node.children:
172 yield from self.visit(child)
173
174
175def whitespace(leaf: Leaf, *, complex_subscript: bool, mode: Mode) -> str: # noqa: C901
176 """Return whitespace prefix if needed for the given `leaf`.
177
178 `complex_subscript` signals whether the given leaf is part of a subscription
179 which has non-trivial arguments, like arithmetic expressions or function calls.
180 """
181 NO: Final[str] = ""
182 SPACE: Final[str] = " "
183 DOUBLESPACE: Final[str] = " "
184 t = leaf.type
185 p = leaf.parent
186 v = leaf.value
187 if t in ALWAYS_NO_SPACE:
188 return NO
189
190 if t == token.COMMENT:
191 return DOUBLESPACE
192
193 assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}"
194 if t == token.COLON and p.type not in {
195 syms.subscript,
196 syms.subscriptlist,
197 syms.sliceop,
198 }:
199 return NO
200
201 prev = leaf.prev_sibling
202 if not prev:
203 prevp = preceding_leaf(p)
204 if not prevp or prevp.type in OPENING_BRACKETS:
205 return NO
206
207 if t == token.COLON:
208 if prevp.type == token.COLON:
209 return NO
210
211 elif prevp.type != token.COMMA and not complex_subscript:
212 return NO
213
214 return SPACE
215
216 if prevp.type == token.EQUAL:
217 if prevp.parent:
218 if prevp.parent.type in {
219 syms.arglist,
220 syms.argument,
221 syms.parameters,
222 syms.varargslist,
223 }:
224 return NO
225
226 elif prevp.parent.type == syms.typedargslist:
227 # A bit hacky: if the equal sign has whitespace, it means we
228 # previously found it's a typed argument. So, we're using
229 # that, too.
230 return prevp.prefix
231
232 elif (
233 prevp.type == token.STAR
234 and parent_type(prevp) == syms.star_expr
235 and parent_type(prevp.parent) == syms.subscriptlist
236 ):
237 # No space between typevar tuples.
238 return NO
239
240 elif prevp.type in VARARGS_SPECIALS:
241 if is_vararg(prevp, within=VARARGS_PARENTS | UNPACKING_PARENTS):
242 return NO
243
244 elif prevp.type == token.COLON:
245 if prevp.parent and prevp.parent.type in {syms.subscript, syms.sliceop}:
246 return SPACE if complex_subscript else NO
247
248 elif (
249 prevp.parent
250 and prevp.parent.type == syms.factor
251 and prevp.type in MATH_OPERATORS
252 ):
253 return NO
254
255 elif prevp.type == token.AT and p.parent and p.parent.type == syms.decorator:
256 # no space in decorators
257 return NO
258
259 elif prev.type in OPENING_BRACKETS:
260 return NO
261
262 if p.type in {syms.parameters, syms.arglist}:
263 # untyped function signatures or calls
264 if not prev or prev.type != token.COMMA:
265 return NO
266
267 elif p.type == syms.varargslist:
268 # lambdas
269 if prev and prev.type != token.COMMA:
270 return NO
271
272 elif p.type == syms.typedargslist:
273 # typed function signatures
274 if not prev:
275 return NO
276
277 if t == token.EQUAL:
278 if prev.type not in TYPED_NAMES:
279 return NO
280
281 elif prev.type == token.EQUAL:
282 # A bit hacky: if the equal sign has whitespace, it means we
283 # previously found it's a typed argument. So, we're using that, too.
284 return prev.prefix
285
286 elif prev.type != token.COMMA:
287 return NO
288
289 elif p.type in TYPED_NAMES:
290 # type names
291 if not prev:
292 prevp = preceding_leaf(p)
293 if not prevp or prevp.type != token.COMMA:
294 return NO
295
296 elif p.type == syms.trailer:
297 # attributes and calls
298 if t == token.LPAR or t == token.RPAR:
299 return NO
300
301 if not prev:
302 if t == token.DOT or t == token.LSQB:
303 return NO
304
305 elif prev.type != token.COMMA:
306 return NO
307
308 elif p.type == syms.argument:
309 # single argument
310 if t == token.EQUAL:
311 return NO
312
313 if not prev:
314 prevp = preceding_leaf(p)
315 if not prevp or prevp.type == token.LPAR:
316 return NO
317
318 elif prev.type in {token.EQUAL} | VARARGS_SPECIALS:
319 return NO
320
321 elif p.type == syms.decorator:
322 # decorators
323 return NO
324
325 elif p.type == syms.dotted_name:
326 if prev:
327 return NO
328
329 prevp = preceding_leaf(p)
330 if not prevp or prevp.type == token.AT or prevp.type == token.DOT:
331 return NO
332
333 elif p.type == syms.classdef:
334 if t == token.LPAR:
335 return NO
336
337 if prev and prev.type == token.LPAR:
338 return NO
339
340 elif p.type in {syms.subscript, syms.sliceop}:
341 # indexing
342 if not prev:
343 assert p.parent is not None, "subscripts are always parented"
344 if p.parent.type == syms.subscriptlist:
345 return SPACE
346
347 return NO
348
349 elif Preview.walrus_subscript in mode and (
350 t == token.COLONEQUAL or prev.type == token.COLONEQUAL
351 ):
352 return SPACE
353
354 elif not complex_subscript:
355 return NO
356
357 elif p.type == syms.atom:
358 if prev and t == token.DOT:
359 # dots, but not the first one.
360 return NO
361
362 elif p.type == syms.dictsetmaker:
363 # dict unpacking
364 if prev and prev.type == token.DOUBLESTAR:
365 return NO
366
367 elif p.type in {syms.factor, syms.star_expr}:
368 # unary ops
369 if not prev:
370 prevp = preceding_leaf(p)
371 if not prevp or prevp.type in OPENING_BRACKETS:
372 return NO
373
374 prevp_parent = prevp.parent
375 assert prevp_parent is not None
376 if prevp.type == token.COLON and prevp_parent.type in {
377 syms.subscript,
378 syms.sliceop,
379 }:
380 return NO
381
382 elif prevp.type == token.EQUAL and prevp_parent.type == syms.argument:
383 return NO
384
385 elif t in {token.NAME, token.NUMBER, token.STRING}:
386 return NO
387
388 elif p.type == syms.import_from:
389 if t == token.DOT:
390 if prev and prev.type == token.DOT:
391 return NO
392
393 elif t == token.NAME:
394 if v == "import":
395 return SPACE
396
397 if prev and prev.type == token.DOT:
398 return NO
399
400 elif p.type == syms.sliceop:
401 return NO
402
403 elif p.type == syms.except_clause:
404 if t == token.STAR:
405 return NO
406
407 return SPACE
408
409
410def preceding_leaf(node: Optional[LN]) -> Optional[Leaf]:
411 """Return the first leaf that precedes `node`, if any."""
412 while node:
413 res = node.prev_sibling
414 if res:
415 if isinstance(res, Leaf):
416 return res
417
418 try:
419 return list(res.leaves())[-1]
420
421 except IndexError:
422 return None
423
424 node = node.parent
425 return None
426
427
428def prev_siblings_are(node: Optional[LN], tokens: List[Optional[NodeType]]) -> bool:
429 """Return if the `node` and its previous siblings match types against the provided
430 list of tokens; the provided `node`has its type matched against the last element in
431 the list. `None` can be used as the first element to declare that the start of the
432 list is anchored at the start of its parent's children."""
433 if not tokens:
434 return True
435 if tokens[-1] is None:
436 return node is None
437 if not node:
438 return False
439 if node.type != tokens[-1]:
440 return False
441 return prev_siblings_are(node.prev_sibling, tokens[:-1])
442
443
444def parent_type(node: Optional[LN]) -> Optional[NodeType]:
445 """
446 Returns:
447 @node.parent.type, if @node is not None and has a parent.
448 OR
449 None, otherwise.
450 """
451 if node is None or node.parent is None:
452 return None
453
454 return node.parent.type
455
456
457def child_towards(ancestor: Node, descendant: LN) -> Optional[LN]:
458 """Return the child of `ancestor` that contains `descendant`."""
459 node: Optional[LN] = descendant
460 while node and node.parent != ancestor:
461 node = node.parent
462 return node
463
464
465def replace_child(old_child: LN, new_child: LN) -> None:
466 """
467 Side Effects:
468 * If @old_child.parent is set, replace @old_child with @new_child in
469 @old_child's underlying Node structure.
470 OR
471 * Otherwise, this function does nothing.
472 """
473 parent = old_child.parent
474 if not parent:
475 return
476
477 child_idx = old_child.remove()
478 if child_idx is not None:
479 parent.insert_child(child_idx, new_child)
480
481
482def container_of(leaf: Leaf) -> LN:
483 """Return `leaf` or one of its ancestors that is the topmost container of it.
484
485 By "container" we mean a node where `leaf` is the very first child.
486 """
487 same_prefix = leaf.prefix
488 container: LN = leaf
489 while container:
490 parent = container.parent
491 if parent is None:
492 break
493
494 if parent.children[0].prefix != same_prefix:
495 break
496
497 if parent.type == syms.file_input:
498 break
499
500 if parent.prev_sibling is not None and parent.prev_sibling.type in BRACKETS:
501 break
502
503 container = parent
504 return container
505
506
507def first_leaf_of(node: LN) -> Optional[Leaf]:
508 """Returns the first leaf of the node tree."""
509 if isinstance(node, Leaf):
510 return node
511 if node.children:
512 return first_leaf_of(node.children[0])
513 else:
514 return None
515
516
517def is_arith_like(node: LN) -> bool:
518 """Whether node is an arithmetic or a binary arithmetic expression"""
519 return node.type in {
520 syms.arith_expr,
521 syms.shift_expr,
522 syms.xor_expr,
523 syms.and_expr,
524 }
525
526
527def is_docstring(leaf: Leaf) -> bool:
528 if prev_siblings_are(
529 leaf.parent, [None, token.NEWLINE, token.INDENT, syms.simple_stmt]
530 ):
531 return True
532
533 # Multiline docstring on the same line as the `def`.
534 if prev_siblings_are(leaf.parent, [syms.parameters, token.COLON, syms.simple_stmt]):
535 # `syms.parameters` is only used in funcdefs and async_funcdefs in the Python
536 # grammar. We're safe to return True without further checks.
537 return True
538
539 return False
540
541
542def is_empty_tuple(node: LN) -> bool:
543 """Return True if `node` holds an empty tuple."""
544 return (
545 node.type == syms.atom
546 and len(node.children) == 2
547 and node.children[0].type == token.LPAR
548 and node.children[1].type == token.RPAR
549 )
550
551
552def is_one_tuple(node: LN) -> bool:
553 """Return True if `node` holds a tuple with one element, with or without parens."""
554 if node.type == syms.atom:
555 gexp = unwrap_singleton_parenthesis(node)
556 if gexp is None or gexp.type != syms.testlist_gexp:
557 return False
558
559 return len(gexp.children) == 2 and gexp.children[1].type == token.COMMA
560
561 return (
562 node.type in IMPLICIT_TUPLE
563 and len(node.children) == 2
564 and node.children[1].type == token.COMMA
565 )
566
567
568def is_tuple_containing_walrus(node: LN) -> bool:
569 """Return True if `node` holds a tuple that contains a walrus operator."""
570 if node.type != syms.atom:
571 return False
572 gexp = unwrap_singleton_parenthesis(node)
573 if gexp is None or gexp.type != syms.testlist_gexp:
574 return False
575
576 return any(child.type == syms.namedexpr_test for child in gexp.children)
577
578
579def is_one_sequence_between(
580 opening: Leaf,
581 closing: Leaf,
582 leaves: List[Leaf],
583 brackets: Tuple[int, int] = (token.LPAR, token.RPAR),
584) -> bool:
585 """Return True if content between `opening` and `closing` is a one-sequence."""
586 if (opening.type, closing.type) != brackets:
587 return False
588
589 depth = closing.bracket_depth + 1
590 for _opening_index, leaf in enumerate(leaves):
591 if leaf is opening:
592 break
593
594 else:
595 raise LookupError("Opening paren not found in `leaves`")
596
597 commas = 0
598 _opening_index += 1
599 for leaf in leaves[_opening_index:]:
600 if leaf is closing:
601 break
602
603 bracket_depth = leaf.bracket_depth
604 if bracket_depth == depth and leaf.type == token.COMMA:
605 commas += 1
606 if leaf.parent and leaf.parent.type in {
607 syms.arglist,
608 syms.typedargslist,
609 }:
610 commas += 1
611 break
612
613 return commas < 2
614
615
616def is_walrus_assignment(node: LN) -> bool:
617 """Return True iff `node` is of the shape ( test := test )"""
618 inner = unwrap_singleton_parenthesis(node)
619 return inner is not None and inner.type == syms.namedexpr_test
620
621
622def is_simple_decorator_trailer(node: LN, last: bool = False) -> bool:
623 """Return True iff `node` is a trailer valid in a simple decorator"""
624 return node.type == syms.trailer and (
625 (
626 len(node.children) == 2
627 and node.children[0].type == token.DOT
628 and node.children[1].type == token.NAME
629 )
630 # last trailer can be an argument-less parentheses pair
631 or (
632 last
633 and len(node.children) == 2
634 and node.children[0].type == token.LPAR
635 and node.children[1].type == token.RPAR
636 )
637 # last trailer can be arguments
638 or (
639 last
640 and len(node.children) == 3
641 and node.children[0].type == token.LPAR
642 # and node.children[1].type == syms.argument
643 and node.children[2].type == token.RPAR
644 )
645 )
646
647
648def is_simple_decorator_expression(node: LN) -> bool:
649 """Return True iff `node` could be a 'dotted name' decorator
650
651 This function takes the node of the 'namedexpr_test' of the new decorator
652 grammar and test if it would be valid under the old decorator grammar.
653
654 The old grammar was: decorator: @ dotted_name [arguments] NEWLINE
655 The new grammar is : decorator: @ namedexpr_test NEWLINE
656 """
657 if node.type == token.NAME:
658 return True
659 if node.type == syms.power:
660 if node.children:
661 return (
662 node.children[0].type == token.NAME
663 and all(map(is_simple_decorator_trailer, node.children[1:-1]))
664 and (
665 len(node.children) < 2
666 or is_simple_decorator_trailer(node.children[-1], last=True)
667 )
668 )
669 return False
670
671
672def is_yield(node: LN) -> bool:
673 """Return True if `node` holds a `yield` or `yield from` expression."""
674 if node.type == syms.yield_expr:
675 return True
676
677 if is_name_token(node) and node.value == "yield":
678 return True
679
680 if node.type != syms.atom:
681 return False
682
683 if len(node.children) != 3:
684 return False
685
686 lpar, expr, rpar = node.children
687 if lpar.type == token.LPAR and rpar.type == token.RPAR:
688 return is_yield(expr)
689
690 return False
691
692
693def is_vararg(leaf: Leaf, within: Set[NodeType]) -> bool:
694 """Return True if `leaf` is a star or double star in a vararg or kwarg.
695
696 If `within` includes VARARGS_PARENTS, this applies to function signatures.
697 If `within` includes UNPACKING_PARENTS, it applies to right hand-side
698 extended iterable unpacking (PEP 3132) and additional unpacking
699 generalizations (PEP 448).
700 """
701 if leaf.type not in VARARGS_SPECIALS or not leaf.parent:
702 return False
703
704 p = leaf.parent
705 if p.type == syms.star_expr:
706 # Star expressions are also used as assignment targets in extended
707 # iterable unpacking (PEP 3132). See what its parent is instead.
708 if not p.parent:
709 return False
710
711 p = p.parent
712
713 return p.type in within
714
715
716def is_multiline_string(leaf: Leaf) -> bool:
717 """Return True if `leaf` is a multiline string that actually spans many lines."""
718 return has_triple_quotes(leaf.value) and "\n" in leaf.value
719
720
721def is_stub_suite(node: Node) -> bool:
722 """Return True if `node` is a suite with a stub body."""
723
724 # If there is a comment, we want to keep it.
725 if node.prefix.strip():
726 return False
727
728 if (
729 len(node.children) != 4
730 or node.children[0].type != token.NEWLINE
731 or node.children[1].type != token.INDENT
732 or node.children[3].type != token.DEDENT
733 ):
734 return False
735
736 if node.children[3].prefix.strip():
737 return False
738
739 return is_stub_body(node.children[2])
740
741
742def is_stub_body(node: LN) -> bool:
743 """Return True if `node` is a simple statement containing an ellipsis."""
744 if not isinstance(node, Node) or node.type != syms.simple_stmt:
745 return False
746
747 if len(node.children) != 2:
748 return False
749
750 child = node.children[0]
751 return (
752 not child.prefix.strip()
753 and child.type == syms.atom
754 and len(child.children) == 3
755 and all(leaf == Leaf(token.DOT, ".") for leaf in child.children)
756 )
757
758
759def is_atom_with_invisible_parens(node: LN) -> bool:
760 """Given a `LN`, determines whether it's an atom `node` with invisible
761 parens. Useful in dedupe-ing and normalizing parens.
762 """
763 if isinstance(node, Leaf) or node.type != syms.atom:
764 return False
765
766 first, last = node.children[0], node.children[-1]
767 return (
768 isinstance(first, Leaf)
769 and first.type == token.LPAR
770 and first.value == ""
771 and isinstance(last, Leaf)
772 and last.type == token.RPAR
773 and last.value == ""
774 )
775
776
777def is_empty_par(leaf: Leaf) -> bool:
778 return is_empty_lpar(leaf) or is_empty_rpar(leaf)
779
780
781def is_empty_lpar(leaf: Leaf) -> bool:
782 return leaf.type == token.LPAR and leaf.value == ""
783
784
785def is_empty_rpar(leaf: Leaf) -> bool:
786 return leaf.type == token.RPAR and leaf.value == ""
787
788
789def is_import(leaf: Leaf) -> bool:
790 """Return True if the given leaf starts an import statement."""
791 p = leaf.parent
792 t = leaf.type
793 v = leaf.value
794 return bool(
795 t == token.NAME
796 and (
797 (v == "import" and p and p.type == syms.import_name)
798 or (v == "from" and p and p.type == syms.import_from)
799 )
800 )
801
802
803def is_with_or_async_with_stmt(leaf: Leaf) -> bool:
804 """Return True if the given leaf starts a with or async with statement."""
805 return bool(
806 leaf.type == token.NAME
807 and leaf.value == "with"
808 and leaf.parent
809 and leaf.parent.type == syms.with_stmt
810 ) or bool(
811 leaf.type == token.ASYNC
812 and leaf.next_sibling
813 and leaf.next_sibling.type == syms.with_stmt
814 )
815
816
817def is_async_stmt_or_funcdef(leaf: Leaf) -> bool:
818 """Return True if the given leaf starts an async def/for/with statement.
819
820 Note that `async def` can be either an `async_stmt` or `async_funcdef`,
821 the latter is used when it has decorators.
822 """
823 return bool(
824 leaf.type == token.ASYNC
825 and leaf.parent
826 and leaf.parent.type in {syms.async_stmt, syms.async_funcdef}
827 )
828
829
830def is_type_comment(leaf: Leaf) -> bool:
831 """Return True if the given leaf is a type comment. This function should only
832 be used for general type comments (excluding ignore annotations, which should
833 use `is_type_ignore_comment`). Note that general type comments are no longer
834 used in modern version of Python, this function may be deprecated in the future."""
835 t = leaf.type
836 v = leaf.value
837 return t in {token.COMMENT, STANDALONE_COMMENT} and v.startswith("# type:")
838
839
840def is_type_ignore_comment(leaf: Leaf) -> bool:
841 """Return True if the given leaf is a type comment with ignore annotation."""
842 t = leaf.type
843 v = leaf.value
844 return t in {token.COMMENT, STANDALONE_COMMENT} and is_type_ignore_comment_string(v)
845
846
847def is_type_ignore_comment_string(value: str) -> bool:
848 """Return True if the given string match with type comment with
849 ignore annotation."""
850 return value.startswith("# type: ignore")
851
852
853def wrap_in_parentheses(parent: Node, child: LN, *, visible: bool = True) -> None:
854 """Wrap `child` in parentheses.
855
856 This replaces `child` with an atom holding the parentheses and the old
857 child. That requires moving the prefix.
858
859 If `visible` is False, the leaves will be valueless (and thus invisible).
860 """
861 lpar = Leaf(token.LPAR, "(" if visible else "")
862 rpar = Leaf(token.RPAR, ")" if visible else "")
863 prefix = child.prefix
864 child.prefix = ""
865 index = child.remove() or 0
866 new_child = Node(syms.atom, [lpar, child, rpar])
867 new_child.prefix = prefix
868 parent.insert_child(index, new_child)
869
870
871def unwrap_singleton_parenthesis(node: LN) -> Optional[LN]:
872 """Returns `wrapped` if `node` is of the shape ( wrapped ).
873
874 Parenthesis can be optional. Returns None otherwise"""
875 if len(node.children) != 3:
876 return None
877
878 lpar, wrapped, rpar = node.children
879 if not (lpar.type == token.LPAR and rpar.type == token.RPAR):
880 return None
881
882 return wrapped
883
884
885def ensure_visible(leaf: Leaf) -> None:
886 """Make sure parentheses are visible.
887
888 They could be invisible as part of some statements (see
889 :func:`normalize_invisible_parens` and :func:`visit_import_from`).
890 """
891 if leaf.type == token.LPAR:
892 leaf.value = "("
893 elif leaf.type == token.RPAR:
894 leaf.value = ")"
895
896
897def is_name_token(nl: NL) -> TypeGuard[Leaf]:
898 return nl.type == token.NAME
899
900
901def is_lpar_token(nl: NL) -> TypeGuard[Leaf]:
902 return nl.type == token.LPAR
903
904
905def is_rpar_token(nl: NL) -> TypeGuard[Leaf]:
906 return nl.type == token.RPAR
907
908
909def is_string_token(nl: NL) -> TypeGuard[Leaf]:
910 return nl.type == token.STRING
911
912
913def is_number_token(nl: NL) -> TypeGuard[Leaf]:
914 return nl.type == token.NUMBER
915
916
917def is_part_of_annotation(leaf: Leaf) -> bool:
918 """Returns whether this leaf is part of type annotations."""
919 ancestor = leaf.parent
920 while ancestor is not None:
921 if ancestor.prev_sibling and ancestor.prev_sibling.type == token.RARROW:
922 return True
923 if ancestor.parent and ancestor.parent.type == syms.tname:
924 return True
925 ancestor = ancestor.parent
926 return False