o
    ei$(                     @   s   d Z ddl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
 G dd deZG dd deZdd
edede	e fddZdedefddZ		ddededefddZ			ddedede
e deddf
ddZdS )zG
Module importing related utilities.

Author
 * Sylvain de Langen 2024
    N)
ModuleType)ListOptionalc                       sZ   e Zd ZdZdededee f fddZdedefd	d
Z	defddZ
dd Z  ZS )
LazyModulea  Defines a module type that lazily imports the target module, thus
    exposing contents without importing the target module needlessly.

    Arguments
    ---------
    name : str
        Name of the module.
    target : str
        Module to be loading lazily.
    package : str, optional
        If specified, the target module load will be relative to this package.
        Depending on how you inject the lazy module into the environment, you
        may choose to specify the package here, or you may choose to include it
        into the `name` with the dot syntax.
        e.g. see how :func:`~lazy_export` and :func:`~deprecated_redirect`
        differ.
    nametargetpackagec                    s"   t  | || _d | _|| _d S N)super__init__r   lazy_moduler   )selfr   r   r   	__class__ [/home/ubuntu/transcripts/venv/lib/python3.10/site-packages/speechbrain/utils/importutils.pyr   $   s   
zLazyModule.__init__
stacklevelreturnc              
   C   s   d}zt t|d }W n ty   td Y nw |dur*|jdr*t | j	du rgz | j
du r@t| j| _	W | j	S td| j | j
| _	W | j	S  tyf } ztdt|  d|d}~ww | j	S )ar  Ensures that the target module is imported and available as
        `self.lazy_module`, also returning it.

        Arguments
        ---------
        stacklevel : int
            The stack trace level of the function that caused the import to
            occur, relative to the **caller** of this function (e.g. if in
            function `f` you call `ensure_module(1)`, it will refer to the
            function that called `f`).

        Raises
        ------
        AttributeError
            When the function responsible for the import attempt is found to be
            `inspect.py`, we raise an `AttributeError` here. This is because
            some code will inadvertently cause our modules to be imported, such
            as some of PyTorch's op registering machinery.

        Returns
        -------
        The target module after ensuring it is imported.
        N   zFailed to inspect frame to check if we should ignore importing a module lazily. This relies on a CPython implementation detail, report an issue if you see this with standard Python and include your version number.z/inspect.py.zLazy import of z failed)inspectgetframeinfosys	_getframeAttributeErrorwarningswarnfilenameendswithr   r   	importlibimport_moduler   	ExceptionImportErrorrepr)r   r   importer_frameer   r   r   ensure_module/   s4   

zLazyModule.ensure_modulec                 C   s"   d| j  d| j d| jd u dS )NzLazyModule(package=z	, target=z	, loaded=))r   r   r   )r   r   r   r   __repr__k   s   "zLazyModule.__repr__c                 C   s   t | d|S Nr   )getattrr&   )r   attrr   r   r   __getattr__n   s   zLazyModule.__getattr__)__name__
__module____qualname____doc__strr   r   intr   r&   r(   r,   __classcell__r   r   r   r   r      s    <r   c                       sT   e Zd ZdZ	ddededee f fddZdd	 Zd
ede	f fddZ
  ZS )DeprecatedModuleRedirecta  Defines a module type that lazily imports the target module using
    :class:`~LazyModule`, but logging a deprecation warning when the import
    is actually being performed.

    This is only the module type itself; if you want to define a redirection,
    use :func:`~deprecated_redirect` instead.

    Arguments
    ---------
    old_import : str
        Old module import path e.g. `mypackage.myoldmodule`
    new_import : str
        New module import path e.g. `mypackage.mynewcoolmodule.mycoolsubmodule`
    extra_reason : str, optional
        If specified, extra text to attach to the warning for clarification
        (e.g. justifying why the move has occurred, or additional problems to
        look out for).
    N
old_import
new_importextra_reasonc                    s"   t  j||d d || _|| _d S )N)r   r   r   )r
   r   r5   r7   )r   r5   r6   r7   r   r   r   r      s   
