@@ -17,17 +17,18 @@ def __init__(self, url_or_path: Union[str, Path]):
17
17
raise ValueError ("Invalid document root reference, it shall be an remote url or local file path" )
18
18
19
19
self ._root_path : Union [Path , None ] = None
20
- self ._root_path_dir : Union [Path , None ] = None
21
20
self ._root_url : Union [str , None ] = None
22
21
self ._root_url_scheme : Union [str , None ] = None
22
+ self ._parent_path : str
23
23
24
24
if self ._isapath (url_or_path ):
25
25
url_or_path = cast (Path , url_or_path )
26
26
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 )
28
28
else :
29
29
url_or_path = cast (str , url_or_path )
30
30
self ._root_url = url_or_path
31
+ self ._parent_path = url_or_path
31
32
try :
32
33
self ._root_url_scheme = urllib .parse .urlparse (url_or_path ).scheme
33
34
if self ._root_url_scheme not in ["http" , "https" ]:
@@ -44,59 +45,89 @@ def resolve(self, recursive: bool = True) -> ResolvedSchema:
44
45
root_schema : SchemaData
45
46
external_schemas : Dict [str , SchemaData ] = {}
46
47
errors : List [str ] = []
48
+ parent : str
47
49
48
50
if self ._root_path :
49
51
root_schema = self ._fetch_remote_file_path (self ._root_path )
50
52
elif self ._root_url :
51
53
root_schema = self ._fetch_url_reference (self ._root_url )
52
54
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 )
54
56
return ResolvedSchema (root_schema , external_schemas , errors )
55
57
56
58
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 ,
58
65
) -> None :
59
66
60
67
for ref in self ._lookup_schema_references (root ):
61
68
if ref .is_local ():
62
69
continue
63
70
64
71
try :
65
- path = ref .value .split ("#" )[0 ]
72
+ path = self ._absolute_path (ref .path , parent )
73
+ parent = self ._parent (path )
74
+
66
75
if path in external_schemas :
67
76
continue
68
77
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 )
73
79
74
80
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 )
76
82
77
83
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 } " )
80
86
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 )
83
113
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 )
90
119
else :
91
- raise RuntimeError ("Bad object initilalization" )
120
+ res = self ._fetch_remote_file_path (Path (abs_path ))
121
+
122
+ return res
92
123
93
124
def _fetch_remote_file_path (self , path : Path ) -> SchemaData :
94
125
logging .info (f"Fetching remote ref file path > { path } " )
95
126
return DataLoader .load (str (path ), path .read_bytes ())
96
127
97
128
def _fetch_url_reference (self , url : str ) -> SchemaData :
98
129
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 )
100
131
101
132
logging .info (f"Fetching remote ref url > { url } " )
102
133
return DataLoader .load (url , httpx .get (url ).content )
0 commit comments