# HG changeset patch # User Goffi # Date 1684163994 -7200 # Node ID 199473ffe4ea92dd718f9522efb1f395f6e3efcf # Parent b56bf0c6c064fe852776c249e467294aef3babec frontends (tools/jid): remove old pyjamas code + type hints diff -r b56bf0c6c064 -r 199473ffe4ea sat_frontends/tools/jid.py --- a/sat_frontends/tools/jid.py Mon May 15 17:02:41 2023 +0200 +++ b/sat_frontends/tools/jid.py Mon May 15 17:19:54 2023 +0200 @@ -1,8 +1,7 @@ #!/usr/bin/env python3 - -# SAT: a jabber client -# Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org) +# Libervia XMPP +# Copyright (C) 2009-2023 Jérôme Poisson (goffi@goffi.org) # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by @@ -17,92 +16,20 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . - -# hack to use this module with pyjamas -try: - str("") # XXX: unicode doesn't exist in pyjamas - - # normal version - class BaseJID(str): - def __new__(cls, jid_str): - self = str.__new__(cls, cls._normalize(jid_str)) - return self - - def __init__(self, jid_str): - pass - - def _parse(self): - """Find node domain and resource""" - node_end = self.find("@") - if node_end < 0: - node_end = 0 - domain_end = self.find("/") - if domain_end == 0: - raise ValueError("a jid can't start with '/'") - if domain_end == -1: - domain_end = len(self) - self.node = self[:node_end] or None - self.domain = self[(node_end + 1) if node_end else 0 : domain_end] - self.resource = self[domain_end + 1 :] or None +from typing import Optional, Tuple -except ( - TypeError, - AttributeError, -): # Error raised is not the same depending on pyjsbuild options - - # pyjamas version - class BaseJID(object): - def __init__(self, jid_str): - self.__internal_str = JID._normalize(jid_str) - - def __str__(self): - return self.__internal_str - - def __getattr__(self, name): - return getattr(self.__internal_str, name) - - def __eq__(self, other): - if not isinstance(other, JID): - return False - return ( - self.node == other.node - and self.domain == other.domain - and self.resource == other.resource - ) +class JID(str): + """This class helps manage JID (@/)""" - def __hash__(self): - return hash("JID<{}>".format(self.__internal_str)) - - def find(self, *args): - return self.__internal_str.find(*args) + def __new__(cls, jid_str: str) -> "JID": + return str.__new__(cls, cls._normalize(jid_str)) - def _parse(self): - """Find node domain and resource""" - node_end = self.__internal_str.find("@") - if node_end < 0: - node_end = 0 - domain_end = self.__internal_str.find("/") - if domain_end == 0: - raise ValueError("a jid can't start with '/'") - if domain_end == -1: - domain_end = len(self.__internal_str) - self.node = self.__internal_str[:node_end] or None - self.domain = self.__internal_str[ - (node_end + 1) if node_end else 0 : domain_end - ] - self.resource = self.__internal_str[domain_end + 1 :] or None - - -class JID(BaseJID): - """This class help manage JID (Node@Domaine/Resource)""" - - def __init__(self, jid_str): - super(JID, self).__init__(jid_str) - self._parse() + def __init__(self, jid_str: str): + self._node, self._domain, self._resource = self._parse() @staticmethod - def _normalize(jid_str): + def _normalize(jid_str: str) -> str: """Naive normalization before instantiating and parsing the JID""" if not jid_str: return jid_str @@ -110,25 +37,68 @@ tokens[0] = tokens[0].lower() # force node and domain to lower-case return "/".join(tokens) + def _parse(self) -> Tuple[Optional[str], str, Optional[str]]: + """Find node, domain, and resource from JID""" + node_end = self.find("@") + if node_end < 0: + node_end = 0 + domain_end = self.find("/") + if domain_end == 0: + raise ValueError("a jid can't start with '/'") + if domain_end == -1: + domain_end = len(self) + node = self[:node_end] or None + domain = self[(node_end + 1) if node_end else 0 : domain_end] + resource = self[domain_end + 1 :] or None + return node, domain, resource + @property - def bare(self): + def node(self) -> Optional[str]: + return self._node + + @property + def local(self) -> Optional[str]: + return self._node + + @property + def domain(self) -> str: + return self._domain + + @property + def resource(self) -> Optional[str]: + return self._resource + + @property + def bare(self) -> "JID": if not self.node: return JID(self.domain) - return JID("{}@{}".format(self.node, self.domain)) + return JID(f"{self.node}@{self.domain}") + + def change_resource(self, resource: str) -> "JID": + """Build a new JID with the same node and domain but a different resource. - def is_valid(self): + @param resource: The new resource for the JID. + @return: A new JID instance with the updated resource. + """ + return JID(f"{self.bare}/{resource}") + + def is_valid(self) -> bool: """ @return: True if the JID is XMPP compliant """ - # TODO: implement real check, according to the RFC http://tools.ietf.org/html/rfc6122 - return self.domain != "" + # Simple check for domain part + if not self.domain or self.domain.startswith(".") or self.domain.endswith("."): + return False + if ".." in self.domain: + return False + return True -def new_resource(entity, resource): +def new_resource(entity: JID, resource: str) -> JID: """Build a new JID from the given entity and resource. - @param entity (JID): original JID - @param resource (unicode): new resource + @param entity: original JID + @param resource: new resource @return: a new JID instance """ - return JID("%s/%s" % (entity.bare, resource)) + return entity.change_resource(resource)