o
    SiV                     @   sZ   d dl mZ d dlmZmZmZ d dlZd dlm	Z	 d dl
mZmZmZ G dd dZdS )    )partial)AnyDictOptionalN)	Recording)asdict_nonullfastcopyifnonec                       s   e Zd ZdZdeeeef  ddfddZdededdf fd	d
Z	dedefddZ
deddf fddZdeeef fddZdedefddZdedejfddZdedefddZdefddZ  ZS )CustomFieldMixinaX  
    :class:`CustomFieldMixin` is intended for classes such as Cut or SupervisionSegment
    that support holding custom, user-defined fields.

    .. caution:: Due to the way inheritance and dataclasses work before Python 3.10,
        it is necessary to re-define ``custom`` attribute in dataclasses that
        inherit from this mixin.
    customreturnNc                 C   s
   || _ d S Nr   )selfr    r   A/home/ubuntu/.local/lib/python3.10/site-packages/lhotse/custom.py__init__   s   
zCustomFieldMixin.__init__keyvaluec                    sX   || j v rt || dS t| ji }|du r||d n|||< |r*|| _dS dS )a0  
        This magic function is called when the user tries to set an attribute.
        We use it as syntactic sugar to store custom attributes in ``self.custom``
        field, so that they can be (de)serialized later.
        Setting a ``None`` value will remove the attribute from ``custom``.
        N)__dataclass_fields__super__setattr__r	   r   pop)r   r   r   r   	__class__r   r   r      s   

zCustomFieldMixin.__setattr__namec                 C   s^   | j }|du rtd| ||v r| j | S |dr(|dd }t| j|S td| )a  
        This magic function is called when the user tries to access an attribute
        of :class:`.MonoCut` that doesn't exist. It is used for accessing the custom
        attributes of cuts.

        We use it to look up the ``custom`` field: when it's None or empty,
        we'll just raise AttributeError as usual.
        If ``item`` is found in ``custom``, we'll return ``custom[item]``.
        If ``item`` starts with "load_", we'll assume the name of the relevant
        attribute comes after that, and that value of that field is of type
        :class:`~lhotse.array.Array` or :class:`~lhotse.array.TemporalArray`.
        We'll return its ``load`` method to call by the user.

        Example of attaching and reading an alignment as TemporalArray::

            >>> cut = MonoCut('cut1', start=0, duration=4, channel=0)
            >>> cut.alignment = TemporalArray(...)
            >>> ali = cut.load_alignment()

        NzNo such attribute: load_   )r   AttributeError
startswithr   load_custom)r   r   r   	attr_namer   r   r   __getattr__)   s   

zCustomFieldMixin.__getattr__c                    sF   || j v rt | | jdu s|| jvrtd| d| j|= dS )z/Used to support ``del cut.custom_attr`` syntax.NzNo such member: '')r   r   __delattr__r   r   )r   r   r   r   r   r$   L   s
   
zCustomFieldMixin.__delattr__c                 C   s   t | S r   )r   )r   r   r   r   to_dictT   s   zCustomFieldMixin.to_dictc                 C   s.   t | | jdur| j ni d}||j|< |S )zGReturn a copy of this object with an extra custom field assigned to it.Nr   )r   r   copy)r   r   r   cpyr   r   r   with_customW   s
   
zCustomFieldMixin.with_customc                 K   s8  ddl m}m} ddlm} | j|}t||r!|jdi |S t||r3|jd| j	| j
d|S t|tr| j| d}|du rNd|v rN|d}| j| dd	rb|jdd
|i|S |jrs|jd|| j	| j
d|S |jd|| j	| j
d|S t||r|jdi |S td| d| d| d)a!  
        Load custom data as numpy array. The custom data is expected to have
        been stored in cuts ``custom`` field as an :class:`~lhotse.array.Array`,
        :class:`~lhotse.array.TemporalArray`, or :class:`~lhotse.image.image.Image` manifest.

        .. note:: It works with Array/Image manifests stored via attribute assignments,
            e.g.: ``cut.my_custom_data = Array(...)`` or ``cut = cut.attach_image('img', ...)``.

        :param name: name of the custom attribute.
        :return: a numpy array with the data.
        r   )ArrayTemporalArray)Image)startduration_channel_selectorNchannel
_unalignedFchannels)r1   offsetr-   zTo load z, the cut needs to have field z (or cut.custom['zW']) defined, and its value has to be a manifest of type Array, TemporalArray, or Image.r   )lhotse.arrayr)   r*   lhotse.image.imager+   r   get
isinstanceloadr,   r-   r   r   
load_audio	has_video
load_video
ValueError)r   r   kwargsr)   r*   r+   r   r1   r   r   r   r    _   sB   




zCustomFieldMixin.load_customc                 C   s   | j du rdS || j v S )z
        Check if the Cut has a custom attribute with name ``name``.

        :param name: name of the custom attribute.
        :return: a boolean.
        NFr   r   r   r   r   r   
has_custom   s   

zCustomFieldMixin.has_customc                 C   s$   | j d u s
|| j vrd S | j |= | S r   r   r=   r   r   r   drop_custom   s   zCustomFieldMixin.drop_custom)__name__
__module____qualname____doc__r   r   strr   r   r   r"   r$   r%   r(   npndarrayr    boolr>   r?   __classcell__r   r   r   r   r
   
   s    	#6r
   )	functoolsr   typingr   r   r   numpyrE   lhotser   lhotse.utilsr   r   r	   r
   r   r   r   r   <module>   s    