| Conditions | 13 |
| Total Lines | 79 |
| Code Lines | 36 |
| Lines | 0 |
| Ratio | 0 % |
| Tests | 30 |
| CRAP Score | 13 |
| 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 build.models.path.DynamicPathManager.get_disjoint_paths() 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 | """Classes related to paths""" |
||
| 181 | 1 | @classmethod |
|
| 182 | 1 | def get_disjoint_paths( |
|
| 183 | cls, circuit, unwanted_path, cutoff=settings.DISJOINT_PATH_CUTOFF |
||
| 184 | ): |
||
| 185 | """Computes the maximum disjoint paths from the unwanted_path for a EVC |
||
| 186 | |||
| 187 | Maximum disjoint paths from the unwanted_path are the paths from the |
||
| 188 | source node to the target node that share the minimum number of links |
||
| 189 | and switches contained in unwanted_path. In other words, unwanted_path |
||
| 190 | is the path we want to avoid: we want the maximum possible disjoint |
||
| 191 | path from it. The disjointness of a path in regards to unwanted_path |
||
| 192 | is calculated by the complementary percentage of shared links and |
||
| 193 | switches between them. As an example, if the unwanted_path has 3 |
||
| 194 | links and 2 switches, a given path P1 has 1 link shared with |
||
| 195 | unwanted_path, and a given path P2 has 2 links and 1 switch shared |
||
| 196 | with unwanted_path, then the disjointness of P1 is 0.8 and the |
||
| 197 | disjointness of P2 is 0.4. In this example, P1 is preferable over P2 |
||
| 198 | because it offers a better disjoint path. When two paths have the same |
||
| 199 | disjointness they are ordered by 'cost' attributed as returned from |
||
| 200 | Pathfinder. When the disjointness of a path is equal to 0 (i.e., it |
||
| 201 | shares all the links with unwanted_path), that particular path is not |
||
| 202 | considered a candidate. |
||
| 203 | |||
| 204 | Parameters: |
||
| 205 | ----------- |
||
| 206 | |||
| 207 | circuit : EVC |
||
| 208 | The EVC providing source node (uni_a) and target node (uni_z) |
||
| 209 | |||
| 210 | unwanted_path : Path |
||
| 211 | The Path which we want to avoid. |
||
| 212 | |||
| 213 | cutoff: int |
||
| 214 | Maximum number of paths to consider when calculating the disjoint |
||
| 215 | paths (number of paths to request from pathfinder) |
||
| 216 | |||
| 217 | Returns: |
||
| 218 | -------- |
||
| 219 | paths : generator |
||
| 220 | Generator of unwanted_path disjoint paths. If unwanted_path is |
||
| 221 | not provided or empty, we return an empty list. |
||
| 222 | 1 | """ |
|
| 223 | unwanted_links = [ |
||
| 224 | (link.endpoint_a.id, link.endpoint_b.id) for link in unwanted_path |
||
| 225 | 1 | ] |
|
| 226 | 1 | unwanted_switches = set() |
|
| 227 | for link in unwanted_path: |
||
| 228 | 1 | unwanted_switches.add(link.endpoint_a.switch.id) |
|
| 229 | unwanted_switches.add(link.endpoint_b.switch.id) |
||
| 230 | 1 | unwanted_switches.discard(circuit.uni_a.interface.switch.id) |
|
| 231 | 1 | unwanted_switches.discard(circuit.uni_z.interface.switch.id) |
|
| 232 | 1 | ||
| 233 | 1 | unwanted_components_n = (len(unwanted_links) + len(unwanted_switches)) |
|
| 234 | 1 | if not unwanted_links or not unwanted_switches: |
|
| 235 | 1 | return None |
|
| 236 | |||
| 237 | paths = cls.get_paths(circuit, max_paths=cutoff, |
||
| 238 | 1 | **circuit.secondary_constraints) |
|
| 239 | 1 | for path in paths: |
|
| 240 | 1 | head = path["hops"][:-1] |
|
| 241 | 1 | tail = path["hops"][1:] |
|
| 242 | 1 | copy_switches = unwanted_switches.copy() |
|
| 243 | 1 | shared_components = 0 |
|
| 244 | 1 | for (endpoint_a, endpoint_b) in unwanted_links: |
|
| 245 | 1 | if ((endpoint_a, endpoint_b) in zip(head, tail)) or ( |
|
| 246 | (endpoint_b, endpoint_a) in zip(head, tail) |
||
| 247 | 1 | ): |
|
| 248 | 1 | shared_components += 1 |
|
| 249 | for component in path["hops"]: |
||
| 250 | 1 | if component in copy_switches: |
|
| 251 | 1 | shared_components += 1 |
|
| 252 | copy_switches.remove(component) |
||
| 253 | 1 | path["disjointness"] = 1 - shared_components / unwanted_components_n |
|
| 254 | 1 | paths = sorted(paths, key=lambda x: (-x['disjointness'], x['cost'])) |
|
| 255 | for path in paths: |
||
| 256 | 1 | if path["disjointness"] == 0: |
|
| 257 | 1 | continue |
|
| 258 | 1 | yield cls.create_path(path["hops"]) |
|
| 259 | 1 | return None |
|
| 260 | 1 | ||
| 278 |