# -*- coding: utf-8 -*- from __future__ import annotations from typing import TYPE_CHECKING from functools import cached_property if TYPE_CHECKING: from typing import Self import urllib # Make sure URIs are interpreted indentically everywhere class Uri: def __assemble(self, scheme: bool, credentials: bool, secure: bool) -> str: ret = '' if scheme: ret += f'{self.protocol}://' if credentials and self.username: ret += self.username if self.password: ret += ':' + '' if secure else self.password ret += '@' if self.hostname: ret += self.hostname if self.port_str: ret += ':' + self.port_str return ret def __init__(self, string: str) -> None: self.__string = string self.__username: str|None = None self.__password: str|None = None def __repr__(self) -> str: return self.full def __str__(self) -> str: return self.id @cached_property def __p(self) -> urllib.parse.ParseResult: from urllib.parse import urlparse return urlparse(self.__string) @classmethod def pimp(cls, url: str|Self) -> Uri: if isinstance(url, Uri): return url return Uri(url) @property def to_string(self) -> str: return self.__string @cached_property def scheme(self) -> str: ret = self.__p.scheme if not ret: return 'file://' return ret @cached_property def protocol(self) -> str: return self.scheme.replace('://', '') @property def username(self) -> str|None: if self.__username is None: return self.__p.username return self.__username def set_username(self, username: str) -> None: self.__username = username @property def password(self) -> str|None: if self.__password is None: return self.__p.password return self.__password def set_password(self, password: str) -> None: self.__password = password @cached_property def hostname(self) -> str|None: return self.__p.hostname @cached_property def port(self) -> int|None: return self.__p.port @cached_property def port_str(self) -> str|None: if self.port is None: return None return str(self.port) @cached_property def authority(self) -> str: return self.__assemble(scheme=False, credentials=True, secure=False) @cached_property def origin(self) -> str: return self.__assemble(scheme=False, credentials=False, secure=True) @cached_property def scheme_plus_authority(self) -> str: return self.scheme + '://' + self.authority @cached_property def id(self) -> str: return self.__assemble(scheme=True, credentials=True, secure=True) @cached_property def full(self) -> str: return self.__assemble(scheme=True, credentials=True, secure=False) + self.path @cached_property def path(self) -> str: return self.__p.path