| Conditions | 10 |
| Total Lines | 63 |
| Code Lines | 57 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like mandos.search.chembl.target_traversal.StandardStrategyParser.parse() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | from __future__ import annotations |
||
| 85 | @classmethod |
||
| 86 | def parse( |
||
| 87 | cls, lines: Sequence[str] |
||
| 88 | ) -> Tup[Set[TargetEdgeReqs], Mapping[TargetEdgeReqs, Acceptance]]: |
||
| 89 | pat_type = r"([a-z_]+)" |
||
| 90 | pat_rel = r"([<>~=])" |
||
| 91 | pat_accept = r"(?:accept:([\-*^$]?))?" |
||
| 92 | pat_src_words = r"(?:src:'''(.+?)''')?" |
||
| 93 | pat_dest_words = r"(?:dest:'''(.+?)''')?" |
||
| 94 | comment = r"(?:#(.*))?" |
||
| 95 | pat = f"^ *{pat_type} *{pat_rel} *{pat_type} *{pat_accept} * {pat_src_words} *{pat_dest_words} *{comment} *$" |
||
| 96 | pat = re.compile(pat) |
||
| 97 | to_rel = { |
||
| 98 | ">": TargetRelType.superset_of, |
||
| 99 | "<": TargetRelType.subset_of, |
||
| 100 | "~": TargetRelType.overlaps_with, |
||
| 101 | "=": TargetRelType.equivalent_to, |
||
| 102 | "*": TargetRelType.any_link, |
||
| 103 | ".": TargetRelType.self_link, |
||
| 104 | } |
||
| 105 | to_accept = { |
||
| 106 | "*": Acceptance.always, |
||
| 107 | "-": Acceptance.never, |
||
| 108 | "^": Acceptance.at_start, |
||
| 109 | "$": Acceptance.at_end, |
||
| 110 | } |
||
| 111 | edges = set() |
||
| 112 | edge_to_acceptance: Dict[TargetEdgeReqs, Acceptance] = {} |
||
| 113 | for line in lines: |
||
| 114 | match = pat.fullmatch(line) |
||
| 115 | if match is None: |
||
| 116 | raise AssertionError(f"Could not parse line '{line}'") |
||
| 117 | try: |
||
| 118 | src_str = match.group(1).lower() |
||
| 119 | sources = TargetType.all_types() if src_str == "any" else [TargetType[src_str]] |
||
| 120 | rel = to_rel[match.group(2)] |
||
| 121 | dest_str = match.group(3).lower() |
||
| 122 | targets = TargetType.all_types() if dest_str == "any" else [TargetType[dest_str]] |
||
| 123 | accept = to_accept[match.group(4).lower()] |
||
| 124 | src_pat = ( |
||
| 125 | None |
||
| 126 | if match.group(5) is None or match.group(5) == "" |
||
| 127 | else re.compile(match.group(5)) |
||
| 128 | ) |
||
| 129 | dest_pat = ( |
||
| 130 | None |
||
| 131 | if match.group(6) is None or match.group(6) == "" |
||
| 132 | else re.compile(match.group(6)) |
||
| 133 | ) |
||
| 134 | except (KeyError, TypeError, sre_compile.error): |
||
| 135 | raise AssertionError(f"Could not parse line '{line}'") |
||
| 136 | for source in sources: |
||
| 137 | for dest in targets: |
||
| 138 | edge = TargetEdgeReqs( |
||
| 139 | src_type=source, |
||
| 140 | src_pattern=src_pat, |
||
| 141 | rel_type=rel, |
||
| 142 | dest_type=dest, |
||
| 143 | dest_pattern=dest_pat, |
||
| 144 | ) |
||
| 145 | edges.add(edge) |
||
| 146 | edge_to_acceptance[edge] = accept |
||
| 147 | return edges, edge_to_acceptance |
||
| 148 | |||
| 243 |