
    :Qg                       d Z ddlm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 ddlmZmZmZmZmZmZmZmZ ddlmZmZmZmZ ddlmZ ddlmZmZ d	Zdd
Z ddZ!ddZ"ddZ#ddZ$ddZ%	 d 	 	 	 	 	 	 	 	 	 d!dZ&	 d"	 	 	 	 	 	 	 	 	 	 	 d#dZ'	 d 	 	 	 	 	 	 	 	 	 d$dZ(	 d 	 	 	 	 	 	 	 	 	 d%dZ)	 	 d&	 	 	 	 	 	 	 	 	 	 	 d'dZ*d"d(dZ+	 d 	 	 	 	 	 	 	 	 	 	 	 d)dZ,	 d 	 	 	 	 	 	 	 	 	 	 	 d*dZ-d+dZ.d,dZ/d-dZ0y).z!Utilities that ease unit-testing.    )annotationsN)AnyListOptional)ANY	MagicMockMockPropertyMockcallcreate_autospec	mock_openpatch)CaptureFixtureFixtureRequestLogCaptureFixtureMonkeyPatch)Element)elements_from_jsonelements_to_json)r   r   r   r   r   r	   r   r   
class_mockfunction_mockinitializer_mockinstance_mockmethod_mockproperty_mockc                    t        |       }|J t        |      }t        |      }|J ||k(  sJ t        d||             y)ab  Raises AssertionError if `elements -> JSON -> List[Element] -> JSON` are not equal.

    The procedure is:

        1. Serialize `elements` to (original) JSON.
        2. Deserialize that JSON to `List[Element]`.
        3. Serialize that `List[Element]` to JSON.
        3. Compare the original and round-tripped JSON, raise if they are different.

    N)textzJSON differs:)r   r   _diff)elementsoriginal_jsonround_tripped_elementsround_tripped_jsons       Y/var/www/html/answerous/venv/lib/python3.12/site-packages/test_unstructured/unit_utils.pyassert_round_trips_through_JSONr$   ,   sa     %X.M$$$/]C)*@A))). +]1 .    c                N    t        |       D ]  \  }}|j                  |        | S )z5Updates the `id` attribute of each element to a hash.)	enumerate
id_to_hash)r   idxelements      r#   assign_hash_idsr+   D   s-    !(+  W3 Or%   c                    |j                  d      }|j                  d      }d} | dj                  t        j                         j	                  ||            z   S )z~Diff of actual compared to expected.

    "+" indicates unexpected lines actual, "-" indicates lines missing from actual.
    T)keependszFdiff: '+': unexpected lines in actual, '-': lines missing from actual
 )
splitlinesjoindifflibDiffercompare)headingactualexpectedexpected_linesactual_liness        r#   r   r   K   sW    
 (($(7N$$d$3LWGRWWW^^-55lNSTTTr%   c                    t        j                  t              j                  j                  dz  }|| z  }t	        |j                               S )zGResolve the absolute-path to `file_name` in the example-docs directory.zexample-docs)pathlibPath__file__parentstrresolve)	file_nameexample_docs_dir	file_paths      r#   example_doc_pathrC   V   s@    ||H-44;;nL 9,Iy  "##r%   c                v    t        t        |             5 }|j                         cddd       S # 1 sw Y   yxY w)z?Contents of example-doc `file_name` as text (decoded as utf-8).N)openrC   read)r@   fs     r#   example_doc_textrH   ]   s0    	y)	* avvx  s   /8c                H    | rt         j                  j                  |       S dS )zWParse `datetime_str` to a datetime.datetime instance or None if `datetime_str` is None.N)dtdatetimefromisoformat)datetime_strs    r#   parse_optional_datetimerN   c   s    6B2;;$$\2LLr%   c                t    t        |fd|i|}| j                  |j                         |j                         S )a$  Return mock patching class with qualified name `q_class_name`.

    The mock is autospec'ed based on the patched class unless the optional argument `autospec` is
    set to False. Any other keyword arguments are passed through to Mock(). Patch is reversed after
    calling test returns.
    autospecr   addfinalizerstopstart)requestq_class_namerP   kwargs_patchs        r#   r   r   p   s6     <=(=f=F%<<>r%   c                    || j                   n|}t        j                  ||fd|i|}| j                  |j                         |j                         S )zcReturn a mock for attribute `attr_name` on `cls`.

    Patch is reversed after pytest uses it.
    name)fixturenamer   objectrR   rS   rT   )rU   cls	attr_namerZ   rW   rX   s         r#   cls_attr_mockr_   ~   sM     #',7DD\\#y>t>v>F%<<>r%   c                t    t        |fd|i|}| j                  |j                         |j                         S )z|Return mock patching function with qualified name `q_function_name`.

    Patch is reversed after calling test returns.
    rP   rQ   )rU   q_function_namerP   rW   rX   s        r#   r   r      s6     ?@X@@F%<<>r%   c                    t        j                  |df|dd|}| j                  |j                         |j	                         S )zaReturn mock for __init__() method on `cls`.

    The patch is reversed after pytest uses it.
    __init__N)rP   return_valuer   r\   rR   rS   rT   )rU   r]   rP   rW   rX   s        r#   r   r      s?     \\#zZH4ZSYZF%<<>r%   c                B    ||n| j                   }t        |f||dd|S )ab  Return a mock for an instance of `cls` that draws its spec from the class.

    The mock does not allow new attributes to be set on the instance. If `name` is missing or
    |None|, the name of the returned |Mock| instance is set to *request.fixturename*. Additional
    keyword arguments are passed through to the Mock() call that creates the mock.
    T)_namespec_setinstance)r[   r   )rU   r]   rZ   rh   rW   s        r#   r   r      s0     #4)<)<D3WdXWPVWWr%   c                8    || j                   }t        dd|i|S )zReturn a "loose" mock, meaning it has no spec to constrain calls on it.

    Additional keyword arguments are passed through to Mock(). If called without a name, it is
    assigned the name of the fixture.
    rZ    )r[   r	   )rU   rZ   rW   s      r#   
