o
    Q `#                     @   s   d Z ddlmZ ddlmZ ddlmZ ddlZddlZddlZddlZddl	m
Z
 ddlmZmZ dd	lmZ ejrUdd
lmZmZmZmZmZmZmZmZ ddl	mZ G dd deZeddZdS )zB`Registry` class mapping protocols and FS URLs to their `Opener`.
    )absolute_import)print_function)unicode_literalsN   )Opener)UnsupportedProtocolEntryPointError)parse_fs_url)CallableDictIteratorListTextTypeTupleUnion   FSc                   @   sx   e Zd ZdZdddZdd Zdd	 Zed
d Zdd Z					dddZ
				dddZej			dddZdS )Registryz'A registry for `Opener` instances.
    osfsFc                 C   s   || _ || _i | _dS )a  Create a registry object.

        Arguments:
            default_opener (str, optional): The protocol to use, if one
                is not supplied. The default is to use 'osfs', so that the
                FS URL is treated as a system path if no protocol is given.
            load_extern (bool, optional): Set to `True` to load openers from
                PyFilesystem2 extensions. Defaults to `False`.

        N)default_openerload_extern
_protocols)selfr   r    r   4/usr/lib/python3/dist-packages/fs/opener/registry.py__init__%   s   
zRegistry.__init__c                 C   s   d | jS )Nz<fs-registry {!r}>)format	protocols)r   r   r   r   __repr__5   s   zRegistry.__repr__c                 C   sN   t |tr|n| }t |tsJ d|jsJ d|jD ]}|| j|< q|S )a  Install an opener.

        Arguments:
            opener (`Opener`): an `Opener` instance, or a callable that
                returns an opener instance.

        Note:
            May be used as a class decorator. For example::
                registry = Registry()
                @registry.install
                class ArchiveOpener(Opener):
                    protocols = ['zip', 'tar']
        zOpener instance requiredzmust list one or more protocols)
isinstancer   r   r   )r   openerZ_openerprotocolr   r   r   install9   s   
zRegistry.installc                 C   s>   t | j}| jr|dd tdD  t tj|}|S )z1`list`: the list of supported protocols.
        c                 s   s    | ]}|j V  qd S )N)name).0entry_pointr   r   r   	<genexpr>W   s
    
z%Registry.protocols.<locals>.<genexpr>	fs.opener)	listr   r   extendpkg_resourcesiter_entry_pointscollectionsOrderedDictfromkeys)r   r   r   r   r   r   O   s   

zRegistry.protocolsc              
   C   s   |p| j }| jrttd|d}nd}|du r+|| jv r$| j| }|S td|z| }W n t	yD } zt
d|d}~ww t|tsNt
dz| }W |S  t	yg } zt
d|d}~ww )a  Get the opener class associated to a given protocol.

        Arguments:
            protocol (str): A filesystem protocol.

        Returns:
            Opener: an opener instance.

        Raises:
            ~fs.opener.errors.UnsupportedProtocol: If no opener
                could be found for the given protocol.
            EntryPointLoadingError: If the returned entry point
                is not an `Opener` subclass or could not be loaded
                successfully.

        r)   Nzprotocol '{}' is not supportedzcould not load entry point; {}z$entry point did not return an openerz could not instantiate opener; {})r   r   nextr,   r-   r   r   r   load	Exceptionr   
issubclassr   )r   r#   r'   Zopener_instancer"   Z	exceptionr   r   r   
get_opener^   s@   



zRegistry.get_openerT.c                 C   sL   d|vr
d ||}t|}|j}|j}| |}	|	|||||}
|
|fS )aX  Open a filesystem from a FS URL.

        Returns a tuple of a filesystem object and a path. If there is
        no path in the FS URL, the path value will be `None`.

        Arguments:
            fs_url (str): A filesystem URL.
            writeable (bool, optional): `True` if the filesystem must be
                writeable.
            create (bool, optional): `True` if the filesystem should be
                created if it does not exist.
            cwd (str): The current working directory.

        Returns:
            (FS, str): a tuple of ``(<filesystem>, <path from url>)``

        z://z{}://{})r   r	   r#   pathr5   open_fs)r   fs_url	writeablecreatecwddefault_protocolZparse_resultr#   Z	open_pathr"   r8   r   r   r   open   s   
zRegistry.openc           	      C   s:   ddl m} t||r|}|S | j|||||d\}}|S )a  Open a filesystem from a FS URL (ignoring the path component).

        Arguments:
            fs_url (str): A filesystem URL.
            writeable (bool, optional): `True` if the filesystem must
                be writeable.
            create (bool, optional): `True` if the filesystem should be
                created if it does not exist.
            cwd (str): The current working directory (generally only
                relevant for OS filesystems).
            default_protocol (str): The protocol to use if one is not
                supplied in the FS URL (defaults to ``"osfs"``).

        Returns:
            ~fs.base.FS: A filesystem instance.

        r   r   )r:   r;   r<   r=   )baser   r!   r>   )	r   r9   r:   r;   r<   r=   r   _fs_pathr   r   r   r8      s   
	
zRegistry.open_fsc                 c   sT    ddl m} t||r|V  dS | j||||d}z
|V  W |  dS |  w )a  Get a context manager to open and close a filesystem.

        Arguments:
            fs_url (FS or str): A filesystem instance or a FS URL.
            create (bool, optional): If `True`, then create the filesystem if
                it doesn't already exist.
            writeable (bool, optional): If `True`, then the filesystem
                must be writeable.
            cwd (str): The current working directory, if opening a
                `~fs.osfs.OSFS`.

        Sometimes it is convenient to be able to pass either a FS object
        *or* an FS URL to a function. This context manager handles the
        required logic for that.

        Example:
            >>> def print_ls(list_fs):
            ...     '''List a directory.'''
            ...     with manage_fs(list_fs) as fs:
            ...         print(' '.join(fs.listdir()))

            This function may be used in two ways. You may either pass
            a ``str``, as follows::

                >>> print_list('zip://projects.zip')

            Or, an filesystem instance::

                >>> from fs.osfs import OSFS
                >>> projects_fs = OSFS('~/')
                >>> print_list(projects_fs)

        r   r   )r;   r:   r<   N)r?   r   r!   r8   close)r   r9   r;   r:   r<   r   r@   r   r   r   	manage_fs   s   *

zRegistry.manage_fsN)r   F)TFr6   r   )FFr6   r   )FFr6   )__name__
__module____qualname____doc__r   r    r$   propertyr   r5   r>   r8   
contextlibcontextmanagerrC   r   r   r   r   r   !   s.    

<
*
(r   T)r   )rG   Z
__future__r   r   r   r.   rI   typingr,   r?   r   errorsr   r   parser	   ZTYPE_CHECKINGr
   r   r   r   r   r   r   r   r   objectr   registryr   r   r   r   <module>   s"   (
 |