From 701dcdbf942a3bb0c61f9a23d0c2a222420ba4c2 Mon Sep 17 00:00:00 2001 From: Izalia Mae Date: Sun, 7 Nov 2021 19:38:13 -0500 Subject: [PATCH] minor changes --- izzylib/dotdict.py | 24 ++++++++++++ izzylib/http_server_async/request.py | 6 +-- izzylib/misc.py | 58 ++++++++++++++++++---------- 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/izzylib/dotdict.py b/izzylib/dotdict.py index 47ed53e..208bcba 100644 --- a/izzylib/dotdict.py +++ b/izzylib/dotdict.py @@ -1,5 +1,7 @@ import json +from urllib.parse import unquote_plus, quote + from .path import Path @@ -66,6 +68,13 @@ class DotDict(dict): return data + @classmethod + def new_from_query_string(cls, query): + data = cls() + data.from_query(query) + return data + + def copy(self): return DotDict(self) @@ -75,6 +84,21 @@ class DotDict(dict): self.__setitem__(k, v) + def from_query(self, query): + if not query: + return + + for qline in unquote_plus(query).split('&'): + try: key, value = qline.split('=') + except: key, value = qline, None + + self[key] = value + + + def to_query(self): + return quote('&'.join(f'{k}={v}' for k,v in self.items())) + + def to_json(self, indent=None, **kwargs): if 'cls' not in kwargs: kwargs['cls'] = JsonEncoder diff --git a/izzylib/http_server_async/request.py b/izzylib/http_server_async/request.py index e04784e..06f95c0 100644 --- a/izzylib/http_server_async/request.py +++ b/izzylib/http_server_async/request.py @@ -161,11 +161,7 @@ class Request: except: self.path = path if self.raw_query: - for qline in unquote_plus(self.raw_query).split('&'): - try: key, value = qline.split('=') - except: key, value = qline, None - - self.query[key] = value + self.query.from_query(self.raw_query) else: try: key, value = line.split(': ', 1) diff --git a/izzylib/misc.py b/izzylib/misc.py index 27f6427..1204fe9 100644 --- a/izzylib/misc.py +++ b/izzylib/misc.py @@ -42,12 +42,12 @@ datetime_formats = { } -def boolean(v, return_value=False): +def boolean(value, return_value=False): ''' Convert a str, bool, int or None object into a boolean. Arguments: - v (str, bool, int, None): The value to be checked + value (str, bool, int, None): The value to be checked return_value (bool): If True, return v instead of True if it can't be converted Return: @@ -55,19 +55,19 @@ def boolean(v, return_value=False): ''' - if type(v) not in [str, bool, int, type(None)]: + if type(value) not in [str, bool, int, type(None)]: raise ValueError(f'Value is not a string, boolean, int, or nonetype: {value}') - value = v.lower() if isinstance(v, str) else v + v = value.lower() if isinstance(value, str) else value - if value in [1, True, 'on', 'y', 'yes', 'true', 'enable']: + if v in [1, True, 'on', 'y', 'yes', 'true', 'enable']: return True - if value in [0, False, None, 'off', 'n', 'no', 'false', 'disable', '']: + if v in [0, False, None, 'off', 'n', 'no', 'false', 'disable', '']: return False if return_value: - return v + return value return True @@ -137,16 +137,16 @@ def get_ip(): return ip -def hasher(string, alg='blake2s'): +def hasher(data, alg='blake2s'): ''' - Hash a string and return the digest in hex format as a string + Hash a string or bytes object and return the digest in hex format as a string Arguments: - string (str, bytes): A string or bytes object to be hashed + data (str, bytes): A string or bytes object to be hashed alg (str): The name of algorithm to use for hashing. Check hashlib.__always_supported for valid hash algs Return: - str: The hashed string in hex format as a string + str: The hashed data in hex format as a string ''' if alg not in hashlib.algorithms_available: @@ -155,10 +155,10 @@ def hasher(string, alg='blake2s'): if alg in ['sha1', 'md4', 'md5', 'md5-sha1']: logging.verbose('Warning: Using an insecure hashing algorithm. sha256 or sha512 is recommended') - string = string.encode('UTF-8') if type(string) != bytes else string + data = data.encode('UTF-8') if type(string) != bytes else data newhash = hashlib.new(alg) - newhash.update(string) + newhash.update(data) return newhash.hexdigest() @@ -343,7 +343,7 @@ def remove(string: str, junk: list): return string -def signal_handler(func=None, *args, original_args=False, **kwargs): +def signal_handler(func, *args, original_args=False, **kwargs): if func: if original_args: handler = lambda signum, frame: func(signum, frame, *args, **kwargs) @@ -473,12 +473,14 @@ class DateString(str): tz_utc = timezone.utc tz_local = datetime.now(tz_utc).astimezone().tzinfo dt = None + format = None def __init__(self, string, format): assert format in datetime_formats self.dt = datetime.strptime(string, datetime_formats[format]).replace(tzinfo=self.tz_utc) + self.format = format def __new__(cls, string, format): @@ -518,15 +520,16 @@ class DateString(str): @property def utc(self): - return self.dt.astimezone(self.tz_utc) + return DateString.from_datetime(self.dt.astimezone(self.tz_utc), self.format) @property def local(self): - return self.dt.astimezone(self.tz_local) + return DateString.from_datetime(self.dt.astimezone(self.tz_local), self.format) - def dump_to_string(self, format): + def dump_to_string(self, format=None): + if not format: format = self.format assert format in datetime_formats return self.dt.strftime(datetime_formats[format]) @@ -542,11 +545,26 @@ class Url(str): def __init__(self, url): parsed = urlparse(url) - self.__parsed = parsed self.proto = parsed.scheme self.host = parsed.netloc + self.port = self.protocols.get(self.proto) if not parsed.port else None self.path = parsed.path - self.query = parsed.query + self.query_string = parsed.query + self.query = DotDict.new_from_query_string(parsed.query) self.username = parsed.username self.password = parsed.password - self.port = self.protocols.get(self.proto) if not parsed.port else None + self.anchor = parsed.fragment + + + @property + def dict(self): + return DotDict( + proto = self.proto, + host = self.host, + port = self.port, + path = self.path, + query_string = self.query_string, + query = self.query, + username = self.username, + password = self.password + )