You've already forked hotpocket
This commit is contained in:
164
services/packages/common/hotpocket_common/url.py
Normal file
164
services/packages/common/hotpocket_common/url.py
Normal file
@@ -0,0 +1,164 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
import typing
|
||||
import urllib.parse
|
||||
|
||||
|
||||
class URL:
|
||||
"""
|
||||
The URL class.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
url = URL('https://ziomek.dog/').\
|
||||
set_path('/index_old.html').\
|
||||
set_query({
|
||||
'test': 'true',
|
||||
}).\
|
||||
to_string()
|
||||
|
||||
The *encoding* argument will be used to decode *initial* if it's
|
||||
```bytes``. Also, it'll be used when decoding QS.
|
||||
"""
|
||||
def __init__(self,
|
||||
initial: str | bytes | pathlib.Path | urllib.parse.ParseResult,
|
||||
encoding: str = 'utf-8'):
|
||||
self.encoding = encoding
|
||||
self.parsed_url: urllib.parse.ParseResult
|
||||
|
||||
if isinstance(initial, urllib.parse.ParseResult):
|
||||
self.parsed_url = initial
|
||||
elif isinstance(initial, pathlib.Path):
|
||||
self.parsed_url = urllib.parse.urlparse(str(initial))
|
||||
elif isinstance(initial, bytes):
|
||||
self.parsed_url = urllib.parse.urlparse(
|
||||
initial.decode(self.encoding),
|
||||
)
|
||||
else:
|
||||
self.parsed_url = urllib.parse.urlparse(initial)
|
||||
|
||||
def replace_parsed_url_field(self, field: str, value: typing.Any):
|
||||
self.parsed_url = self.parsed_url._replace(**{field: value})
|
||||
|
||||
return self
|
||||
|
||||
def append_path_component(self, component: str | pathlib.Path) -> URL:
|
||||
_ = self.set_path(self.path / component)
|
||||
|
||||
return self
|
||||
|
||||
@property
|
||||
def scheme(self) -> str:
|
||||
return self.parsed_url.scheme
|
||||
|
||||
def set_scheme(self, new_scheme: str) -> URL:
|
||||
self.replace_parsed_url_field('scheme', new_scheme)
|
||||
|
||||
return self
|
||||
|
||||
@property
|
||||
def netloc(self) -> str:
|
||||
return self.parsed_url.netloc
|
||||
|
||||
def set_netloc(self, new_netloc: str) -> URL:
|
||||
self.replace_parsed_url_field('netloc', new_netloc)
|
||||
|
||||
return self
|
||||
|
||||
@property
|
||||
def hostname(self) -> str | None:
|
||||
return self.parsed_url.hostname
|
||||
|
||||
@property
|
||||
def port(self) -> int | None:
|
||||
return self.parsed_url.port
|
||||
|
||||
@property
|
||||
def username(self) -> str | None:
|
||||
return self.parsed_url.username
|
||||
|
||||
@property
|
||||
def password(self) -> str | None:
|
||||
return self.parsed_url.password
|
||||
|
||||
@property
|
||||
def path(self) -> pathlib.PurePosixPath:
|
||||
return pathlib.PurePosixPath(self.parsed_url.path)
|
||||
|
||||
def set_path(self, new_path: str | pathlib.Path | pathlib.PurePath) -> URL:
|
||||
self.replace_parsed_url_field(
|
||||
'path', str(pathlib.PurePosixPath(new_path)),
|
||||
)
|
||||
|
||||
return self
|
||||
|
||||
@property
|
||||
def params(self) -> str:
|
||||
return self.parsed_url.params
|
||||
|
||||
def set_params(self, new_params: str) -> URL:
|
||||
self.replace_parsed_url_field('params', new_params)
|
||||
|
||||
return self
|
||||
|
||||
@property
|
||||
def query(self) -> dict[typing.AnyStr, list[typing.AnyStr]]:
|
||||
if self.parsed_url.query == '':
|
||||
return {}
|
||||
|
||||
return urllib.parse.parse_qs(
|
||||
self.parsed_url.query, encoding=self.encoding, # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
def set_query(self,
|
||||
new_query: dict[typing.AnyStr, list[typing.AnyStr]] | list,
|
||||
) -> URL:
|
||||
self.replace_parsed_url_field(
|
||||
'query', urllib.parse.urlencode(new_query, doseq=True),
|
||||
)
|
||||
|
||||
return self
|
||||
|
||||
@property
|
||||
def query_string(self) -> str:
|
||||
return self.parsed_url.query
|
||||
|
||||
def set_query_string(self, new_query_string: str) -> URL:
|
||||
self.replace_parsed_url_field('query', new_query_string)
|
||||
|
||||
return self
|
||||
|
||||
@property
|
||||
def fragment(self) -> str:
|
||||
return self.parsed_url.fragment
|
||||
|
||||
def set_fragment(self, new_fragment: str) -> URL:
|
||||
self.replace_parsed_url_field('fragment', new_fragment)
|
||||
|
||||
return self
|
||||
|
||||
def to_string(self) -> str:
|
||||
return urllib.parse.urlunparse(self.parsed_url)
|
||||
|
||||
def __truediv__(self, component: str | pathlib.Path) -> URL:
|
||||
return self.append_path_component(component)
|
||||
|
||||
def __mod__(self,
|
||||
query: dict[typing.AnyStr, list[typing.AnyStr]],
|
||||
) -> URL:
|
||||
return self.set_query(
|
||||
{**self.query, **query},
|
||||
)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.to_string()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'<URL {self}>'
|
||||
|
||||
def __bytes__(self) -> bytes:
|
||||
return self.__str__().encode(self.encoding)
|
||||
Reference in New Issue
Block a user