Skip to content

Commit

Permalink
use Union type for type hints to support python 3.9
Browse files Browse the repository at this point in the history
  • Loading branch information
Richard Penman authored and Richard Penman committed Jan 15, 2025
1 parent d975446 commit 19a4ffa
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 19 deletions.
15 changes: 13 additions & 2 deletions whois/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
33 changes: 21 additions & 12 deletions whois/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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)

Expand Down Expand Up @@ -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)

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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*(.+)",
Expand Down Expand Up @@ -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"""

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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"""

Expand All @@ -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"""

Expand Down
18 changes: 13 additions & 5 deletions whois/whois.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 19a4ffa

Please sign in to comment.