summaryrefslogtreecommitdiff
path: root/python-asyncwhois.spec
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2023-05-05 10:52:13 +0000
committerCoprDistGit <infra@openeuler.org>2023-05-05 10:52:13 +0000
commit38bffad2ac59c51725ad7d6de3168e4fee59d99a (patch)
tree5b1ea38ebeb5f5055dc8e499ab9649967c9a9c2a /python-asyncwhois.spec
parent149ad27725d77ca6a8fa76f6a2a56c6cc02afac7 (diff)
automatic import of python-asyncwhoisopeneuler20.03
Diffstat (limited to 'python-asyncwhois.spec')
-rw-r--r--python-asyncwhois.spec624
1 files changed, 624 insertions, 0 deletions
diff --git a/python-asyncwhois.spec b/python-asyncwhois.spec
new file mode 100644
index 0000000..e6e98a4
--- /dev/null
+++ b/python-asyncwhois.spec
@@ -0,0 +1,624 @@
+%global _empty_manifest_terminate_build 0
+Name: python-asyncwhois
+Version: 1.0.5
+Release: 1
+Summary: asyncio-friendly Python module for WHOIS and RDAP queries.
+License: MIT
+URL: https://github.com/pogzyb/asyncwhois
+Source0: https://mirrors.nju.edu.cn/pypi/web/packages/6c/24/0bb4145222ffa6a20bb19cbd14347f05686af3d7e18bea755ce9c1d6a1c1/asyncwhois-1.0.5.tar.gz
+BuildArch: noarch
+
+Requires: python3-socks[asyncio]
+Requires: python3-tldextract
+Requires: python3-whodap
+
+%description
+### asyncwhois
+
+[![PyPI version](https://badge.fury.io/py/asyncwhois.svg)](https://badge.fury.io/py/asyncwhois)
+![build-workflow](https://github.com/pogzyb/asyncwhois/actions/workflows/build-and-test.yml/badge.svg)
+[![codecov](https://codecov.io/gh/pogzyb/asyncwhois/branch/main/graph/badge.svg?token=Q4xtgezXGX)](https://codecov.io/gh/pogzyb/asyncwhois)
+[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
+
+`asyncwhois` | Async-friendly Python library for WHOIS and RDAP queries.
+
+#### Quickstart
+
+```python
+import asyncio
+from pprint import pprint
+
+import asyncwhois
+
+# pick a domain
+domain = 'bitcoin.org'
+# domain could also be a URL; asyncwhois uses tldextract to parse the URL
+domain = 'https://www.google.com?q=asyncwhois'
+
+# standard call
+result = asyncwhois.whois_domain(domain)
+# result.query_output # The semi-free text output from the whois server
+# result.parser_output # A dictionary of key:values extracted from query_output
+# result.tld_extract_result # tldextract result (`tldextract.tldextract.ExtractResult`)
+
+# asyncio call
+loop = asyncio.get_event_loop()
+result = loop.run_until_complete(asyncwhois.aio_whois_domain(domain))
+
+pprint(result.parser_output)
+"""
+{created: datetime.datetime(2008, 8, 18, 13, 19, 55),
+ dnssec: 'unsigned',
+ domain_name: 'bitcoin.org',
+ expires: datetime.datetime(2029, 8, 18, 13, 19, 55),
+ name_servers: ['dns1.registrar-servers.com', 'dns2.registrar-servers.com'],
+ registrant_address: 'P.O. Box 0823-03411',
+ registrant_city: 'Panama',
+ registrant_country: 'PA',
+ registrant_name: 'WhoisGuard Protected',
+ registrant_organization: 'WhoisGuard, Inc.',
+ registrant_state: 'Panama',
+ registrant_zipcode: '',
+ registrar: 'NAMECHEAP INC',
+ status: ['clientTransferProhibited '
+ 'https://icann.org/epp#clientTransferProhibited'],
+ updated: datetime.datetime(2019, 11, 24, 13, 58, 35, 940000)}
+ ...
+ """
+```
+
+#### RDAP
+
+The `whodap` (https://github.com/pogzyb/whodap) project is used behind the scenes to perform RDAP queries.
+
+```python
+# RDAP domain query
+result = asyncwhois.rdap_domain('https://google.com')
+
+# Async RDAP domain query
+result = loop.run_until_complete(asyncwhois.aio_rdap_domain('https://google.com'))
+pprint(result.query_output) # Raw RDAP query output as a dictionary
+pprint(result.parser_output) # RDAP query output parsed/flattened into a WHOIS-like dictionary
+print(result.tld_extract_result) # tldextract result (`tldextract.tldextract.ExtractResult`)
+
+```
+
+#### Using Proxies
+
+SOCKS4 and SOCKS5 proxies are supported for WHOIS and RDAP queries.
+
+```python
+tor_host = 'localhost'
+tor_port = 9050
+
+# WHOIS Queries with Proxy
+result = asyncwhois.whois_domain(
+ 'bitcoin.org', proxy_url=f"socks5://{tor_host}:{tor_port}")
+# or with auth...
+tor_user = 'torpedo'
+tor_pw = 'torpw'
+result = asyncwhois.whois_ipv4(
+ '8.8.8.8', proxy_url=f"socks5://{tor_user}:{tor_pw}@{tor_host}:{tor_port}")
+
+# RDAP Queries with Proxy
+import httpx
+
+# EXTERNAL DEPENDENCY for SOCKS Proxies.
+from httpx_socks import SyncProxyTransport, AsyncProxyTransport
+
+transport = SyncProxyTransport.from_url(f"socks5://{tor_host}:{tor_port}")
+client = httpx.Client(transport=transport)
+result = asyncwhois.rdap_ipv6('2001:4860:4860::8888', httpx_client=client)
+
+transport = AsyncProxyTransport.from_url(f"socks5://{tor_user}:{tor_pw}@{tor_host}:{tor_port}")
+async with httpx.AsyncClient(transport=transport) as client:
+ result = await asyncwhois.aio_rdap_domain('bitcoin.org', httpx_client=client)
+
+```
+
+#### Exported Functions
+
+| Function | Description |
+| ----------- | ----------- |
+| `whois_domain` | WHOIS lookup for domain names |
+| `whois_ipv4` | WHOIS lookup for ipv4 addresses |
+| `whois_ipv6` | WHOIS lookup for ipv6 addresses |
+| `rdap_domain` | RDAP lookup for domain names |
+| `rdap_ipv4` | RDAP lookup for ipv4 addresses |
+| `rdap_ipv6` | RDAP lookup for ipv6 addresses |
+| `rdap_asn` | RDAP lookup for Autonomous System Numbers |
+| `aio_whois_domain` | async counterpart to `whois_domain` |
+| `aio_whois_ipv4` | async counterpart to `whois_ipv4` |
+| `aio_whois_ipv6` | async counterpart to `whois_ipv6` |
+| `aio_rdap_domain` | async counterpart to `rdap_domain` |
+| `aio_rdap_ipv4` | async counterpart to `rdap_ipv4` |
+| `aio_rdap_ipv6` | async counterpart to `rdap_ipv6` |
+| `aio_rdap_asn` | async counterpart to `rdap_asn` |
+
+#### Contributions
+
+Parsed output not what you expected? Unfortunately, "the format of responses [from a WHOIS server] follow a semi-free text format". Therefore,
+situations will arise where this module does not support parsing the output from a specific server, and you may find
+yourself needing more control over how parsing happens. Fortunately, you can create customized parsers to suit your needs.
+
+Example: This is a snippet of the output from running the "whois google.be" command.
+```python
+Domain: google.be
+Status: NOT AVAILABLE
+Registered: Tue Dec 12 2000
+
+Registrant:
+ Not shown, please visit www.dnsbelgium.be for webbased whois.
+
+Registrar Technical Contacts:
+ Organisation: MarkMonitor Inc.
+ Language: en
+ Phone: +1.2083895740
+ Fax: +1.2083895771
+
+Registrar:
+ Name: MarkMonitor Inc.
+ Website: http://www.markmonitor.com
+
+Nameservers:
+ ns2.google.com
+ ns1.google.com
+ ns4.google.com
+ ns3.google.com
+
+Keys:
+
+Flags:
+ clientTransferProhibited
+...
+```
+In this case, the "name servers" are listed on separate lines. The default BaseParser regexes
+won't find all of these server names. In order to accommodate this extra step, the "parse" method was
+overwritten within the parser subclass as seen below:
+```python
+class RegexBE(BaseParser):
+ _be_expressions = { # the base class (BaseParser) will handle these regexes
+ BaseKeys.CREATED: r'Registered: *(.+)',
+ BaseKeys.REGISTRAR: r'Registrar:\n.+Name: *(.+)',
+ BaseKeys.REGISTRANT_NAME: r'Registrant:\n *(.+)'
+ }
+
+ def __init__(self):
+ super().__init__()
+ self.update_reg_expressions(self._be_expressions)
+
+ def parse(self, blob: str) -> Dict[str, Any]:
+ # run base class parsing for other keys
+ parsed_output = super().parse(blob)
+ # custom parsing is needed to extract all the name servers
+ ns_match = re.search(r"Name servers: *(.+)Keys: ", blob, re.DOTALL)
+ if ns_match:
+ parsed_output[BaseKeys.NAME_SERVERS] = [m.strip() for m in ns_match.group(1).split('\n') if m.strip()]
+ return parsed_output
+```
+
+
+%package -n python3-asyncwhois
+Summary: asyncio-friendly Python module for WHOIS and RDAP queries.
+Provides: python-asyncwhois
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: python3-pip
+%description -n python3-asyncwhois
+### asyncwhois
+
+[![PyPI version](https://badge.fury.io/py/asyncwhois.svg)](https://badge.fury.io/py/asyncwhois)
+![build-workflow](https://github.com/pogzyb/asyncwhois/actions/workflows/build-and-test.yml/badge.svg)
+[![codecov](https://codecov.io/gh/pogzyb/asyncwhois/branch/main/graph/badge.svg?token=Q4xtgezXGX)](https://codecov.io/gh/pogzyb/asyncwhois)
+[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
+
+`asyncwhois` | Async-friendly Python library for WHOIS and RDAP queries.
+
+#### Quickstart
+
+```python
+import asyncio
+from pprint import pprint
+
+import asyncwhois
+
+# pick a domain
+domain = 'bitcoin.org'
+# domain could also be a URL; asyncwhois uses tldextract to parse the URL
+domain = 'https://www.google.com?q=asyncwhois'
+
+# standard call
+result = asyncwhois.whois_domain(domain)
+# result.query_output # The semi-free text output from the whois server
+# result.parser_output # A dictionary of key:values extracted from query_output
+# result.tld_extract_result # tldextract result (`tldextract.tldextract.ExtractResult`)
+
+# asyncio call
+loop = asyncio.get_event_loop()
+result = loop.run_until_complete(asyncwhois.aio_whois_domain(domain))
+
+pprint(result.parser_output)
+"""
+{created: datetime.datetime(2008, 8, 18, 13, 19, 55),
+ dnssec: 'unsigned',
+ domain_name: 'bitcoin.org',
+ expires: datetime.datetime(2029, 8, 18, 13, 19, 55),
+ name_servers: ['dns1.registrar-servers.com', 'dns2.registrar-servers.com'],
+ registrant_address: 'P.O. Box 0823-03411',
+ registrant_city: 'Panama',
+ registrant_country: 'PA',
+ registrant_name: 'WhoisGuard Protected',
+ registrant_organization: 'WhoisGuard, Inc.',
+ registrant_state: 'Panama',
+ registrant_zipcode: '',
+ registrar: 'NAMECHEAP INC',
+ status: ['clientTransferProhibited '
+ 'https://icann.org/epp#clientTransferProhibited'],
+ updated: datetime.datetime(2019, 11, 24, 13, 58, 35, 940000)}
+ ...
+ """
+```
+
+#### RDAP
+
+The `whodap` (https://github.com/pogzyb/whodap) project is used behind the scenes to perform RDAP queries.
+
+```python
+# RDAP domain query
+result = asyncwhois.rdap_domain('https://google.com')
+
+# Async RDAP domain query
+result = loop.run_until_complete(asyncwhois.aio_rdap_domain('https://google.com'))
+pprint(result.query_output) # Raw RDAP query output as a dictionary
+pprint(result.parser_output) # RDAP query output parsed/flattened into a WHOIS-like dictionary
+print(result.tld_extract_result) # tldextract result (`tldextract.tldextract.ExtractResult`)
+
+```
+
+#### Using Proxies
+
+SOCKS4 and SOCKS5 proxies are supported for WHOIS and RDAP queries.
+
+```python
+tor_host = 'localhost'
+tor_port = 9050
+
+# WHOIS Queries with Proxy
+result = asyncwhois.whois_domain(
+ 'bitcoin.org', proxy_url=f"socks5://{tor_host}:{tor_port}")
+# or with auth...
+tor_user = 'torpedo'
+tor_pw = 'torpw'
+result = asyncwhois.whois_ipv4(
+ '8.8.8.8', proxy_url=f"socks5://{tor_user}:{tor_pw}@{tor_host}:{tor_port}")
+
+# RDAP Queries with Proxy
+import httpx
+
+# EXTERNAL DEPENDENCY for SOCKS Proxies.
+from httpx_socks import SyncProxyTransport, AsyncProxyTransport
+
+transport = SyncProxyTransport.from_url(f"socks5://{tor_host}:{tor_port}")
+client = httpx.Client(transport=transport)
+result = asyncwhois.rdap_ipv6('2001:4860:4860::8888', httpx_client=client)
+
+transport = AsyncProxyTransport.from_url(f"socks5://{tor_user}:{tor_pw}@{tor_host}:{tor_port}")
+async with httpx.AsyncClient(transport=transport) as client:
+ result = await asyncwhois.aio_rdap_domain('bitcoin.org', httpx_client=client)
+
+```
+
+#### Exported Functions
+
+| Function | Description |
+| ----------- | ----------- |
+| `whois_domain` | WHOIS lookup for domain names |
+| `whois_ipv4` | WHOIS lookup for ipv4 addresses |
+| `whois_ipv6` | WHOIS lookup for ipv6 addresses |
+| `rdap_domain` | RDAP lookup for domain names |
+| `rdap_ipv4` | RDAP lookup for ipv4 addresses |
+| `rdap_ipv6` | RDAP lookup for ipv6 addresses |
+| `rdap_asn` | RDAP lookup for Autonomous System Numbers |
+| `aio_whois_domain` | async counterpart to `whois_domain` |
+| `aio_whois_ipv4` | async counterpart to `whois_ipv4` |
+| `aio_whois_ipv6` | async counterpart to `whois_ipv6` |
+| `aio_rdap_domain` | async counterpart to `rdap_domain` |
+| `aio_rdap_ipv4` | async counterpart to `rdap_ipv4` |
+| `aio_rdap_ipv6` | async counterpart to `rdap_ipv6` |
+| `aio_rdap_asn` | async counterpart to `rdap_asn` |
+
+#### Contributions
+
+Parsed output not what you expected? Unfortunately, "the format of responses [from a WHOIS server] follow a semi-free text format". Therefore,
+situations will arise where this module does not support parsing the output from a specific server, and you may find
+yourself needing more control over how parsing happens. Fortunately, you can create customized parsers to suit your needs.
+
+Example: This is a snippet of the output from running the "whois google.be" command.
+```python
+Domain: google.be
+Status: NOT AVAILABLE
+Registered: Tue Dec 12 2000
+
+Registrant:
+ Not shown, please visit www.dnsbelgium.be for webbased whois.
+
+Registrar Technical Contacts:
+ Organisation: MarkMonitor Inc.
+ Language: en
+ Phone: +1.2083895740
+ Fax: +1.2083895771
+
+Registrar:
+ Name: MarkMonitor Inc.
+ Website: http://www.markmonitor.com
+
+Nameservers:
+ ns2.google.com
+ ns1.google.com
+ ns4.google.com
+ ns3.google.com
+
+Keys:
+
+Flags:
+ clientTransferProhibited
+...
+```
+In this case, the "name servers" are listed on separate lines. The default BaseParser regexes
+won't find all of these server names. In order to accommodate this extra step, the "parse" method was
+overwritten within the parser subclass as seen below:
+```python
+class RegexBE(BaseParser):
+ _be_expressions = { # the base class (BaseParser) will handle these regexes
+ BaseKeys.CREATED: r'Registered: *(.+)',
+ BaseKeys.REGISTRAR: r'Registrar:\n.+Name: *(.+)',
+ BaseKeys.REGISTRANT_NAME: r'Registrant:\n *(.+)'
+ }
+
+ def __init__(self):
+ super().__init__()
+ self.update_reg_expressions(self._be_expressions)
+
+ def parse(self, blob: str) -> Dict[str, Any]:
+ # run base class parsing for other keys
+ parsed_output = super().parse(blob)
+ # custom parsing is needed to extract all the name servers
+ ns_match = re.search(r"Name servers: *(.+)Keys: ", blob, re.DOTALL)
+ if ns_match:
+ parsed_output[BaseKeys.NAME_SERVERS] = [m.strip() for m in ns_match.group(1).split('\n') if m.strip()]
+ return parsed_output
+```
+
+
+%package help
+Summary: Development documents and examples for asyncwhois
+Provides: python3-asyncwhois-doc
+%description help
+### asyncwhois
+
+[![PyPI version](https://badge.fury.io/py/asyncwhois.svg)](https://badge.fury.io/py/asyncwhois)
+![build-workflow](https://github.com/pogzyb/asyncwhois/actions/workflows/build-and-test.yml/badge.svg)
+[![codecov](https://codecov.io/gh/pogzyb/asyncwhois/branch/main/graph/badge.svg?token=Q4xtgezXGX)](https://codecov.io/gh/pogzyb/asyncwhois)
+[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
+
+`asyncwhois` | Async-friendly Python library for WHOIS and RDAP queries.
+
+#### Quickstart
+
+```python
+import asyncio
+from pprint import pprint
+
+import asyncwhois
+
+# pick a domain
+domain = 'bitcoin.org'
+# domain could also be a URL; asyncwhois uses tldextract to parse the URL
+domain = 'https://www.google.com?q=asyncwhois'
+
+# standard call
+result = asyncwhois.whois_domain(domain)
+# result.query_output # The semi-free text output from the whois server
+# result.parser_output # A dictionary of key:values extracted from query_output
+# result.tld_extract_result # tldextract result (`tldextract.tldextract.ExtractResult`)
+
+# asyncio call
+loop = asyncio.get_event_loop()
+result = loop.run_until_complete(asyncwhois.aio_whois_domain(domain))
+
+pprint(result.parser_output)
+"""
+{created: datetime.datetime(2008, 8, 18, 13, 19, 55),
+ dnssec: 'unsigned',
+ domain_name: 'bitcoin.org',
+ expires: datetime.datetime(2029, 8, 18, 13, 19, 55),
+ name_servers: ['dns1.registrar-servers.com', 'dns2.registrar-servers.com'],
+ registrant_address: 'P.O. Box 0823-03411',
+ registrant_city: 'Panama',
+ registrant_country: 'PA',
+ registrant_name: 'WhoisGuard Protected',
+ registrant_organization: 'WhoisGuard, Inc.',
+ registrant_state: 'Panama',
+ registrant_zipcode: '',
+ registrar: 'NAMECHEAP INC',
+ status: ['clientTransferProhibited '
+ 'https://icann.org/epp#clientTransferProhibited'],
+ updated: datetime.datetime(2019, 11, 24, 13, 58, 35, 940000)}
+ ...
+ """
+```
+
+#### RDAP
+
+The `whodap` (https://github.com/pogzyb/whodap) project is used behind the scenes to perform RDAP queries.
+
+```python
+# RDAP domain query
+result = asyncwhois.rdap_domain('https://google.com')
+
+# Async RDAP domain query
+result = loop.run_until_complete(asyncwhois.aio_rdap_domain('https://google.com'))
+pprint(result.query_output) # Raw RDAP query output as a dictionary
+pprint(result.parser_output) # RDAP query output parsed/flattened into a WHOIS-like dictionary
+print(result.tld_extract_result) # tldextract result (`tldextract.tldextract.ExtractResult`)
+
+```
+
+#### Using Proxies
+
+SOCKS4 and SOCKS5 proxies are supported for WHOIS and RDAP queries.
+
+```python
+tor_host = 'localhost'
+tor_port = 9050
+
+# WHOIS Queries with Proxy
+result = asyncwhois.whois_domain(
+ 'bitcoin.org', proxy_url=f"socks5://{tor_host}:{tor_port}")
+# or with auth...
+tor_user = 'torpedo'
+tor_pw = 'torpw'
+result = asyncwhois.whois_ipv4(
+ '8.8.8.8', proxy_url=f"socks5://{tor_user}:{tor_pw}@{tor_host}:{tor_port}")
+
+# RDAP Queries with Proxy
+import httpx
+
+# EXTERNAL DEPENDENCY for SOCKS Proxies.
+from httpx_socks import SyncProxyTransport, AsyncProxyTransport
+
+transport = SyncProxyTransport.from_url(f"socks5://{tor_host}:{tor_port}")
+client = httpx.Client(transport=transport)
+result = asyncwhois.rdap_ipv6('2001:4860:4860::8888', httpx_client=client)
+
+transport = AsyncProxyTransport.from_url(f"socks5://{tor_user}:{tor_pw}@{tor_host}:{tor_port}")
+async with httpx.AsyncClient(transport=transport) as client:
+ result = await asyncwhois.aio_rdap_domain('bitcoin.org', httpx_client=client)
+
+```
+
+#### Exported Functions
+
+| Function | Description |
+| ----------- | ----------- |
+| `whois_domain` | WHOIS lookup for domain names |
+| `whois_ipv4` | WHOIS lookup for ipv4 addresses |
+| `whois_ipv6` | WHOIS lookup for ipv6 addresses |
+| `rdap_domain` | RDAP lookup for domain names |
+| `rdap_ipv4` | RDAP lookup for ipv4 addresses |
+| `rdap_ipv6` | RDAP lookup for ipv6 addresses |
+| `rdap_asn` | RDAP lookup for Autonomous System Numbers |
+| `aio_whois_domain` | async counterpart to `whois_domain` |
+| `aio_whois_ipv4` | async counterpart to `whois_ipv4` |
+| `aio_whois_ipv6` | async counterpart to `whois_ipv6` |
+| `aio_rdap_domain` | async counterpart to `rdap_domain` |
+| `aio_rdap_ipv4` | async counterpart to `rdap_ipv4` |
+| `aio_rdap_ipv6` | async counterpart to `rdap_ipv6` |
+| `aio_rdap_asn` | async counterpart to `rdap_asn` |
+
+#### Contributions
+
+Parsed output not what you expected? Unfortunately, "the format of responses [from a WHOIS server] follow a semi-free text format". Therefore,
+situations will arise where this module does not support parsing the output from a specific server, and you may find
+yourself needing more control over how parsing happens. Fortunately, you can create customized parsers to suit your needs.
+
+Example: This is a snippet of the output from running the "whois google.be" command.
+```python
+Domain: google.be
+Status: NOT AVAILABLE
+Registered: Tue Dec 12 2000
+
+Registrant:
+ Not shown, please visit www.dnsbelgium.be for webbased whois.
+
+Registrar Technical Contacts:
+ Organisation: MarkMonitor Inc.
+ Language: en
+ Phone: +1.2083895740
+ Fax: +1.2083895771
+
+Registrar:
+ Name: MarkMonitor Inc.
+ Website: http://www.markmonitor.com
+
+Nameservers:
+ ns2.google.com
+ ns1.google.com
+ ns4.google.com
+ ns3.google.com
+
+Keys:
+
+Flags:
+ clientTransferProhibited
+...
+```
+In this case, the "name servers" are listed on separate lines. The default BaseParser regexes
+won't find all of these server names. In order to accommodate this extra step, the "parse" method was
+overwritten within the parser subclass as seen below:
+```python
+class RegexBE(BaseParser):
+ _be_expressions = { # the base class (BaseParser) will handle these regexes
+ BaseKeys.CREATED: r'Registered: *(.+)',
+ BaseKeys.REGISTRAR: r'Registrar:\n.+Name: *(.+)',
+ BaseKeys.REGISTRANT_NAME: r'Registrant:\n *(.+)'
+ }
+
+ def __init__(self):
+ super().__init__()
+ self.update_reg_expressions(self._be_expressions)
+
+ def parse(self, blob: str) -> Dict[str, Any]:
+ # run base class parsing for other keys
+ parsed_output = super().parse(blob)
+ # custom parsing is needed to extract all the name servers
+ ns_match = re.search(r"Name servers: *(.+)Keys: ", blob, re.DOTALL)
+ if ns_match:
+ parsed_output[BaseKeys.NAME_SERVERS] = [m.strip() for m in ns_match.group(1).split('\n') if m.strip()]
+ return parsed_output
+```
+
+
+%prep
+%autosetup -n asyncwhois-1.0.5
+
+%build
+%py3_build
+
+%install
+%py3_install
+install -d -m755 %{buildroot}/%{_pkgdocdir}
+if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi
+if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi
+if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi
+if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi
+pushd %{buildroot}
+if [ -d usr/lib ]; then
+ find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/lib64 ]; then
+ find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/bin ]; then
+ find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/sbin ]; then
+ find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+touch doclist.lst
+if [ -d usr/share/man ]; then
+ find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst
+fi
+popd
+mv %{buildroot}/filelist.lst .
+mv %{buildroot}/doclist.lst .
+
+%files -n python3-asyncwhois -f filelist.lst
+%dir %{python3_sitelib}/*
+
+%files help -f doclist.lst
+%{_docdir}/*
+
+%changelog
+* Fri May 05 2023 Python_Bot <Python_Bot@openeuler.org> - 1.0.5-1
+- Package Spec generated