B
    i\l5                 @   s   d Z ddlmZ ddlZddlZddlm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
 ZG dd deZejG dd dejeZejG dd dejeZdS )a  Create links in the HDF5 file.

This module implements containers for soft and external links.  Hard
links doesn't need a container as such as they are the same as regular
nodes (groups or leaves).

Classes:

    SoftLink
    ExternalLink

Functions:

Misc variables:

    )absolute_importN   )linkextension)Node)lazyattr)AttributeSetc             C   s   t | |S )zGuess the link class.)r   Z_get_link_class)Z	parent_idname r	   *lib/python3.7/site-packages/tables/link.py_g_get_link_class)   s    r   c                   s\   e Zd ZdZedd Zd fdd	Zddd	Zdd
dZdd Z	dddZ
dd Z  ZS )Linka  Abstract base class for all PyTables links.

    A link is a node that refers to another node.  The Link class inherits from
    Node class and the links that inherits from Link are SoftLink and
    ExternalLink.  There is not a HardLink subclass because hard links behave
    like a regular Group or Leaf.  Contrarily to other nodes, links cannot have
    HDF5 attributes.  This is an HDF5 library limitation that might be solved
    in future releases.

    See :ref:`LinksTutorial` for a small tutorial on how to work with links.

    .. rubric:: Link attributes

    .. attribute:: target

        The path string to the pointed node.

    c             C   s   G dd dt }|| S )z
        A *NoAttrs* instance replacing the typical *AttributeSet* instance of
        other node objects.  The purpose of *NoAttrs* is to make clear that
        HDF5 attributes are not supported in link nodes.
        c               @   s$   e Zd Zdd Zdd Zdd ZdS )zLink._v_attrs.<locals>.NoAttrsc             S   s   t d| jj d S )Nz1you cannot get attributes from this `%s` instance)KeyError	__class____name__)selfr   r	   r	   r
   __getattr__M   s    z*Link._v_attrs.<locals>.NoAttrs.__getattr__c             S   s   t d| jj d S )Nz/you cannot set attributes to this `%s` instance)r   r   r   )r   r   valuer	   r	   r
   __setattr__Q   s    z*Link._v_attrs.<locals>.NoAttrs.__setattr__c             S   s   d S )Nr	   )r   r	   r	   r
   _g_closeU   s    z'Link._v_attrs.<locals>.NoAttrs._g_closeN)r   
__module____qualname__r   r   r   r	   r	   r	   r
   NoAttrsL   s   r   )r   )r   r   r	   r	   r
   _v_attrsE   s    zLink._v_attrsNFc                s(   |d k	| _ || _tt| ||| d S )N)Z_v_newtargetsuperr   __init__)r   
parentnoder   r   _log)r   r	   r
   r   Y   s    
zLink.__init__c             C   s&   | j ||||d}|j||d |S )zCopy this link and return the new one.

        See :meth:`Node._f_copy` for a complete explanation of the arguments.
        Please note that there is no recursive flag since links do not have
        child nodes.

        )	newparentnewname	overwritecreateparentsT)Z_f_copy	_v_parentZ
_g_refnode)r   r   r   r    r!   Znewnoder	   r	   r
   copya   s
    
z	Link.copyc             C   s   | j |||dS )zrMove or rename this link.

        See :meth:`Node._f_move` for a complete explanation of the arguments.

        )r   r   r    )Z_f_move)r   r   r   r    r	   r	   r
   mover   s    z	Link.movec             C   s   |   S )z$Remove this link from the hierarchy.)Z	_f_remove)r   r	   r	   r
   remove|   s    zLink.removec             C   s   | j ||dS )zuRename this link in place.

        See :meth:`Node._f_rename` for a complete explanation of the arguments.

        )r   r    )Z	_f_rename)r   r   r    r	   r	   r
   rename   s    zLink.renamec             C   s   t | S )N)str)r   r	   r	   r
   __repr__   s    zLink.__repr__)NF)NNFF)NNF)NF)r   r   r   __doc__r   r   r   r#   r$   r%   r&   r(   __classcell__r	   r	   )r   r
   r   0   s    



	r   c               @   s\   e Zd ZdZdZdZdZdd Zdd Zd	d
 Z	dd Z
