Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/libcst/_maybe_sentinel.py: 80%

5 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-25 06:43 +0000

1# Copyright (c) Meta Platforms, Inc. and affiliates. 

2# 

3# This source code is licensed under the MIT license found in the 

4# LICENSE file in the root directory of this source tree. 

5 

6from enum import auto, Enum 

7 

8 

9class MaybeSentinel(Enum): 

10 """ 

11 A :class:`MaybeSentinel` value is used as the default value for some attributes to 

12 denote that when generating code (when :attr:`Module.code` is evaluated) we should 

13 optionally include this element in order to generate valid code. 

14 

15 :class:`MaybeSentinel` is only used for "syntactic trivia" that most users shouldn't 

16 care much about anyways, like commas, semicolons, and whitespace. 

17 

18 For example, a function call's :attr:`Arg.comma` value defaults to 

19 :attr:`MaybeSentinel.DEFAULT`. A comma is required after every argument, except for 

20 the last one. If a comma is required and :attr:`Arg.comma` is a 

21 :class:`MaybeSentinel`, one is inserted. 

22 

23 This makes manual node construction easier, but it also means that we safely add 

24 arguments to a preexisting function call without manually fixing the commas: 

25 

26 >>> import libcst as cst 

27 >>> fn_call = cst.parse_expression("fn(1, 2)") 

28 >>> new_fn_call = fn_call.with_changes( 

29 ... args=[*fn_call.args, cst.Arg(cst.Integer("3"))] 

30 ... ) 

31 >>> dummy_module = cst.parse_module("") # we need to use Module.code_for_node 

32 >>> dummy_module.code_for_node(fn_call) 

33 'fn(1, 2)' 

34 >>> dummy_module.code_for_node(new_fn_call) 

35 'fn(1, 2, 3)' 

36 

37 Notice that a comma was automatically inserted after the second argument. Since the 

38 original second argument had no comma, it was initialized to 

39 :attr:`MaybeSentinel.DEFAULT`. During the code generation of the second argument, a 

40 comma was inserted to ensure that the resulting code is valid. 

41 

42 .. warning:: 

43 While this sentinel is used in place of nodes, it is not a :class:`CSTNode`, and 

44 will not be visited by a :class:`CSTVisitor`. 

45 

46 Some other libraries, like `RedBaron`_, take other approaches to this problem. 

47 RedBaron's tree is mutable (LibCST's tree is immutable), and so they're able to 

48 solve this problem with `"proxy lists" 

49 <http://redbaron.pycqa.org/en/latest/proxy_list.html>`_. Both approaches come with 

50 different sets of tradeoffs. 

51 

52 .. _RedBaron: http://redbaron.pycqa.org/en/latest/index.html 

53 """ 

54 

55 DEFAULT = auto() 

56 

57 def __repr__(self) -> str: 

58 return str(self)