Source code for tld.base

import logging
from codecs import open as codecs_open
from typing import Dict, ItemsView, Optional, Union
from urllib.request import urlopen

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

__author__ = "Artur Barseghyan"
__copyright__ = "2013-2023 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, "BaseTLDSourceParser"] = {} def __new__(mcs, name, bases, attrs): 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 return new_cls @property def _uid(cls) -> str: return getattr(cls, "uid", cls.__name__)
[docs] @classmethod def reset(mcs) -> None: mcs.REGISTRY = {}
[docs] @classmethod def get( mcs, key: str, default: "BaseTLDSourceParser" = None ) -> Union["BaseTLDSourceParser", None]: return mcs.REGISTRY.get(key, default)
[docs] @classmethod def items(mcs) -> ItemsView[str, "BaseTLDSourceParser"]: return mcs.REGISTRY.items()
# @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) local_file = codecs_open(local_file_abs_path, "wb", encoding="utf8") local_file.write(remote_file.read().decode("utf8")) local_file.close() 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) return True