Skip to content

Commit ad9c7da

Browse files
committed
resolver / refactor (squash me)
1 parent 33276c9 commit ad9c7da

File tree

1 file changed

+53
-22
lines changed

1 file changed

+53
-22
lines changed

openapi_python_client/resolver/schema_resolver.py

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,18 @@ def __init__(self, url_or_path: Union[str, Path]):
1717
raise ValueError("Invalid document root reference, it shall be an remote url or local file path")
1818

1919
self._root_path: Union[Path, None] = None
20-
self._root_path_dir: Union[Path, None] = None
2120
self._root_url: Union[str, None] = None
2221
self._root_url_scheme: Union[str, None] = None
22+
self._parent_path: str
2323

2424
if self._isapath(url_or_path):
2525
url_or_path = cast(Path, url_or_path)
2626
self._root_path = url_or_path.absolute()
27-
self._root_path_dir = self._root_path.parent
27+
self._parent_path = str(self._root_path.parent)
2828
else:
2929
url_or_path = cast(str, url_or_path)
3030
self._root_url = url_or_path
31+
self._parent_path = url_or_path
3132
try:
3233
self._root_url_scheme = urllib.parse.urlparse(url_or_path).scheme
3334
if self._root_url_scheme not in ["http", "https"]:
@@ -44,59 +45,89 @@ def resolve(self, recursive: bool = True) -> ResolvedSchema:
4445
root_schema: SchemaData
4546
external_schemas: Dict[str, SchemaData] = {}
4647
errors: List[str] = []
48+
parent: str
4749

4850
if self._root_path:
4951
root_schema = self._fetch_remote_file_path(self._root_path)
5052
elif self._root_url:
5153
root_schema = self._fetch_url_reference(self._root_url)
5254

53-
self._resolve_schema_references(root_schema, external_schemas, errors, recursive)
55+
self._resolve_schema_references(self._parent_path, root_schema, external_schemas, errors, recursive)
5456
return ResolvedSchema(root_schema, external_schemas, errors)
5557

5658
def _resolve_schema_references(
57-
self, root: SchemaData, external_schemas: Dict[str, SchemaData], errors: List[str], recursive: bool
59+
self,
60+
parent: str,
61+
root: SchemaData,
62+
external_schemas: Dict[str, SchemaData],
63+
errors: List[str],
64+
recursive: bool,
5865
) -> None:
5966

6067
for ref in self._lookup_schema_references(root):
6168
if ref.is_local():
6269
continue
6370

6471
try:
65-
path = ref.value.split("#")[0]
72+
path = self._absolute_path(ref.path, parent)
73+
parent = self._parent(path)
74+
6675
if path in external_schemas:
6776
continue
6877

69-
if ref.is_url():
70-
external_schemas[path] = self._fetch_url_reference(path)
71-
else:
72-
external_schemas[path] = self._fetch_remote_reference(path)
78+
external_schemas[path] = self._fetch_remote_reference(path)
7379

7480
if recursive:
75-
self._resolve_schema_references(external_schemas[path], external_schemas, errors, recursive)
81+
self._resolve_schema_references(parent, external_schemas[path], external_schemas, errors, recursive)
7682

7783
except Exception:
78-
errors.append("Failed to gather external reference data of {0}".format(ref.value))
79-
logging.exception("Failed to gather external reference data of {0}".format(ref.value))
84+
errors.append(f"Failed to gather external reference data of {ref.value} from {path}")
85+
logging.exception(f"Failed to gather external reference data of {ref.value} from {path}")
8086

81-
def _fetch_remote_reference(self, relative_path: str) -> SchemaData:
82-
assert self._root_path_dir or self._root_url
87+
def _parent(self, abs_path: str) -> str:
88+
if abs_path.startswith("http", 0):
89+
return urllib.parse.urljoin(f"{abs_path}/", "..")
90+
else:
91+
path = Path(abs_path)
92+
return str(path.parent)
93+
94+
def _absolute_path(self, relative_path: str, parent: str) -> str:
95+
if relative_path.startswith("http", 0):
96+
return relative_path
97+
98+
if relative_path.startswith("//"):
99+
if parent.startswith("http"):
100+
scheme = urllib.parse.urlparse(parent).scheme
101+
return f"{scheme}:{relative_path}"
102+
else:
103+
scheme = self._root_url_scheme or "http"
104+
return f"{scheme}:{relative_path}"
105+
106+
if parent.startswith("http"):
107+
return urllib.parse.urljoin(parent, relative_path)
108+
else:
109+
parent_dir = Path(parent)
110+
abs_path = parent_dir.joinpath(relative_path)
111+
abs_path = abs_path.resolve()
112+
return str(abs_path)
83113

84-
if self._root_path_dir:
85-
abs_path = self._root_path_dir.joinpath(relative_path)
86-
return self._fetch_remote_file_path(abs_path)
87-
elif self._root_url:
88-
abs_url = urllib.parse.urljoin(self._root_url, relative_path)
89-
return self._fetch_url_reference(abs_url)
114+
def _fetch_remote_reference(self, abs_path: str) -> SchemaData:
115+
res: SchemaData
116+
117+
if abs_path.startswith("http"):
118+
res = self._fetch_url_reference(abs_path)
90119
else:
91-
raise RuntimeError("Bad object initilalization")
120+
res = self._fetch_remote_file_path(Path(abs_path))
121+
122+
return res
92123

93124
def _fetch_remote_file_path(self, path: Path) -> SchemaData:
94125
logging.info(f"Fetching remote ref file path > {path}")
95126
return DataLoader.load(str(path), path.read_bytes())
96127

97128
def _fetch_url_reference(self, url: str) -> SchemaData:
98129
if url.startswith("//", 0):
99-
url = "{0}:{1}".format(self._root_url_scheme, url)
130+
url = "{0}:{1}".format((self._root_url_scheme or "http"), url)
100131

101132
logging.info(f"Fetching remote ref url > {url}")
102133
return DataLoader.load(url, httpx.get(url).content)

0 commit comments

Comments
 (0)