Source code for domonic.webapi.url

"""
    domonic.webapi.url
    ====================================
    https://developer.mozilla.org/en-US/docs/Web/API/URL

    # TODO - move the unit tests for this class from javascript to webapi
    # TODO - untested

"""

import urllib


[docs]class URL: """a-tag extends from URL""" def __update__(self): # print( "update URL:", type(self), self ) try: # make obj with all old props new = {} new["protocol"] = self.url.scheme new["hostname"] = self.url.hostname new["href"] = self.url.geturl() new["port"] = self.url.port new["host"] = "" # self.url.hostname new["pathname"] = self.url.path new["hash"] = "" # self.url.hash new["search"] = "" # self.url.hash # update it with all the new ones new = {} new["protocol"] = self.protocol new["hostname"] = self.hostname new["href"] = self.href new["port"] = self.port new["host"] = self.host new["pathname"] = self.pathname new["hash"] = self.hash # self.hash new["search"] = self.search # self.url.query new["_searchParams"] = self._searchParams # URLSearchParams(self.url.query) # NOTE - rebuild happening here self.url = urllib.parse.urlsplit( new["protocol"] + "://" + new["host"] + new["pathname"] + new["hash"] + new["search"] ) self.href = self.url.geturl() except Exception: # as e: # print('fails on props called by init as they dont exist yet') # print(e) pass def __init__(self, url: str = "", *args, **kwargs): # TODO - relative to """URL builds a url Args: url (str): a url """ self.url = urllib.parse.urlsplit(url) self.href = url # self.url.geturl() self.protocol = self.url.scheme self.hostname = self.url.hostname self.port = self.url.port self.host = self.url.hostname self.pathname = self.url.path self.hash = "" self.search = self.url.query self._searchParams = URLSearchParams(self.url.query) @property def searchParams(self): return self._searchParams.toString() def toString(self): return str(self.href) # def toJson # @property # def href(self): # TODO - check js vs tag. does js version remove query?. if so detect self. # return self.href # @href.setter # def href(self, href:str): # self.url = href # self.href = href @property def protocol(self): return self.__protocol @protocol.setter def protocol(self, p: str): self.__protocol = p # if self.ready : self.__update__() # TODO - this instead of silent err? self.__update__() @property def hostname(self): return self.__hostname @hostname.setter def hostname(self, h: str): if h is None: return if ":" in h: h = h.split(":")[0] self.__hostname = h self.__update__() @property def port(self): return self.__port @port.setter def port(self, p: str): self.__port = p self.__update__() @property def host(self): if self.port is not None: return self.hostname + ":" + str(self.port) else: return self.hostname @host.setter def host(self, h: str): if h is None: return p = self.port if ":" in h: p = int(h.split(":")[1]) h = h.split(":")[0] self.__host = h self.hostname = h self.port = p self.__update__() @property def pathname(self): return self.__pathname @pathname.setter def pathname(self, p: str): self.__pathname = p self.__update__() @property def hash(self): """ " hash Sets or returns the anchor part (#) of a URL""" if "#" in self.href: return "#" + self.href.split("#")[1] # return '' return self.__hash @hash.setter def hash(self, h: str): self.__hash = h self.__update__() # @property # def origin(self): """# origin Returns the protocol, hostname and port number of a URL Location""" def __str__(self): return str(self.href)
# NOTE - node -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- # @staticmethod # def domainToASCII(domain: str): # """[It returns the Punycode ASCII serialization of the domain. # If domain is an invalid domain, the empty string is returned.] # Args: # domain (str): [description] # """ # pass # @staticmethod # def domainToUnicode(domain: str): # """[returns the Unicode serialization of the domain. # If the domain is invalid, the empty string is returned] # Args: # domain (str): [description] # """ # pass # @staticmethod # def fileURLToPath(url: str): # """[ensures the correct decodings of percent-encoded characters as well as # ensuring a cross-platform valid absolute path string.] # Args: # url (str): [The fully-resolved platform-specific file path.] # """ # if url is None: # return # return urllib.parse.unquote(url) # @staticmethod # def format(URL, options): # """[summary] # Args: # URL ([type]): [description] # options ([type]): [description] # """ # pass # @staticmethod # def pathToFileURL(path: str): # """[summary] # Args: # path (str): [description] # """ # pass # @staticmethod # def urlToHttpOptions(url: str): # """[summary] # Args: # url (str): [description] # """ # pass
[docs]class URLSearchParams: """[utility methods to work with the query string of a URL]""" def __init__(self, paramString): # , **paramsObj): """[Returns a URLSearchParams object instance.] Args: paramString ([type]): [ i.e. q=URLUtils.searchParams&topic=api] """ # TODO - escape # import ast # TODO - dont think i can do this cant urls params have duplicate keys? # self.params = ast.literal_eval(paramString) if isinstance(paramString, str): if paramString.startswith("?"): paramString = paramString[1 : len(paramString)] import urllib self.params = urllib.parse.parse_qs(paramString) elif hasattr(paramString, "__iter__"): self.params = [item for sublist in paramString for item in sublist] elif isinstance(paramString, dict): # self.params = dict([(key, item) for key, item in paramString.iteritems()]) self.params = {key: item for key, item in paramString.iteritems()} else: raise TypeError( f"Malformed paramString. Must be a string or a dict with dict like items. Got: {paramString}" ) def __iter__(self): for attr in self.params.items(): # dir(self.params.items()): # if not attr.startswith("__"): yield attr
[docs] def append(self, key, value): """Appends a specified key/value pair as a new search parameter""" # TODO - ordereddict? self.params[key].append(value) # [key]=value
[docs] def delete(self, key): """Deletes the given search parameter, and its associated value, from the list of all search parameters.""" del self.params[key]
[docs] def has(self, key): """Returns a Boolean indicating if such a given parameter exists.""" return key in self.params
[docs] def entries(self): """Returns an iterator allowing iteration through all key/value pairs contained in this object.""" return self.params.items()
[docs] def forEach(self, func): """Allows iteration through all values contained in this object via a callback function.""" for key, value in self.params.items(): func(key, value)
[docs] def keys(self): """Returns an iterator allowing iteration through all keys of the key/value pairs contained in this object.""" return self.params.keys()
[docs] def get(self, key): """Returns the first value associated with the given search parameter.""" try: return self.params.get(key, None)[0] except Exception: return None
[docs] def sort(self): """Sorts all key/value pairs, if any, by their keys.""" self.params.sort()
[docs] def values(self): """Returns an iterator allowing iteration through all values of the key/value pairs contained in this object.""" return self.params.values()
[docs] def toString(self): """Returns a string containing a query string suitable for use in a URL.""" # return '&'.join([str(x) for x in self.params]) return urllib.parse.urlencode(self.params, doseq=True)
# return str(self.params)
[docs] def set(self, key, value): """Sets the value associated with a given search parameter to the given value. If there are several values, the others are deleted.""" self.params[key] = value
[docs] def getAll(self, key): """Returns all the values associated with a given search parameter.""" return self.params.get(key)
def __str__(self): return urllib.parse.urlencode(self.params, doseq=True)