o
    qoi                     @   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ZddlZddlm	Z	m
Z
mZ ejdde
d fddZ				dd	ed
e	defddZejddG dd dZdede	fddZdS )zLazy imports API and utils.    N)AnyIteratorOptionalTreturnc                 c   sD    | st d tj}ztjt| tdt_dV  W |t_dS |t_w )a
  Context manager which replaces import statements with lazy imports.

  A ProxyObject is returned for the import statement as dummy module. The
  actual module is not imported until calling `fdl.build()` on Fiddle
  `Buildable` objects.


  Usage:

  ```python
  with fdl.experimental.lazy_imports():
    import foo.bar.baz as model

  config = fdl.Config(model.MyModel, layer_num=3, dtype='float16')

  my_model = fdl.build(config)  # The module is not actually loaded until now.
  ```

  Warning: Please import modules only when using lazy imports, and do not import
   classes or functions directly. Because it would confuse the API what's the
   correct module path to import.

  ```
  # Errors will be raised when importing classes/functions directly.
  with fdl.experimental.lazy_imports():
    from foo.bar.baz.my_module import MyModel  # Wrong usage!

  # Instead, you should import the module directly only.
  with fdl.experimental.lazy_imports():
    from foo.bar.baz import my_module  # Correct usage!

  config = fdl.Config(my_module.MyModel, ...)
  ```

  Be aware that when using lazy imported modules within `fdl.Partial`, lazy
  imported modules are not loaded until calling the object after `fdl.build()`.
  This is differet from `fdl.Config` where the modules are loaded when calling
  `fdl.build()`.

  ```
  with lazy_imports.lazy_imports(kw_only=True):
    from path.to.the.module import module_1
    from path.to.the.module import module_2

  config = fdl.Config(module_1.MyModel)
  my_model = fld.build(config)  # module_1 is loaded here.

  partial = fdl.Partial(module_2.my_function)
  my_fn = fdl.build(partial)  # module_2 not loaded here.
  assert isinstance(my_fn.func, ProxyObject)
  out = my_fn(x=1, ...)  # module_2 is loaded here during call time.
  ```

  NOTE: When using positional arguments for lazy-imported functions/classes,
  be aware that the config will likely be different from normal-imported
  functions/classes. As Fiddle does not have signature information for
  lazy-imported modules, values for positional arguments, like value 'v' in the
  example below, will be saved as positional-only arguments, and using the index
  0 as the key in `__arguments__`, even if it actually corresponds to a
  positional-or-keyword argument.

  # In foo.py
  def bar(x):
    return x

  # In file_1.py
  with fdl.lazy_import():
    import foo
  cfg_1 = fdl.Config(foo.bar, 'v')
  assert cfg_1.__arguments__ == {0: 'v'}

  # In file_2.py
  import foo
  cfg_2 = fdl.Config(foo.bar, 'v')
  assert cfg_2.__arguments__ == {'x': 'v'}


  Args:
    kw_only: Whether to only allow keyword args usage for lazy imported modules.
      Defaults to True.

  Yields:
    None
  zWhen using positional arguments for lazy-imported functions/classes, be aware that the config will likely be different fromnormal-imported functions/classes.)kw_only	proxy_clsN)loggingwarningbuiltins
__import__	functoolspartial_fake_importProxyObject)r   origin_import r   Y/home/ubuntu/.local/lib/python3.10/site-packages/fiddle/_src/experimental/lazy_imports.pylazy_imports   s   Vr   r   namefromlistlevelc                C   s   ~~|rt d|  d| d^}}|j||d}	d|	_|s-|	}
|D ]} |
| }
q#|	S |D ]} |	| }	q/|D ]} |	|  q9|	S )zMock of `builtins.__import__`.z*Relative import statements not supported (z)..)r   r   T)
ValueErrorsplit
from_cache	is_importchild_import)r   globals_locals_r   r   r   r   	root_namepartsrootchildsr   r   r   r      s    r   F)eqc                   @   s   e Zd ZU dZeed< dZeed< dZe	d  ed< dZ
eed< dZeed< eejd	d
dd ZedefddZdefddZdedefddZdd Zdd Zdedd fddZdd ZdS )r   z.Base class to represent a module, function,...r   Fr   Nparentr   
loaded_obji   )maxsizec                 K   s   | di |S )zFactory to cache all instances of module.

    Note: The cache is global to all instances of the
    `fake_import` contextmanager.

    Args:
      **kwargs: Init kwargs

    Returns:
      New object
    Nr   r   )clskwargsr   r   r   r      s   zProxyObject.from_cacher   c                 C   s:   | j s| jS | j jr| jsd}nd}| j j | | j S )N:r   )r$   r   r   qualname)self	separatorr   r   r   r*      s   zProxyObject.qualnamec                 C   s   t | j d| jdS )N())type__name__r*   r+   r   r   r   __repr__   s   zProxyObject.__repr__c                 C   s   |dkr$t dt jj}t dt jj}| jrt |gS t ||gS |dkr+| jS |dkr5d| j S t| j|| j| dd}|S )	N__signature__argsr(   __qualname__r0   ProxyObject_F)r   r   r$   r   )	inspect	ParameterVAR_POSITIONALVAR_KEYWORDr   	Signaturer*   r/   r   )r+   r   r4   r(   retr   r   r   __getattr__   s,   zProxyObject.__getattr__c                 C   s   t | j| j| jfS )N)hashr*   r$   r   r1   r   r   r   __hash__   s   zProxyObject.__hash__c                 C   s&   t |tsdS | j|jko| j|jkS )NF)
isinstancer   r*   r$   )r+   otherr   r   r   __eq__   s   
zProxyObject.__eq__c                 C   s   t | |}d|_|S )zReturns the child import.T)getattrr   )r+   r   objr   r   r   r      s   
zProxyObject.child_importc                 O   s@   | j d u rt| j| _ | jr|rtd| dS | j |i |S )NzXThis lazily imported function/class is keyword arguments only.Got positional arguments: z. )r%   import_moduler*   r   r   )r+   r4   r(   r   r   r   __call__  s   

zProxyObject.__call__)r0   
__module__r5   __doc__str__annotations__r   boolr$   r   r   r%   r   classmethodr   	lru_cacher   propertyr*   r2   r=   r?   rB   r   rF   r   r   r   r   r      s$   
 
	r   qualname_strc                 C   s|   |  d}t|dkr|\}}nt|dkr#|\} | jddd\}}ntd| t|}| dD ]}t||}q4|S )z4Import module/function/class from a module qualname.r)         r   )maxsplitzInvalid )r   lenrsplitr   	importlibrE   rC   )rO   r    
import_str
attributesrD   attrr   r   r   rE     s   


rE   )T)NNr   r   )rH   r
   
contextlibdataclassesr   rU   r7   r   typingr   r   r   contextmanagerr   rI   intr   	dataclassr   rE   r   r   r   r   <module>   s2   j

)_