Coverage for src/bioimageio/spec/_internal/root_url.py: 74%
43 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-18 09:17 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-18 09:17 +0000
1from __future__ import annotations
3from pathlib import PurePosixPath
4from typing import Any, ClassVar, Iterable
5from urllib.parse import urlsplit, urlunsplit
7import pydantic
8from pydantic import RootModel
10from .validated_string import ValidatedString
13class RootHttpUrl(ValidatedString):
14 """An untested HTTP URL, possibly a 'URL folder' or an invalid HTTP URL"""
16 root_model: ClassVar[type[RootModel[Any]]] = RootModel[pydantic.HttpUrl]
17 _validated: pydantic.HttpUrl
19 def absolute(self):
20 """analog to `absolute` method of pathlib."""
21 return self
23 @property
24 def scheme(self) -> str:
25 return self._validated.scheme
27 @property
28 def host(self) -> str | None:
29 return self._validated.host
31 @property
32 def path(self) -> str | None:
33 return self._validated.path
35 @property
36 def parent(self) -> RootHttpUrl:
37 parsed = urlsplit(str(self))
38 path = list(parsed.path.split("/"))
39 if (
40 parsed.netloc == "zenodo.org"
41 and parsed.path.startswith("/api/records/")
42 and parsed.path.endswith("/content")
43 ):
44 path[-2:-1] = []
45 else:
46 path = path[:-1]
48 return RootHttpUrl(
49 urlunsplit(
50 (
51 parsed.scheme,
52 parsed.netloc,
53 "/".join(path),
54 parsed.query,
55 parsed.fragment,
56 )
57 )
58 )
60 @property
61 def parents(self) -> Iterable[RootHttpUrl]:
62 """iterate over all URL parents (max 100)"""
63 current = self
64 for _ in range(100):
65 current = current.parent
66 yield current
68 @property
69 def suffix(self) -> str:
70 if self.path is None:
71 return ""
72 else:
73 return PurePosixPath(self.path).suffix
75 def __truediv__(self, other: str) -> RootHttpUrl:
76 parsed = urlsplit(str(self))
77 return RootHttpUrl(
78 urlunsplit(
79 (
80 parsed.scheme,
81 parsed.netloc,
82 f"{parsed.path.strip('/')}/{other.strip('/')}",
83 parsed.query,
84 parsed.fragment,
85 )
86 )
87 )