Coverage for /home/deng/Projects/ete4/hackathon/ete4/ete4/smartview/renderer/nodestyle.py: 60%

25 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2024-03-21 09:19 +0100

1import re 

2 

3from ete4.utils import SVG_COLORS 

4 

5_LINE_TYPE_CHECKER = lambda x: x in (0, 1, 2) # 0 solid, 1 dashed, 2 dotted 

6_SIZE_CHECKER = lambda x: isinstance(x, int) 

7_COLOR_MATCH = re.compile("^#[A-Fa-f\d]{6}$") 

8_COLOR_CHECKER = lambda x: x.lower() in SVG_COLORS or re.match(_COLOR_MATCH, x) 

9_NODE_TYPE_CHECKER = lambda x: x in ["triangle", "circle", "square"] 

10_BOOL_CHECKER = lambda x: isinstance(x, bool) or x in (0, 1) 

11_FLOAT_CHECKER = lambda x: isinstance(x, float) or isinstance(x, int) 

12 

13 

14NODE_STYLE_DEFAULT = [ 

15 ["fgcolor", "#0030c1", _COLOR_CHECKER], 

16 ["bgcolor", "transparent", _COLOR_CHECKER], 

17 ["fgopacity", 1, _FLOAT_CHECKER], 

18 ["outline_line_color", "#000000", _COLOR_CHECKER], 

19 ["outline_line_width", 0.5, _SIZE_CHECKER], 

20 ["outline_color", "#e5e5e5", _COLOR_CHECKER], 

21 ["outline_opacity", 0.3, _FLOAT_CHECKER], 

22 ["vt_line_color", "#000000", _COLOR_CHECKER], 

23 ["hz_line_color", "#000000", _COLOR_CHECKER], 

24 ["hz_line_type", 0, _LINE_TYPE_CHECKER], 

25 ["vt_line_type", 0, _LINE_TYPE_CHECKER], 

26 ["size", 0, _SIZE_CHECKER], # node circle size 

27 ["shape", "circle", _NODE_TYPE_CHECKER], # circle, square, triangle 

28 ["draw_descendants", True, _BOOL_CHECKER], 

29 ["hz_line_width", 0.5, _SIZE_CHECKER], 

30 ["vt_line_width", 0.5, _SIZE_CHECKER] 

31] 

32 

33 

34# _smfaces and faces are registered to allow deepcopy to work on nodes 

35VALID_NODE_STYLE_KEYS = {i[0] for i in NODE_STYLE_DEFAULT} | {"_smfaces"} 

36 

37class NodeStyle(dict): 

38 """ 

39 Dictionary with all valid node graphical attributes. 

40 """ 

41 

42 def __init__(self, *args, **kargs): 

43 """ 

44 For all possible parameters, see NODE_STYLE_DEFAULT. Some descriptions: 

45 

46 :param True draw_descendants: Mark an internal node as a leaf. 

47 :param 0 hz_line_width: Horizontal line width in pixels. If 0 

48 it is automatic (normally 1 pixel). 

49 :param 0 vt_line_width: Vertical line width in pixels. If 0 it 

50 is automatic (normally 1 pixel). 

51 """ 

52 super().__init__(*args, **kargs) 

53 self.init() 

54 

55 def init(self): 

56 for key, dvalue, checker in NODE_STYLE_DEFAULT: 

57 if key not in self: 

58 self[key] = dvalue 

59 elif not checker(self[key]): 

60 raise ValueError("'%s' attribute in node style has not a valid value: %s" % 

61 (key, self[key])) 

62 

63 def __setitem__(self, i, v): 

64 if i not in VALID_NODE_STYLE_KEYS: 

65 raise ValueError("'%s' is not a valid keyword for a NodeStyle instance" % i) 

66 

67 super().__setitem__(i, v)