(self, spec_file: str, index_filename: str, class_names: list[str] | None, dry_run: bool)
| 2403 | return True |
| 2404 | |
| 2405 | def suggest_paths(self, spec_file: str, index_filename: str, class_names: list[str] | None, dry_run: bool) -> bool: |
| 2406 | print(f"Using spec {spec_file}") |
| 2407 | with open(spec_file) as r: |
| 2408 | spec = json.load(r) |
| 2409 | with open(index_filename) as r: |
| 2410 | index = json.load(r) |
| 2411 | |
| 2412 | if not class_names: |
| 2413 | class_names = index.get("classes", {}).keys() |
| 2414 | |
| 2415 | if len(class_names) == 1: |
| 2416 | print(f"Suggesting API paths for PyGithub class {class_names[0]}") |
| 2417 | else: |
| 2418 | print(f"Suggesting API paths for {len(class_names)} PyGithub classes") |
| 2419 | print() |
| 2420 | |
| 2421 | paths = spec.get("paths", {}) |
| 2422 | classes = index.get("classes", {}) |
| 2423 | return_schema_to_paths = index.get("indices", {}).get("return_schema_to_paths") |
| 2424 | if return_schema_to_paths is None: |
| 2425 | raise RuntimeError("OpenAPI spec has not been indexed via openapi.py index") |
| 2426 | implemented_paths = index.get("paths", {}) |
| 2427 | |
| 2428 | self.suggest_path_corrections(paths, implemented_paths) |
| 2429 | |
| 2430 | for cls in class_names: |
| 2431 | clazz = classes.get(cls) |
| 2432 | print(f"Class {cls}") |
| 2433 | for schema in clazz.get("schemas", []): |
| 2434 | print(f"- Implements schema {schema}") |
| 2435 | for path in return_schema_to_paths.get(schema, []): |
| 2436 | print(f" - Returned by path {path}") |
| 2437 | for candidate_path in paths: |
| 2438 | verbs = paths[candidate_path].keys() |
| 2439 | if len(candidate_path) > len(path) and candidate_path.startswith(f"{path}/"): |
| 2440 | rel_path = candidate_path[len(path) + 1 :] |
| 2441 | rel_path_fields = rel_path.split("/") |
| 2442 | rel_path_params = [ |
| 2443 | field.startswith("{") and field.endswith("}") for field in rel_path_fields |
| 2444 | ] |
| 2445 | # we skip paths where multiple path parameters exist, or |
| 2446 | # the path parameter is not at the end of the path |
| 2447 | if sum(rel_path_params) > 1 or sum(rel_path_params) == 1 and not rel_path_params[-1]: |
| 2448 | continue |
| 2449 | |
| 2450 | skip = False |
| 2451 | rel_subpath = [] |
| 2452 | for rel_field in rel_path_fields: |
| 2453 | rel_subpath.append(rel_field) |
| 2454 | subpath = "/".join([path] + rel_subpath) |
| 2455 | for method in implemented_paths.get(subpath, {}).get("GET", {}).get("methods", []): |
| 2456 | for return_type in method.get("returns", []): |
| 2457 | if return_type in classes: |
| 2458 | if self.verbose: |
| 2459 | print(f"\n - Parent path {subpath} returns {return_type}", end="") |
| 2460 | skip = True |
| 2461 | if skip: |
| 2462 | continue |
no test coverage detected