lib.base.Uri: Add module

Add a URI abstraction module. The class is designed to replace less unified attempts at URI parsing throughout the jw-pkg code base.

Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
Jan Lindemann 2026-04-27 12:40:58 +02:00
commit f0eeb14a97
Signed by: Jan Lindemann
GPG key ID: 3750640C9E25DD61

View file

@ -0,0 +1,122 @@
# -*- 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 += ':' + '<hidden>' 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