diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa25c115..7d61095e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,6 +32,7 @@ jobs: uses: actions/setup-python@v5 with: python-version: ${{ matrix.language.python-version }} + check-latest: true - name: Install Python requirements run: | pip install --upgrade pip diff --git a/tests/main_test.py b/tests/main_test.py index c4050f7d..4b260b14 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -4,6 +4,7 @@ import logging import os +import sys import tempfile from collections.abc import Sequence from pathlib import Path @@ -17,7 +18,7 @@ import tldextract import tldextract.suffix_list from tldextract.cache import DiskCache -from tldextract.remote import inet_pton, lenient_netloc, looks_like_ip +from tldextract.remote import lenient_netloc, looks_like_ip, looks_like_ipv6 from tldextract.suffix_list import SuffixListNotFound from tldextract.tldextract import ExtractResult @@ -152,21 +153,24 @@ def test_lenient_netloc() -> None: ) -@pytest.mark.skipif(not inet_pton, reason="inet_pton unavailable") -def test_looks_like_ip_with_inet_pton() -> None: - """Test preferred function to check if a string looks like an IP address.""" - assert looks_like_ip("1.1.1.1", inet_pton) is True - assert looks_like_ip("a.1.1.1", inet_pton) is False - assert looks_like_ip("1.1.1.1\n", inet_pton) is False - assert looks_like_ip("256.256.256.256", inet_pton) is False +def test_looks_like_ip() -> None: + """Test function to check if a string looks like an IPv4 address.""" + assert looks_like_ip("1.1.1.1") is True + assert looks_like_ip("1.1.1.01") is False + assert looks_like_ip("a.1.1.1") is False + assert looks_like_ip("1.1.1.1\n") is False + assert looks_like_ip("256.256.256.256") is False -def test_looks_like_ip_without_inet_pton() -> None: - """Test fallback function to check if a string looks like an IP address.""" - assert looks_like_ip("1.1.1.1", None) is True - assert looks_like_ip("a.1.1.1", None) is False - assert looks_like_ip("1.1.1.1\n", None) is False - assert looks_like_ip("256.256.256.256", None) is False +def test_looks_like_ipv6() -> None: + """Test function to check if a string looks like an IPv6 address.""" + assert looks_like_ipv6("::") is True + assert looks_like_ipv6("aBcD:ef01:2345:6789:aBcD:ef01:aaaa:2288") is True + assert looks_like_ipv6("aBcD:ef01:2345:6789:aBcD:ef01:127.0.0.1") is True + assert looks_like_ipv6("ZBcD:ef01:2345:6789:aBcD:ef01:127.0.0.1") is False + if sys.version_info >= (3, 8, 12): # noqa: UP036 + assert looks_like_ipv6("aBcD:ef01:2345:6789:aBcD:ef01:127.0.0.01") is False + assert looks_like_ipv6("aBcD:ef01:2345:6789:aBcD:") is False def test_similar_to_ip() -> None: diff --git a/tldextract/cache.py b/tldextract/cache.py index ce3b1fd6..7f6d5d01 100644 --- a/tldextract/cache.py +++ b/tldextract/cache.py @@ -38,8 +38,7 @@ def md5(*args: bytes) -> hashlib._Hash: def get_pkg_unique_identifier() -> str: - """ - Generate an identifier unique to the python version, tldextract version, and python instance. + """Generate an identifier unique to the python version, tldextract version, and python instance. This will prevent interference between virtualenvs and issues that might arise when installing a new version of tldextract @@ -66,8 +65,7 @@ def get_pkg_unique_identifier() -> str: def get_cache_dir() -> str: - """ - Get a cache dir that we have permission to write to. + """Get a cache dir that we have permission to write to. Try to follow the XDG standard, but if that doesn't work fallback to the package directory http://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html diff --git a/tldextract/remote.py b/tldextract/remote.py index 228fa345..08b07221 100644 --- a/tldextract/remote.py +++ b/tldextract/remote.py @@ -3,16 +3,9 @@ from __future__ import annotations import re -from collections.abc import Callable from ipaddress import AddressValueError, IPv6Address from urllib.parse import scheme_chars -inet_pton: Callable[[int, str], bytes] | None -try: - from socket import AF_INET, AF_INET6, inet_pton # Availability: Unix, Windows. -except ImportError: - inet_pton = None - IP_RE = re.compile( r"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)" r"{3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" @@ -59,32 +52,16 @@ def _schemeless_url(url: str) -> str: return url[double_slashes_start + 2 :] -def looks_like_ip( - maybe_ip: str, pton: Callable[[int, str], bytes] | None = inet_pton -) -> bool: - """Check whether the given str looks like an IP address.""" +def looks_like_ip(maybe_ip: str) -> bool: + """Check whether the given str looks like an IPv4 address.""" if not maybe_ip[0].isdigit(): return False - if pton is not None: - try: - pton(AF_INET, maybe_ip) - return True - except OSError: - return False return IP_RE.fullmatch(maybe_ip) is not None -def looks_like_ipv6( - maybe_ip: str, pton: Callable[[int, str], bytes] | None = inet_pton -) -> bool: +def looks_like_ipv6(maybe_ip: str) -> bool: """Check whether the given str looks like an IPv6 address.""" - if pton is not None: - try: - pton(AF_INET6, maybe_ip) - return True - except OSError: - return False try: IPv6Address(maybe_ip) except AddressValueError: diff --git a/tldextract/tldextract.py b/tldextract/tldextract.py index 902cae69..0e570acd 100644 --- a/tldextract/tldextract.py +++ b/tldextract/tldextract.py @@ -75,8 +75,7 @@ class ExtractResult: @property def registered_domain(self) -> str: - """ - Joins the domain and suffix fields with a dot, if they're both set. + """Joins the domain and suffix fields with a dot, if they're both set. >>> extract('http://forums.bbc.co.uk').registered_domain 'bbc.co.uk' @@ -89,8 +88,7 @@ def registered_domain(self) -> str: @property def fqdn(self) -> str: - """ - Returns a Fully Qualified Domain Name, if there is a proper domain/suffix. + """Returns a Fully Qualified Domain Name, if there is a proper domain/suffix. >>> extract('http://forums.bbc.co.uk/path/to/file').fqdn 'forums.bbc.co.uk' @@ -103,8 +101,7 @@ def fqdn(self) -> str: @property def ipv4(self) -> str: - """ - Returns the ipv4 if that is what the presented domain/url is. + """Returns the ipv4 if that is what the presented domain/url is. >>> extract('http://127.0.0.1/path/to/file').ipv4 '127.0.0.1' @@ -123,8 +120,7 @@ def ipv4(self) -> str: @property def ipv6(self) -> str: - """ - Returns the ipv6 if that is what the presented domain/url is. + """Returns the ipv6 if that is what the presented domain/url is. >>> extract('http://[aBcD:ef01:2345:6789:aBcD:ef01:127.0.0.1]/path/to/file').ipv6 'aBcD:ef01:2345:6789:aBcD:ef01:127.0.0.1' @@ -334,8 +330,7 @@ def update( @property def tlds(self, session: requests.Session | None = None) -> list[str]: - """ - Returns the list of tld's used by default. + """Returns the list of tld's used by default. This will vary based on `include_psl_private_domains` and `extra_suffixes` """