z!DeprecatedModuleRedirect.__init__c                 C   sB   d| j  d| j d}| jdur|d| j 7 }tj|dd dS )zREmits the warning for the redirection (with the extra reason if
        provided).zModule 'z"' was deprecated, redirecting to 'z'. Please update your script.N    )r   )r5   r   r7   r   r   )r   warning_textr   r   r   _redirection_warn   s   


z*DeprecatedModuleRedirect._redirection_warnr   r   c                    s*   | j d u }t |d }|r|   |S r)   )r   r
   r&   r;   )r   r   should_warnmoduler   r   r   r&      s
   
z&DeprecatedModuleRedirect.ensure_moduler	   )r-   r.   r/   r0   r1   r   r   r;   r2   r   r&   r3   r   r   r   r   r4   s   s    
r4   F	file_pathfind_subpackagesr   c                 C   sp   g }t j| }t |D ](}|drq|dr#||dd  |r5t jt j||r5|| q|S )a  Returns a list of importable scripts in the same module as the specified
    file. e.g. if you have `foo/__init__.py` and `foo/bar.py`, then
    `files_in_module("foo/__init__.py")` then the result will be `["bar"]`.

    Not recursive; this is only applies to the direct modules/subpackages of the
    package at the given path.

    Arguments
    ---------
    file_path : str
        Path of the file to navigate the directory of. Typically the
        `__init__.py` path this is called from, using `__file__`.
    find_subpackages : bool
        Whether we should find the subpackages as well.

    Returns
    -------
    imports : List[str]
        List of importable scripts with the same module.
    __z.pyN)	ospathdirnamelistdir
startswithr   appendisdirjoin)r>   r?   imports
module_dirr   r   r   r   find_imports   s   



rL   r   r   c                 C   s2   t tj| | r
dS ttj| | t| | | dS )a  Makes `name` lazily available under the module list for the specified
    `package`, unless it was loaded already, in which case it is ignored.

    Arguments
    ---------
    name : str
        Name of the module, as long as it can get imported with
        `{package}.{name}`.
    package : str
        The relevant package, usually determined with `__name__` from the
        `__init__.py`.

    Returns
    -------
    None
    N)hasattrr   modulessetattrr   )r   r   r   r   r   lazy_export   s   rP   init_file_pathexport_subpackagesc                 C   s    t | |dD ]}t|| qdS )a  Makes all modules under a module lazily importable merely by accessing
    them; e.g. `foo/bar.py` could be accessed with `foo.bar.some_func()`.

    Arguments
    ---------
    init_file_path : str
        Path of the `__init__.py` file, usually determined with `__file__` from
        there.
    package : str
        The relevant package, usually determined with `__name__` from the
        `__init__.py`.
    export_subpackages : bool
        Whether we should make the subpackages (subdirectories) available
        directly as well.
    )r?   N)rL   rP   )rQ   r   rR   r   r   r   r   lazy_export_all   s
   
rS   r5   r6   r7   also_lazy_exportc                 C   sp   t | ||d}|tj| < |r4| d}| d| }| |d d }ttj| |s6ttj| || dS dS dS )a  Patches the module list to add a lazy redirection from `old_import` to
    `new_import`, emitting a `DeprecationWarning` when imported.

    Arguments
    ---------
    old_import : str
        Old module import path e.g. `mypackage.myoldmodule`
    new_import : str
        New module import path e.g. `mypackage.mycoolpackage.mynewmodule`
    extra_reason : str, optional
        If specified, extra text to attach to the warning for clarification
        (e.g. justifying why the move has occurred, or additional problems to
        look out for).
    also_lazy_export : bool
        Whether the module should also be exported as a lazy module in the
        package determined in `old_import`.
        e.g. if you had a `foo.bar.somefunc` import as `old_import`, assuming
        you have `foo` imported (or lazy loaded), you could use
        `foo.bar.somefunc` directly without importing `foo.bar` explicitly.
    )r7   r   Nr   )r4   r   rN   rfindrM   rO   )r5   r6   r7   rT   redirectpackage_sep_idxold_package
old_moduler   r   r   deprecated_redirect  s   

rZ   )F)NF)r0   r   r   rB   r   r   typesr   typingr   r   r   r4   r1   boolrL   rP   rS   rZ   r   r   r   r   <module>   sB    bA)
