Castle: The best Real-Time/Embedded/HighTech language EVER. Attempt 2
Revision | 30b384e24ddf6da239bc88563416bb1abb73f2ca (tree) |
---|---|
Time | 2022-05-31 03:44:08 |
Author | Albert Mietus < albert AT mietus DOT nl > |
Commiter | Albert Mietus < albert AT mietus DOT nl > |
Added 'make mutmut' Mutation testing -- and fix/whitelisted some trivials
@@ -9,10 +9,17 @@ | ||
9 | 9 | coverage run --branch -m pytest ${PYTEST_OPTONS} pytst/ |
10 | 10 | coverage report --skip-covered |
11 | 11 | coverage html |
12 | +pytest-only: | |
13 | + pytest ${PYTEST_OPTONS} pytst | |
12 | 14 | pytest-s test-s: |
13 | 15 | pytest ${PYTEST_OPTONS} -s pytst |
14 | 16 | test-ds test-sd test-d: |
15 | 17 | pytest ${PYTEST_OPTONS} --log-cli-level=DEBUG -s pytst/ |
18 | +mutmut: | |
19 | + -mutmut run --tests-dir pytst --paths-to-mutate castle | |
20 | + mutmut html && mutmut results | |
21 | + open html/index.html | |
22 | + | |
16 | 23 | |
17 | 24 | demo: pytest-demo python-demo |
18 | 25 |
@@ -45,7 +52,12 @@ | ||
45 | 52 | clean_caches: |
46 | 53 | find . -type d -name __pycache__ -print0 | xargs -0 rm -r |
47 | 54 | find . -type d -name .pytest_cache -print0 | xargs -0 rm -r |
55 | + rm -f ./.coverage | |
56 | + rm -f ./.mutmut-cache | |
48 | 57 | |
58 | +cleaner: clean | |
59 | + rm -rd ./htmlcov/ #coverage | |
60 | + rm -rf ./html # mutmut | |
49 | 61 | |
50 | 62 | PYREVERSE_DIR=pyreversed |
51 | 63 | PYREVERSE_FORMAT=svg |
@@ -6,12 +6,12 @@ | ||
6 | 6 | """Base class for all Castle ATS nodes""" |
7 | 7 | |
8 | 8 | def __init__(self, *, parse_tree=None, **kwargs): |
9 | - assert len(kwargs)==0, "Do not call 'Object' with kwargs (caller is wrong)" | |
9 | + assert len(kwargs)==0, "Do not call 'Object' with kwargs (caller is wrong)" # pragma: no mutate | |
10 | 10 | super().__init__(**kwargs) |
11 | 11 | self._parse_tree = parse_tree |
12 | 12 | |
13 | 13 | def __str__(self): # mostly for debugging |
14 | - return '\n__DEBUG__ ' + str(type(self).__name__) + "\n\t" + "\n\t".join(f'{n}\t{str(v)}:{type(v).__name__}' for n,v in self.__dict__.items() if n[0]!='_') | |
14 | + return '\n__DEBUG__ ' + str(type(self).__name__) + "\n\t" + "\n\t".join(f'{n}\t{str(v)}:{type(v).__name__}' for n,v in self.__dict__.items() if n[0]!='_') # pragma: no mutate | |
15 | 15 | |
16 | 16 | def serialize(self, strategy="XML") -> str: |
17 | 17 | return Serialize(strategy).serialize(self) |
@@ -24,15 +24,15 @@ | ||
24 | 24 | ### Mostly for debugging |
25 | 25 | @staticmethod |
26 | 26 | def _typeName(of): |
27 | - return type(of).__name__ | |
27 | + return type(of).__name__ # pragma: no mutate | |
28 | 28 | |
29 | 29 | def _valType(self, of:None): |
30 | - if not of: of=self | |
31 | - return f'{of}:{self._typeName(of)}' | |
30 | + if not of: of=self # pragma: no mutate | |
31 | + return f'{of}:{self._typeName(of)}' # pragma: no mutate | |
32 | 32 | |
33 | 33 | |
34 | 34 | class IDError(ValueError): |
35 | - "The given ID is not valid as an ID" | |
35 | + "The given ID is not valid as an ID" # pragma: no mutate | |
36 | 36 | |
37 | 37 | |
38 | 38 |
@@ -1,4 +1,4 @@ | ||
1 | -import logging; logger = logging.getLogger(__name__) | |
1 | +import logging; logger = logging.getLogger(__name__) # pragma: no mutate | |
2 | 2 | |
3 | 3 | from ._base import AST_BASE, ID, IDError |
4 | 4 |
@@ -14,14 +14,14 @@ | ||
14 | 14 | """With this MixIn PEG-classes get the ``.value`` property""" |
15 | 15 | |
16 | 16 | def __init__(self, *, value=None, **kwargs): |
17 | - logger.debug(f'{self._typeName(self)}.MixIn_value_attribute:: value:=' + | |
18 | - ('[[' +', '.join(f'{v}:{type(v).__name__}' for v in value) + ']]') if isinstance(value, list) else f's>>{value}<<') | |
17 | + logger.debug(f'{self._typeName(self)}.MixIn_value_attribute:: value:=' + # pragma: no mutate | |
18 | + ('[[' +', '.join(f'{v}:{type(v).__name__}' for v in value) + ']]') if isinstance(value, list) else f's>>{value}<<') # pragma: no mutate | |
19 | 19 | super().__init__(**kwargs) |
20 | 20 | self._value=value |
21 | 21 | |
22 | 22 | @property |
23 | 23 | def value(self): |
24 | - logger.debug(f'{self._typeName(self)}:: @value={self._value}') | |
24 | + logger.debug(f'{self._typeName(self)}:: @value={self._value}') # pragma: no mutate | |
25 | 25 | return self._value |
26 | 26 | |
27 | 27 |
@@ -29,13 +29,13 @@ | ||
29 | 29 | """With this MixIn PEG-classes get the ``.expr`` property""" |
30 | 30 | |
31 | 31 | def __init__(self, *, expr=None, **kwargs): |
32 | - logger.debug(f'{self._typeName(self)}.MixIn_expr_attribute:: expr:={self._valType(expr)}') | |
32 | + logger.debug(f'{self._typeName(self)}.MixIn_expr_attribute:: expr:={self._valType(expr)}') # pragma: no mutate | |
33 | 33 | super().__init__(**kwargs) |
34 | 34 | self._expr = expr |
35 | 35 | |
36 | 36 | @property |
37 | 37 | def expr(self): |
38 | - logger.debug(f'{self._typeName(self)}:: @expr={self._expr}') | |
38 | + logger.debug(f'{self._typeName(self)}:: @expr={self._expr}') # pragma: no mutate | |
39 | 39 | return self._expr |
40 | 40 | |
41 | 41 |
@@ -43,7 +43,7 @@ | ||
43 | 43 | """With this MixIn PEG-class get the ``.children`` property; and sequence-alike methods""" |
44 | 44 | def __init__(self, *, children, **kwargs): |
45 | 45 | logger.debug(f'{self._typeName(self)}.MixIn_children_tuple:: children[{len(children)}]:=' + |
46 | - ('[[' +', '.join(f'{c}:{type(c).__name__}' for c in children) + ']]') if isinstance(children, list) else f's>>{children}<<') | |
46 | + ('[[' +', '.join(f'{c}:{type(c).__name__}' for c in children) + ']]') if isinstance(children, list) else f's>>{children}<<') # pragma: no mutate | |
47 | 47 | super().__init__(**kwargs) |
48 | 48 | self._children = tuple(children) |
49 | 49 |
@@ -53,7 +53,7 @@ | ||
53 | 53 | return self._children[key] |
54 | 54 | def __iter__(self): return self._children.__iter__() |
55 | 55 | def __str__(self): |
56 | - return f"<{type(self).__name__}.MixIn_children_tuple:{len(self)}[" + ",".join(str(c) for c in self) + "]>" | |
56 | + return f"<{type(self).__name__}.MixIn_children_tuple:{len(self)}[" + ",".join(str(c) for c in self) + "]>" # pragma: no mutate | |
57 | 57 | |
58 | 58 | ## |
59 | 59 | ## Note: When using TypeHints with PEG-classes; the clases |
@@ -66,7 +66,7 @@ | ||
66 | 66 | class RegExpTerm(Terminal): pass |
67 | 67 | class Number(Terminal): # Value is stored as a string |
68 | 68 | def __str__(self): # mostly for debugging |
69 | - return f'<"{self.value}">' | |
69 | + return f'<"{self.value}">' # pragma: no mutate | |
70 | 70 | |
71 | 71 | class Markers(PEG): pass # abstract |
72 | 72 | class EOF(Markers): pass # XXX Todo ## singleton? |
@@ -90,9 +90,9 @@ | ||
90 | 90 | def __init__(self, *, |
91 | 91 | name: ID, expr:Expression=None, |
92 | 92 | **kwargs): |
93 | - logger.debug(f'{self._typeName(self)}: name={self._valType(name)}, expr={self._valType(expr)}') | |
93 | + logger.debug(f'{self._typeName(self)}: name={self._valType(name)}, expr={self._valType(expr)}') # pragma: no mutate | |
94 | 94 | if expr: |
95 | - logger.debug("\t" + "; ".join(f'{c}:{type(c)}' for c in expr)) | |
95 | + logger.debug("\t" + "; ".join(f'{c}:{type(c)}' for c in expr)) # pragma: no mutate | |
96 | 96 | if not isinstance(name, ID): raise TypeError(f'Rule-name {name} is not of type ID') |
97 | 97 | super().__init__(**kwargs) |
98 | 98 | self.name = name |
@@ -132,14 +132,14 @@ | ||
132 | 132 | # __init__ (see MixIn) sets self._children; assuming it is a list |
133 | 133 | |
134 | 134 | def __str__(self): # mostly for debugging |
135 | - return "Seq{{" + " ; ".join(f"{c}" for c in self) + "}}" | |
135 | + return "Seq{{" + " ; ".join(f"{c}" for c in self) + "}}" # pragma: no mutate | |
136 | 136 | |
137 | 137 | |
138 | 138 | class OrderedChoice(MixIn_children_tuple, Expression): # A | B | C | ... the order is relevant |
139 | 139 | """OC: A _tuple_ of alternative expressions""" |
140 | 140 | |
141 | 141 | def __str__(self): # mostly for debugging |
142 | - return "OC{{" + " | ".join(f"{c}" for c in self._children) + "}}" | |
142 | + return "OC{{" + " | ".join(f"{c}" for c in self._children) + "}}" # pragma: no mutate | |
143 | 143 | |
144 | 144 | class Optional(Quantity):pass |
145 | 145 | class ZeroOrMore(Quantity):pass |
@@ -37,7 +37,7 @@ | ||
37 | 37 | **kwargs): |
38 | 38 | super().__init__(read_dirs=read_dirs, **kwargs) |
39 | 39 | if language_def is None: |
40 | - raise ValueError("The `language_def` is a mandatory parameter") | |
40 | + raise ValueError("The `language_def` is a mandatory parameter") # pragma: no mutate | |
41 | 41 | # comment_def is allowed to be None |
42 | 42 | if visitor is None: |
43 | 43 | raise ValueError("visitor is a mandatory parameter") |
@@ -29,7 +29,7 @@ | ||
29 | 29 | |
30 | 30 | class PegVisitor(arpeggio.PTNodeVisitor): |
31 | 31 | def _logstr_node_children(self, node, children): |
32 | - return f'>>{node}<< children[{len(children)}] >>' + ", ".join(f'{c}:{type(c).__name__}' for c in children) + '<<' | |
32 | + return f'>>{node}<< children[{len(children)}] >>' + ", ".join(f'{c}:{type(c).__name__}' for c in children) + '<<' # pragma: no mutate | |
33 | 33 | |
34 | 34 | def visit_str_term(self, node, children): |
35 | 35 | return grammar.StrTerm(value=node[1], parse_tree=node) |
@@ -54,27 +54,27 @@ | ||
54 | 54 | '#': grammar.UnorderedGroup} |
55 | 55 | |
56 | 56 | if len(children) == 1: # No Optional part |
57 | - logger.debug(f'visit_single_expr==1:: {getattr(children[0], "name", children[0])}:{type(children[0])}') | |
57 | + logger.debug(f'visit_single_expr==1:: {getattr(children[0], "name", children[0])}:{type(children[0])}') # pragma: no mutate | |
58 | 58 | return children[0] |
59 | 59 | |
60 | 60 | elif len(children) == 2: # Optional part |
61 | - logger.debug(f'visit_single_expr==2::Got: {children[0]}, {children[1]}') | |
61 | + logger.debug(f'visit_single_expr==2::Got: {children[0]}, {children[1]}') # pragma: no mutate | |
62 | 62 | expr = children[0] |
63 | 63 | token = str(children[1]) |
64 | 64 | quantum_cls = token_2_class.get(token) |
65 | 65 | if quantum_cls: |
66 | 66 | ast=quantum_cls(expr=expr, parse_tree=node) |
67 | - logger.debug(f'visit_single_expr==2::Pass: {quantum_cls}(expr={expr})') | |
67 | + logger.debug(f'visit_single_expr==2::Pass: {quantum_cls}(expr={expr})') # pragma: no mutate | |
68 | 68 | return ast |
69 | 69 | else: |
70 | 70 | raise QuantityError(f"token '{token}' not recognised") |
71 | - else: # #children not in (1,2) | |
72 | - raise NotImplementedError("visit_single_expr, len>2") # -- Is this possible? | |
71 | + else: # #children not in (1,2) -- Is this possible? | |
72 | + raise NotImplementedError("visit_single_expr, len>2") # pragma: no mutate | |
73 | 73 | |
74 | 74 | |
75 | 75 | # expression <- sequence, op_alternative; op_alternative <- ('|' expression)? |
76 | 76 | def visit_expression(self, node, children) -> Union[grammar.Sequence, grammar.OrderedChoice]: |
77 | - logger.debug('visit_expression::' + self._logstr_node_children(node, children)) | |
77 | + logger.debug('visit_expression::' + self._logstr_node_children(node, children)) # pragma: no mutate | |
78 | 78 | if len(children) == 1: #Only sequence |
79 | 79 | return children[0] |
80 | 80 | elif len(children) == 2: # So, having 1 or more alternatives in children[1] |
@@ -90,14 +90,14 @@ | ||
90 | 90 | |
91 | 91 | # OneOrMore(single_expr) |
92 | 92 | def visit_sequence(self, node, children) -> grammar.Sequence: |
93 | - logger.debug(f'visit_sequence::{self._logstr_node_children(node, children)}') | |
93 | + logger.debug(f'visit_sequence::{self._logstr_node_children(node, children)}') # pragma: no mutate | |
94 | 94 | return grammar.Sequence(children=children, parse_tree=node) |
95 | 95 | |
96 | 96 | |
97 | 97 | def visit_predicate(self, node, children): |
98 | 98 | token_2_predicate = {'&': grammar.AndPredicate, |
99 | 99 | '!': grammar.NotPredicate} |
100 | - logger.debug(f'visit_predicate:: >>{node}<< #children={len(children)}') | |
100 | + logger.debug(f'visit_predicate:: >>{node}<< #children={len(children)}') # pragma: no mutate | |
101 | 101 | |
102 | 102 | if len(children) == 2: |
103 | 103 | token = children[0] |
@@ -107,12 +107,12 @@ | ||
107 | 107 | return ast |
108 | 108 | else: |
109 | 109 | raise PredicateError(f"token '{token}' not recognised") |
110 | - else: | |
111 | - raise NotImplementedError("visit_predicate, len!=2") # -- Is this possible? | |
110 | + else: # -- Is this possible? | |
111 | + raise NotImplementedError("visit_predicate, len!=2") # pragma: no mutate | |
112 | 112 | |
113 | 113 | |
114 | 114 | def visit_rules(self, node, children): # Mix of `ParseRule`(s)`Setting`(s) ; will be sorted out n `Grammar` |
115 | - logger.debug('visit_rules::' + self._logstr_node_children(node, children)) | |
115 | + logger.debug('visit_rules::' + self._logstr_node_children(node, children)) # pragma: no mutate | |
116 | 116 | return grammar.Rules(children=children[:], parse_tree=node) |
117 | 117 | |
118 | 118 |
@@ -129,5 +129,5 @@ | ||
129 | 129 | return grammar.ID(name=str(node), parse_tree=node) |
130 | 130 | |
131 | 131 | def visit_setting(self, node, children): |
132 | - logger.debug('visit_setting::' + self._logstr_node_children(node, children)) | |
132 | + logger.debug('visit_setting::' + self._logstr_node_children(node, children)) # pragma: no mutate | |
133 | 133 | return grammar.Setting(name=children[0], value=children[1] , parse_tree=node) |