dd Zdd Zdd Zdd ZdS )SoftLinka,  Represents a soft link (aka symbolic link).

    A soft link is a reference to another node in the *same* file hierarchy.
    Provided that the target node exists, its attributes and methods can be
    accessed directly from the softlink using the normal `.` syntax.

    Softlinks also have the following public methods/attributes:

        * `target`
        * `dereference()`
        * `copy()`
        * `move()`
        * `remove()`
        * `rename()`
        * `is_dangling()`

    Note that these will override any correspondingly named methods/attributes
    of the target node.

    For backwards compatibility, it is also possible to obtain the target node
    via the `__call__()` special method (this action is called *dereferencing*;
    see below)

    Examples
    --------

    ::

        >>> f = tables.open_file('/tmp/test_softlink.h5', 'w')
        >>> a = f.create_array('/', 'A', np.arange(10))
        >>> link_a = f.create_soft_link('/', 'link_A', target='/A')

        # transparent read/write access to a softlinked node
        >>> link_a[0] = -1
        >>> print(link_a[:], link_a.dtype)
        (array([-1,  1,  2,  3,  4,  5,  6,  7,  8,  9]), dtype('int64'))

        # dereferencing a softlink using the __call__() method
        >>> print(link_a() is a)
        True

        # SoftLink.remove() overrides Array.remove()
        >>> link_a.remove()
        >>> print(link_a)
        <closed tables.link.SoftLink at 0x7febe97186e0>
        >>> print(a[:], a.dtype)
        (array([-1,  1,  2,  3,  4,  5,  6,  7,  8,  9]), dtype('int64'))


    ZSOFTLINK)r   dereferenceis_danglingr#   r$   r%   r&   r   __str__r(   Z__unicode__r   __dict__)Z_f_Z_c_Z_g_Z_v_c             C   s   |   S )a;  Dereference `self.target` and return the object.

        Examples
        --------

        ::

            >>> f=tables.open_file('data/test.h5')
            >>> print(f.root.link0)
            /link0 (SoftLink) -> /another/path
            >>> print(f.root.link0())
            /another/path (Group) ''

        )r,   )r   r	   r	   r
   __call__   s    zSoftLink.__call__c             C   s:   | j r2| j}| jds&| j| j}| j|S d S d S )N/)	_v_isopenr   
startswithr"   _g_join_v_file	_get_node)r   r   r	   r	   r
   r,      s    zSoftLink.dereferencec             C   sx   |t jks|d d t jkr(t| |S | js:tdn:|  rFd S | 	 }y
||S  t
k
rr   ||S X d S )N   zthe node object is closed)r+   _link_attrnames_link_attrprefixesobject__getattribute__r2   tablesClosedNodeErrorr-   r,   AttributeErrorr   )r   attrnameZtarget_noder	   r	   r
   r;      s    

zSoftLink.__getattribute__c             C   sd   |t jks|d d t jkr,t| || n4| js>tdn"|  rPt	dn| 
 || d S )Nr7   zthe node object is closedzsoftlink target does not exist)r+   r8   r9   r:   r   r2   r<   r=   r-   
ValueErrorr,   )r   r?   r   r	   r	   r
   r      s    

zSoftLink.__setattr__c             C   s6   | j stdn |  r$tdn|  |S dS )zd__getitem__ must be defined in the SoftLink class in order for array
        indexing syntax to workzthe node object is closedzsoftlink target does not existN)r2   r<   r=   r-   r@   r,   __getitem__)r   keyr	   r	   r
   rA     s
    
zSoftLink.__getitem__c             C   s8   | j stdn"|  r$tdn|  || dS )zd__setitem__ must be defined in the SoftLink class in order for array
        indexing syntax to workzthe node object is closedzsoftlink target does not existN)r2   r<   r=   r-   r@   r,   __setitem__)r   rB   r   r	   r	   r
   rC     s
    
