From 19a4ffa814ab6acd8dac2a780e52313b5ad2a56c Mon Sep 17 00:00:00 2001 From: Richard Penman <{ID}+{username}@users.noreply.github.com> Date: Wed, 15 Jan 2025 23:23:16 +0800 Subject: [PATCH] use Union type for type hints to support python 3.9 --- whois/__init__.py | 15 +++++++++++++-- whois/parser.py | 33 +++++++++++++++++++++------------ whois/whois.py | 18 +++++++++++++----- 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/whois/__init__.py b/whois/__init__.py index 85311d9..e45ef47 100644 --- a/whois/__init__.py +++ b/whois/__init__.py @@ -24,7 +24,16 @@ ) -def whois(url: str, command: bool = False, flags: int = 0, executable: str = "whois", executable_opts: Optional[list[str]] = None, inc_raw: bool = False, quiet: bool = False, convert_punycode: bool = True) -> dict[str, Any]: +def whois( + url: str, + command: bool = False, + flags: int = 0, + executable: str = "whois", + executable_opts: Optional[list[str]] = None, + inc_raw: bool = False, + quiet: bool = False, + convert_punycode: bool = True, +) -> dict[str, Any]: """ url: the URL to search whois command: whether to use the native whois command (default False) @@ -63,7 +72,9 @@ def whois(url: str, command: bool = False, flags: int = 0, executable: str = "wh # try builtin client nic_client = NICClient() if convert_punycode: - text = nic_client.whois_lookup(None, domain.encode("idna").decode("utf-8"), flags, quiet=quiet) + text = nic_client.whois_lookup( + None, domain.encode("idna").decode("utf-8"), flags, quiet=quiet + ) else: text = nic_client.whois_lookup(None, domain, flags, quiet=quiet) entry = WhoisEntry.load(domain, text) diff --git a/whois/parser.py b/whois/parser.py index b4623aa..ee9b931 100644 --- a/whois/parser.py +++ b/whois/parser.py @@ -10,7 +10,7 @@ import re from datetime import datetime import dateutil.parser as dp -from typing import Any, Optional, Self +from typing import Any, Optional, Union from dateutil.utils import default_tzinfo from .time_zones import tz_data @@ -58,7 +58,7 @@ "%d/%m/%Y %H:%M:%S.%f %Z", # 23/04/2015 12:00:07.619546 EEST "%B %d %Y", # August 14 2017 "%d.%m.%Y %H:%M:%S", # 08.03.2014 10:28:24 - "before %Y", # before 2001 + "before %Y", # before 2001 "before %b-%Y", # before aug-1996 "before %Y-%m-%d", # before 1996-01-01 "before %Y%m%d", # before 19960821 @@ -71,7 +71,7 @@ class WhoisError(Exception): pass -def datetime_parse(s: str) -> str | datetime: +def datetime_parse(s: str) -> Union[str, datetime]: for known_format in KNOWN_FORMATS: try: return datetime.strptime(s, known_format) @@ -80,13 +80,16 @@ def datetime_parse(s: str) -> str | datetime: return s -def cast_date(s: str, dayfirst: bool = False, yearfirst: bool = False) -> str | datetime: +def cast_date( + s: str, dayfirst: bool = False, yearfirst: bool = False +) -> Union[str, datetime]: """Convert any date string found in WHOIS to a datetime object.""" try: # Use datetime.timezone.utc to support < Python3.9 - return default_tzinfo(dp.parse( - s, tzinfos=tz_data, dayfirst=dayfirst, yearfirst=yearfirst - ), datetime.timezone.utc) + return default_tzinfo( + dp.parse(s, tzinfos=tz_data, dayfirst=dayfirst, yearfirst=yearfirst), + datetime.timezone.utc, + ) except Exception: return datetime_parse(s) @@ -140,12 +143,14 @@ def parse(self) -> None: """ for attr, regex in list(self._regex.items()): if regex: - values: list[str | datetime] = [] + values: list[Union[str, datetime]] = [] for data in re.findall(regex, self.text, re.IGNORECASE | re.M): matches = data if isinstance(data, tuple) else [data] for value in matches: value = self._preprocess(attr, value) - if value and str(value).lower() not in [str(v).lower() for v in values]: + if value and str(value).lower() not in [ + str(v).lower() for v in values + ]: # avoid duplicates values.append(value) @@ -158,8 +163,7 @@ def parse(self) -> None: else: self[attr] = None - - def _preprocess(self, attr: str, value: str) -> str | datetime: + def _preprocess(self, attr: str, value: str) -> Union[str, datetime]: value = value.strip() if value and isinstance(value, str) and not value.isdigit() and "_date" in attr: # try casting to date format @@ -740,7 +744,7 @@ class WhoisPl(WhoisEntry): regex: dict[str, str] = { "domain_name": r"DOMAIN NAME: *(.+)\n", - "name_servers": r"nameservers:(?:\s+(\S+)\.[^\n]*\n)(?:\s+(\S+)\.[^\n]*\n)?(?:\s+(\S+)\.[^\n]*\n)?(?:\s+(\S+)\.[^\n]*\n)?", # up to 4 + "name_servers": r"nameservers:(?:\s+(\S+)\.[^\n]*\n)(?:\s+(\S+)\.[^\n]*\n)?(?:\s+(\S+)\.[^\n]*\n)?(?:\s+(\S+)\.[^\n]*\n)?", # up to 4 "registrar": r"REGISTRAR:\s*(.+)", "registrar_url": r"URL: *(.+)", # not available "status": r"Registration status:\n\s*(.+)", # not available @@ -960,6 +964,7 @@ class WhoisJp(WhoisEntry): nintendo.co.jp """ + not_found = "No match!!" regex: dict[str, str] = { "domain_name": r"^(?:a\. )?\[Domain Name\]\s*(.+)", @@ -1399,6 +1404,7 @@ def __init__(self, domain: str, text: str): else: WhoisEntry.__init__(self, domain, text, self.regex) + class WhoisStyle(WhoisRu): """Whois parser for .style domains""" @@ -2122,6 +2128,7 @@ class WhoisAi(WhoisEntry): "billing_email": r"Billing\s*Email\.*:\s*(.+)", "name_servers": r"Name Server\.*:\s*(.+)", } + def __init__(self, domain: str, text: str): if "not registered" in text: raise WhoisError(text) @@ -3410,6 +3417,7 @@ def __init__(self, domain: str, text: str): else: WhoisEntry.__init__(self, domain, text, self.regex) + class WhoisLv(WhoisEntry): """Whois parser for .lv domains""" @@ -3431,6 +3439,7 @@ def __init__(self, domain: str, text: str): else: WhoisEntry.__init__(self, domain, text, self.regex) + class WhoisCo(WhoisEntry): """Whois parser for .co domains""" diff --git a/whois/whois.py b/whois/whois.py index 5aabd87..fbaed1e 100644 --- a/whois/whois.py +++ b/whois/whois.py @@ -177,7 +177,6 @@ def get_socket(): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) return s - def findwhois_iana(self, tld: str) -> Optional[str]: s = self.get_socket() s.settimeout(10) @@ -192,9 +191,16 @@ def findwhois_iana(self, tld: str) -> Optional[str]: s.close() match = re.search(r"whois:\s+(.*?)\n", response.decode("utf-8")) return match.group(1) if match else None - - def whois(self, query: str, hostname: str, flags: int, many_results: bool = False, quiet: bool = False, timeout: int = 10) -> str: + def whois( + self, + query: str, + hostname: str, + flags: int, + many_results: bool = False, + quiet: bool = False, + timeout: int = 10, + ) -> str: """Perform initial lookup with TLD whois server then, if the quick flag is false, search that result for the region-specific whois server and do a lookup @@ -214,7 +220,7 @@ def whois(self, query: str, hostname: str, flags: int, many_results: bool = Fals elif hostname == NICClient.DK_HOST: query_bytes = " --show-handles " + query elif hostname.endswith(".jp"): - query_bytes = query + '/e' + query_bytes = query + "/e" elif hostname.endswith(NICClient.QNICHOST_TAIL) and many_results: query_bytes = "=" + query else: @@ -398,7 +404,9 @@ def choose_server(self, domain: str) -> Optional[str]: # server = NICClient.QNICHOST_HEAD + tld # return server - def whois_lookup(self, options: Optional[dict], query_arg: str, flags: int, quiet: bool = False) -> str: + def whois_lookup( + self, options: Optional[dict], query_arg: str, flags: int, quiet: bool = False + ) -> str: """Main entry point: Perform initial lookup on TLD whois server, or other server to get region-specific whois server, then if quick flag is false, perform a second lookup on the region-specific