U
    yhZ*                     @   s(  d dl Z d dlmZmZmZmZmZ d dlZd dlm	Z	 e 
eZG dd dZG dd dZG dd	 d	eZG d
d dZe Zdd ZejedddZd&ee dddZdd ZedddZee dddZeedddZeeeef ddd Zejedd!d"Zd#Zedd$d%ZdS )'    N)AnyDictOptionalProtocolTupleparse_namespacec                   @   s   e Zd ZeedddZdS )FakeScriptObjectwrapped_objscript_class_namec                 C   s   || _ || _d S Nr
   )selfr   r    r   T/var/www/html/venv/lib/python3.8/site-packages/torch/_library/fake_class_registry.py__init__   s    zFakeScriptObject.__init__N)__name__
__module____qualname__r   strr   r   r   r   r   r	      s   r	   c                   @   s,   e Zd Zeeeej dddZdd Z	dS )FakeScriptMethodself_fake_objmethod_nameschemac                 C   s   || _ || _|| _d S r   r   )r   r   r   r   r   r   r   r      s    zFakeScriptMethod.__init__c                 O   s"   ddl m} || j| jf||S )Nr   )call_torchbind)Z!torch._higher_order_ops.torchbindr   r   r   )r   argskwargsr   r   r   r   __call__   s    zFakeScriptMethod.__call__N)
r   r   r   r	   r   r   torchZFunctionSchemar   r   r   r   r   r   r      s
   
r   c                   @   s    e Zd ZeejdddZdS )HasStaticMethodFromReal)real_objc                 C   s   d S r   r   )clsr!   r   r   r   	from_real&   s    z!HasStaticMethodFromReal.from_realN)r   r   r   classmethodr   ScriptObjectr#   r   r   r   r   r    %   s   r    c                   @   st   e Zd Zdd ZeedddZeedddZdeddd	d
Z	eedddZ
ddddZeddddZdS )FakeClassRegistryc                 C   s
   i | _ d S r   _registered_classr   r   r   r   r   ,   s    zFakeClassRegistry.__init__full_qualnamereturnc                 C   s
   || j kS r   r'   r   r+   r   r   r   has_impl/   s    zFakeClassRegistry.has_implc                 C   s   |  | | j| S r   )_check_registeredr(   r-   r   r   r   get_impl2   s    
zFakeClassRegistry.get_implNc                 C   s&   |  |rtd|| || j|< d S )NzD%s is already registered. Previous fake class is overrided with  %s.)r.   logwarningr(   )r   r+   
fake_classr   r   r   register6   s    
zFakeClassRegistry.registerc                 C   s(   |  |std| n| j|S d S )NziCannot deregister %s. Please use register_fake_class to register it first. Or do you dereigster it twice?)r.   r1   r2   r(   popr-   r   r   r   
deregister?   s    
zFakeClassRegistry.deregisterr,   c                 C   s   | j   d S r   )r(   clearr)   r   r   r   r8   I   s    zFakeClassRegistry.clearc                 C   s   || j krt| dd S )NzH is not registered. Please use register_fake_class to register it first.)r(   RuntimeErrorr-   r   r   r   r/   L   s    
z#FakeClassRegistry._check_registered)N)r   r   r   r   r   boolr.   r   r0   r4   r6   r8   r/   r   r   r   r   r&   +   s   	
r&   c                 C   sT   t | tstd| D ]8}t |ts,tdt|dkrFt |d tstdqd S )NzExpect flat x to be a tuple.z&Expect flat x to be a tuple of tuples.   r   zXExpect element of flat x to be a tuple of two elements with first element being a string)
isinstancetupler9   lenr   )flat_xtpr   r   r   _check_valid_flat_script_objW   s    

rA   )xr,   c                    s   dd l m  m} | }t| |tj fdd|}t|	|}t
||  }| D ]v}t||d }|rt|std| d| dt||}	d }
t|	tjr|	j}
t||t|||
 qbtd|| qb|S )Nr   c                    s
     | S r   )Zfrom_tensor)t	fake_moder   r   <lambda>n       zto_fake_obj.<locals>.<lambda>zExpect z to be a callable but got .z.fake object of %s doesn't implement method %s.)Ztorch.utils._pytreeutilsZ_pytreeZ__obj_flatten__rA   Ztree_map_onlyr   ZTensor"_find_fake_class_for_script_object__obj_unflatten__r	   _typequalified_nameZ_method_namesgetattrcallabler9   r<   ZScriptMethodr   setattrr   r1   r2   )rE   rB   Zpytreer?   Zfake_flattenedZfake_xZfake_x_wrappednameattrZ	real_attrZmethod_schemar   rD   r   to_fake_obje   s4    