zSoftLink.__setitem__c             C   s   |   | jkS )N)r,   r5   )r   r	   r	   r
   r-   %  s    zSoftLink.is_danglingc             C   sf   | j j}t| j}| jds,| j| j}| jr8d}nd}|| jkrLd}nd}d|| j	|| j|f S )zReturn a short string representation of the link.

        Examples
        --------

        ::

            >>> f=tables.open_file('data/test.h5')
            >>> print(f.root.link0)
            /link0 (SoftLink) -> /path/to/node

        r1    zclosed z (dangling)z%s%s (%s) -> %s%s)
r   r   r'   r   r3   r"   r4   r2   r5   _v_pathname)r   	classnamer   closedZdanglingr	   r	   r
   r.   )  s    


zSoftLink.__str__N)r   r   r   r)   
_c_classidr8   r9   r0   r,   r;   r   rA   rC   r-   r.   r	   r	   r	   r
   r+      s   3r+   c                   sR   e Zd ZdZdZd fdd	Zdd Zd	d
 Zdd Z fddZ	dd Z
  ZS )ExternalLinka  Represents an external link.

    An external link is a reference to a node in *another* file.
    Getting access to the pointed node (this action is called
    *dereferencing*) is done via the :meth:`__call__` special method
    (see below).

    .. rubric:: ExternalLink attributes

    .. attribute:: extfile

        The external file handler, if the link has been dereferenced.
        In case the link has not been dereferenced yet, its value is
        None.

    ZEXTERNALLINKNFc                s    d | _ tt| |||| d S )N)extfiler   rI   r   )r   r   r   r   r   )r   r	   r
   r   _  s    zExternalLink.__init__c             C   s   | j d\}}|d| fS )z=Return the external filename and nodepath from `self.target`.z:/r1   )r   split)r   filenamer   r	   r	   r
   _get_filename_nodef  s    zExternalLink._get_filename_nodec             K   s   |   \}}tj|s6tj| jj}tj||}| jdksH| jj	sZt
j|f|| _n(| jj|ksjt| jj|ddkst| j|S )a  Dereference self.target and return the object.

        You can pass all the arguments supported by the :func:`open_file`
        function (except filename, of course) so as to open the referenced
        external file.

        Examples
        --------

        ::

            >>> f=tables.open_file('data1/test1.h5')
            >>> print(f.root.link2)
            /link2 (ExternalLink) -> data2/test2.h5:/path/to/node
            >>> plink2 = f.root.link2('a')  # open in 'a'ppend mode
            >>> print(plink2)
            /path/to/node (Group) ''
            >>> print(plink2._v_filename)
            'data2/test2.h5'        # belongs to referenced file

        Nmoder)rM   ospathisabsdirnamer5   rL   joinrJ   isopenr<   Z	open_fileAssertionErrorrN   getr6   )r   kwargsrL   r   Zbase_directoryr	   r	   r
   r0   m  s    zExternalLink.__call__c             C   s&   | j }|dk	r"|jr"|  d| _ dS )z'Safely unmount self.extfile, if opened.N)rJ   rU   close)r   rJ   r	   r	   r
   umount  s    zExternalLink.umountc                s   |    tt|   dS )z#Especific close for external links.N)rZ   r   rI   _f_close)r   )r   r	   r
   r[     s    zExternalLink._f_closec             C   s   | j j}d| j|| jf S )a  Return a short string representation of the link.

        Examples
        --------

        ::

            >>> f=tables.open_file('data1/test1.h5')
            >>> print(f.root.link2)
            /link2 (ExternalLink) -> data2/test2.h5:/path/to/node

        z%s (%s) -> %s)r   r   rE   r   )r   rF   r	   r	   r
   r.     s    zExternalLink.__str__)NF)r   r   r   r)   rH   r   rM   r0   rZ   r[   r.   r*   r	   r	   )r   r
   rI   H  s   (	rI   )r)   Z
__future__r   rP   r<   rD   r   Znoder   Zutilsr   Zattributesetr   ZsixZtables.filer   r   Zpython_2_unicode_compatibler+   rI   r	   r	   r	   r
   <module>   s    ^ :