| |
| import inspect |
| from typing import Optional, Type, Union |
|
|
| from .base import BaseStorageBackend |
| from .http_backend import HTTPBackend |
| from .lmdb_backend import LmdbBackend |
| from .local_backend import LocalBackend |
| from .memcached_backend import MemcachedBackend |
| from .petrel_backend import PetrelBackend |
|
|
| backends: dict = {} |
| prefix_to_backends: dict = {} |
|
|
|
|
| def _register_backend(name: str, |
| backend: Type[BaseStorageBackend], |
| force: bool = False, |
| prefixes: Union[str, list, tuple, None] = None): |
| """Register a backend. |
| |
| Args: |
| name (str): The name of the registered backend. |
| backend (BaseStorageBackend): The backend class to be registered, |
| which must be a subclass of :class:`BaseStorageBackend`. |
| force (bool): Whether to override the backend if the name has already |
| been registered. Defaults to False. |
| prefixes (str or list[str] or tuple[str], optional): The prefix |
| of the registered storage backend. Defaults to None. |
| """ |
| global backends, prefix_to_backends |
|
|
| if not isinstance(name, str): |
| raise TypeError('the backend name should be a string, ' |
| f'but got {type(name)}') |
|
|
| if not inspect.isclass(backend): |
| raise TypeError(f'backend should be a class, but got {type(backend)}') |
| if not issubclass(backend, BaseStorageBackend): |
| raise TypeError( |
| f'backend {backend} is not a subclass of BaseStorageBackend') |
|
|
| if name in backends and not force: |
| raise ValueError(f'{name} is already registered as a storage backend, ' |
| 'add "force=True" if you want to override it') |
| backends[name] = backend |
|
|
| if prefixes is not None: |
| if isinstance(prefixes, str): |
| prefixes = [prefixes] |
| else: |
| assert isinstance(prefixes, (list, tuple)) |
|
|
| for prefix in prefixes: |
| if prefix in prefix_to_backends and not force: |
| raise ValueError( |
| f'{prefix} is already registered as a storage backend,' |
| ' add "force=True" if you want to override it') |
|
|
| prefix_to_backends[prefix] = backend |
|
|
|
|
| def register_backend(name: str, |
| backend: Optional[Type[BaseStorageBackend]] = None, |
| force: bool = False, |
| prefixes: Union[str, list, tuple, None] = None): |
| """Register a backend. |
| |
| Args: |
| name (str): The name of the registered backend. |
| backend (class, optional): The backend class to be registered, |
| which must be a subclass of :class:`BaseStorageBackend`. |
| When this method is used as a decorator, backend is None. |
| Defaults to None. |
| force (bool): Whether to override the backend if the name has already |
| been registered. Defaults to False. |
| prefixes (str or list[str] or tuple[str], optional): The prefix |
| of the registered storage backend. Defaults to None. |
| |
| This method can be used as a normal method or a decorator. |
| |
| Examples: |
| |
| >>> class NewBackend(BaseStorageBackend): |
| ... def get(self, filepath): |
| ... return filepath |
| ... |
| ... def get_text(self, filepath): |
| ... return filepath |
| >>> register_backend('new', NewBackend) |
| |
| >>> @register_backend('new') |
| ... class NewBackend(BaseStorageBackend): |
| ... def get(self, filepath): |
| ... return filepath |
| ... |
| ... def get_text(self, filepath): |
| ... return filepath |
| """ |
| if backend is not None: |
| _register_backend(name, backend, force=force, prefixes=prefixes) |
| return |
|
|
| def _register(backend_cls): |
| _register_backend(name, backend_cls, force=force, prefixes=prefixes) |
| return backend_cls |
|
|
| return _register |
|
|
|
|
| register_backend('local', LocalBackend, prefixes='') |
| register_backend('memcached', MemcachedBackend) |
| register_backend('lmdb', LmdbBackend) |
| |
| |
| register_backend('petrel', PetrelBackend, prefixes=['petrel', 's3']) |
| register_backend('http', HTTPBackend, prefixes=['http', 'https']) |
|
|