rS   r3   c                    s&   t d fdd}|dkr|S ||S )a
  Register a fake implementation for this class.

    It's in the same spirit of registering a fake implementation for
    an operator but with the difference that it
    associates a fake class with the original torch bind class (registered
    with torch::class_). In this way, torch.compile can handle them properly
    in components such as Dynamo and AOTAutograd.

    This API may be used as a decorator (see example). For the fake class, users
    are required to provide a from_real classmethod that takes a real object and
    returns an instance of the fake class. All tensors in the fake object should also
    be properly fakified with to_fake_tensor() in from_real.


    Examples:
        # For a custom class Foo defined in test_custom_class_registration.cpp:

        TORCH_LIBRARY(_TorchScriptTesting, m) {
          m.class_<TensorQueue>("_TensorQueue")
            .def(torch::init<at::Tensor>())
            .def("push", &TensorQueue::push)
            .def("pop", &TensorQueue::pop)
            .def("top", &TensorQueue::top)
            .def("size", &TensorQueue::size)
            .def("clone_queue", &TensorQueue::clone_queue)
            .def("__obj_flatten__", &TensorQueue::__obj_flatten__)
            .def_pickle(
                // __getstate__
                [](const c10::intrusive_ptr<TensorQueue>& self)
                    -> c10::Dict<std::string, at::Tensor> {
                  return self->serialize();
                },
                // __setstate__
                [](c10::Dict<std::string, at::Tensor> data)
                    -> c10::intrusive_ptr<TensorQueue> {
                  return c10::make_intrusive<TensorQueue>(std::move(data));
                });
            };
        # We could register a fake class FakeTensorQueue in Python as follows:
        import torch

        @torch._library.register_fake_class("_TorchScriptTesting::_TensorQueue")
        class FakeTensorQueue:
            def __init__(self, queue):
                self.queue = queue

            @classmethod
            def __obj_unflatten__(cls, flattened_ctx):
                return cls(**dict(ctx))

            def push(self, x):
                self.queue.append(x)

            def pop(self):
                return self.queue.pop(0)

            def size(self):
                return len(self.queue)

    In this example, the original TensorQeue need to addd a __obj_flatten__ method
    to the class TensorQueue and the flattend result is passed into FakeTensorQueue's
    __obj_unflatten__ as inputs to create a fake class. This protocol allows pytorch to look
    at the contents of the script object and properly handle them in the subsystems
    like dynamo, aot_aotugrad or more.
    rT   c                    sp   t  \}}tj||}t| td }|s>t|  dt dt| jt t	s\tt dt
t |  | S )Nz doesn't define a classmethod rH   z method is not a classmethod.)r   r   Z_CZ _get_custom_class_python_wrapperrN   _CONVERT_FROM_REAL_NAMEr9   r<   __dict__r$   global_fake_class_registryr4   _full_qual_class_name)r3   nsrQ   Ztorchbind_classZfrom_methodqualnamer   r   inner   s    z"register_fake_class.<locals>.innerN)r    )r[   r3   r\   r   rZ   r   register_fake_class   s    Cr]   c                 C   s   t t| S r   )rW   r6   rX   rZ   r   r   r   deregister_fake_class   s    r^   r7   c                 C   s
   t | S r   )rW   r.   r+   r   r   r   has_fake_class   s    r`   c                 C   s   t | sd S t| S r   )r`   rW   r0   r_   r   r   r   find_fake_class   s    ra   )r[   r,   c                 C   s   t | \}}d| d | S )Nz__torch__.torch.classes.rH   r   )r[   rY   rQ   r   r   r   rX      s    rX   r*   c                 C   s0   |  d}t|dkst|\}}}}}||fS )NrH      )splitr>   AssertionError)r+   ZsplitsZ_torchZtorch_nsclassesrY   
class_namer   r   r   _ns_and_class_name   s    
rg   c              
   C   sN   |    }t|\}}t|}|d krJtd| d| d| dt d	|S )Nz ScriptObject's zA haven't registered a fake class. Please use register_fake_class(z::a  ) to annotate a fake class for the script obj. Specifically, create a python class that implements a fake version for all the methods that're used in the program and put annotated class in the program e.g. after loading the library. The fake methods can be written in the same way as a meta kernel for an operator but need to additionally simulate the object's states. Be sure to add a z; classmethod to enable creating a fake obj from a real one.)rL   rM   rg   ra   r9   rU   )rB   r+   rY   rf   r3   r   r   r   rJ     s    	rJ   rK   c              
      st   t |}t|td }|s,t| dt dtjj| d  tjj fdd |	|W  5 Q R  S Q R X d S )Nz must define a classmethod z2 that converts the real object to the fake object.c                      s    S r   r   r   ctxr   r   rF   $  rG   z%_fake_obj_from_real.<locals>.<lambda>)
rJ   rN   rU   r9   r   Z_libraryZabstract_implZAbstractImplCtxZset_ctx_getterr#   )rE   rB   r3   Zfrom_real_methodr   rh   r   _fake_obj_from_real  s    rj   )N) loggingtypingr   r   r   r   r   r   Ztorch._library.utilsr   	getLoggerr   r1   r	   r   r    r&   rW   rA   r%   rS   r]   r^   r:   r`   ra   r   rX   rg   rJ   rU   rj   r   r   r   r   <module>   s(   
((\