Source code for tld.base

import logging
from typing import Dict, ItemsView, Optional, Type, ValuesView
from urllib.request import urlopen

from .exceptions import TldImproperlyConfigured, TldIOError
from .helpers import project_dir

__author__ = "Artur Barseghyan"
__copyright__ = "2013-2026 Artur Barseghyan"
__license__ = "MPL-1.1 OR GPL-2.0-only OR LGPL-2.1-or-later"
__all__ = (
    "BaseTLDSourceParser",
    "Registry",
)

LOGGER = logging.getLogger(__name__)


[docs] class Registry(type): REGISTRY: Dict[str, Type["BaseTLDSourceParser"]] = {} def __new__(mcs, name, bases, attrs): # noqa: N804 new_cls = type.__new__(mcs, name, bases, attrs) # Here the name of the class is used as key but it could be any class # parameter. if getattr(new_cls, "_uid", None): mcs.REGISTRY[new_cls._uid] = new_cls # type: ignore return new_cls @property def _uid(cls) -> str: return getattr(cls, "uid", cls.__name__)
[docs] @classmethod def reset(cls) -> None: cls.REGISTRY = {}
[docs] @classmethod def get( cls, key: str, default: Optional[Type["BaseTLDSourceParser"]] = None ) -> Optional[Type["BaseTLDSourceParser"]]: return cls.REGISTRY.get(key, default)
[docs] @classmethod def items(cls) -> ItemsView[str, Type["BaseTLDSourceParser"]]: return cls.REGISTRY.items()
[docs] @classmethod def values(cls) -> ValuesView[Type["BaseTLDSourceParser"]]: return cls.REGISTRY.values()
# @classmethod # def get_registry(mcs) -> Dict[str, Type]: # return dict(mcs.REGISTRY) # # @classmethod # def pop(mcs, uid) -> None: # mcs.REGISTRY.pop(uid)
[docs] class BaseTLDSourceParser(metaclass=Registry): """Base TLD source parser.""" uid: Optional[str] = None source_url: str local_path: str include_private: bool = True
[docs] @classmethod def validate(cls): """Constructor.""" if not cls.uid: raise TldImproperlyConfigured( "The `uid` property of the TLD source parser shall be defined." )
[docs] @classmethod def get_tld_names(cls, fail_silently: bool = False, retry_count: int = 0): """Get tld names. :param fail_silently: :param retry_count: :return: """ cls.validate() raise NotImplementedError( "Your TLD source parser shall implement `get_tld_names` method." )
[docs] @classmethod def update_tld_names(cls, fail_silently: bool = False) -> bool: """Update the local copy of the TLD file. :param fail_silently: :return: """ try: remote_file = urlopen(cls.source_url) local_file_abs_path = project_dir(cls.local_path) with open(local_file_abs_path, "w", encoding="utf8") as local_file: local_file.write(remote_file.read().decode("utf8")) remote_file.close() LOGGER.info( f"Fetched '{cls.source_url}' as '{local_file_abs_path}'" ) except Exception as err: LOGGER.error( f"Failed fetching '{cls.source_url}'. Reason: {str(err)}" ) if fail_silently: return False raise TldIOError(err) from err return True