loose_mockrl      s'     |""$T$V$$r%   c                    t        j                  ||fd|i|}| j                  |j                         |j	                         S )zdReturn mock for method `method_name` on `cls`.

    The patch is reversed after pytest uses it.
    rP   re   )rU   r]   method_namerP   rW   rX   s         r#   r   r      s<     \\#{HXHHF%<<>r%   c                    t        j                  ||fd|i|}| j                  |j                         |j	                         S )zfReturn mock for function `fn_name` on `std_mod`.

    The patch is reversed after pytest uses it.
    rP   re   )rU   std_modfn_namerP   rW   rX   s         r#   stdlib_fn_mockrr      s<     \\'7HXHHF%<<>r%   c                    d|z  }t        |t               fddi|}| j                  |j                         |j	                         S )z?Return a mock for the builtin `open()` method in `module_name`.z%s.opencreateT)r   r   rR   rS   rT   )rU   module_namerW   targetrX   s        r#   	open_mockrw      sB    $F69;>t>v>F%<<>r%   c                    t        j                  ||fdt        i|}| j                  |j                         |j                         S )zgA mock for property `prop_name` on class `cls`.

    Patch is reversed at the end of the test run.
    new_callable)r   r\   r
   rR   rS   rT   )rU   r]   	prop_namerW   rX   s        r#   r   r      s<    
 \\#yN|NvNF%<<>r%   c                p    t        |fi |}| j                  |j                         |j                         S )z}Return a mock patching the variable with qualified name `q_var_name`.

    Patch is reversed after calling test returns.
    rQ   )rU   
q_var_namerW   rX   s       r#   var_mockr}      s1    
 :((F%<<>r%   )r   zList[Element]returnNone)r   list[Element]r~   r   )r4   r>   r5   r>   r6   r>   )r@   r>   r~   r>   )rM   zOptional[str]r~   zOptional[dt.datetime])T)
rU   r   rV   r>   rP   boolrW   r   r~   r	   )N)rU   r   r]   typer^   r>   rZ   
str | NonerW   r   r~   r	   )
rU   r   ra   r>   rP   r   rW   r   r~   r	   )
rU   r   r]   r   rP   r   rW   r   r~   r	   )NT)rU   r   r]   r   rZ   r   rh   r   rW   r   r~   r	   )rU   r   rZ   r   rW   r   r~   r	   )rU   r   r]   r   rn   r>   rP   r   rW   r   r~   r	   )rU   r   rp   ztypes.ModuleTyperq   r>   rP   r   rW   r   r~   r	   )rU   r   ru   r>   rW   r   r~   r	   )
rU   r   r]   r   rz   r>   rW   r   r~   r	   )rU   r   r|   r>   rW   r   r~   r	   )1__doc__
__future__r   rK   rJ   r1   r:   typestypingr   r   r   unittest.mockr   r   r	   r
   r   r   r   r   pytestr   r   r   r   unstructured.documents.elementsr   unstructured.staging.baser   r   __all__r$   r+   r   rC   rH   rN   r   r_   r   r   r   rl   r   rr   rw   r   r}   rk   r%   r#   <module>r      s"   ' "     & &	 	 	 R Q 3 J$0U$M BF+.:>QT	$ 		  	
  
$ EI		.1	=A	TW			 :>		"&	26	IL			 	XX	X X 	X
 X 
X"% 		  	
  
( 	  	
  
 r%   