
    BVh2                         d Z ddlmZ ddlZddlZddlmZ ddlmZ ddlm	Z	 ddlm
Z
 d Zd Z	 	 	 	 dd	Zd
 Zd Zd Zd Z G d de      Zy)a  Utility functions for comparing proto2 messages in Python.

ProtoEq() compares two proto2 messages for equality.

ClearDefaultValuedFields() recursively clears the fields that are set to their
default values. This is useful for comparing protocol buffers where the
semantics of unset fields and default valued fields are the same.

assertProtoEqual() is useful for unit tests.  It produces much more helpful
output than assertEqual() for proto2 messages, e.g. this:

  outer {
    inner {
-     strings: "x"
?               ^
+     strings: "y"
?               ^
    }
  }

...compared to the default output from assertEqual() that looks like this:

AssertionError: <my.Msg object at 0x9fb353c> != <my.Msg object at 0x9fb35cc>

Call it inside your unit test's googletest.TestCase subclasses like this:

  from tensorflow.python.util.protobuf import compare

  class MyTest(googletest.TestCase):
    ...
    def testXXX(self):
      ...
      compare.assertProtoEqual(self, a, b)

Alternatively:

  from tensorflow.python.util.protobuf import compare

  class MyTest(compare.ProtoAssertions, googletest.TestCase):
    ...
    def testXXX(self):
      ...
      self.assertProtoEqual(a, b)
    N)
descriptordescriptor_pool)message)text_formatc                 j   t        j                  |       st        j                  |      r+t        j                  |       t        j                  |      k(  S t        j                  |       st        j                  |      r| |k(  S t        | |z
        |t	        t        |       t        |            z  k  S )a'  Returns True if x is close to y given the relative tolerance or if x and y are both inf, both -inf, or both NaNs.

  This function does not distinguish between signalling and non-signalling NaN.

  Args:
    x: float value to be compared
    y: float value to be compared
    relative_tolerance: float. The allowable difference between the two values
      being compared is determined by multiplying the relative tolerance by the
      maximum of the two values. If this is not provided, then all floats are
      compared using string comparison.
  )mathisnanisinfabsmax)xyrelative_tolerances      W/home/dcms/DCMS/lib/python3.12/site-packages/tensorflow/python/util/protobuf/compare.pyisCloser   H   sz     
ZZ]djjm::a=DJJqM))	ZZ]djjm6M	QU)CAA,??	??    c                    t        |j                         |j                               D ]]  \  }}d}|\  }}|d   }	|j                  t        j                  j
                  k7  rd}|g}|	g}	|j                  t        j                  j                  k(  s'|j                  t        j                  j                  k(  rgt        t        ||	            D ]O  \  }
\  }}t        |||      s|r|t        ||d   j                        |
<   6t        ||d   j                  |       Q |j                  t        j                  j                  k(  s)|j                  t        j                  j                  k(  sG|j                  t        j                  j                  k(  r|j                   j"                  r|j                   j%                         j&                  r|j                   j(                  d   j                  t        j                  j                  k(  st        t+        |j-                               t+        |	j-                                     D ]  \  }}t/        | |||        ;t        ||	      D ]  \  }}t/        | |||        ` y)a  Recursively replaces the floats in actual with those in expected iff they are approximately equal.

  This is done because string equality will consider values such as 5.0999999999
  and 5.1 as not being equal, despite being extremely close.

  Args:
    self: googletest.TestCase
    expected: expected values
    actual: actual values
    relative_tolerance: float, relative tolerance.
  T   Fr      expectedactualr   N)zip
ListFieldslabelr   FieldDescriptorLABEL_REPEATEDtype
TYPE_FLOATTYPE_DOUBLE	enumerater   getattrnamesetattrTYPE_MESSAGE
TYPE_GROUPmessage_typehas_options
GetOptions	map_entryfields_by_numberitervaluescheckFloatEqAndReplace)selfr   r   r   expected_fieldsactual_fieldsis_repeatedexpected_descexpected_valuesactual_valuesir   r   e_va_vvas                    r   r/   r/   _   sD    ),V..0) 5$o} K%4"M?!!$Mj88GGGk()o$om 	j88CCC!;!;!G!GG _m!DE 6)!Va 1a+,89GFM!,11215FM!,11156 	j88EEE!;!;!F!FF 


 : : G G
G((44((335?? &&77:??))667 ?))+,d=3G3G3I.J hc3 ##5	 7 	DAq
 Qq=O	c5r   c                    t        j                         }t        |t              r&t	        j
                  ||j                         |      }||fD ];  }|r)|j                         }	|	r| j                  d|	d|       |s1t        |       = |t        | |||       t	        j                  ||      }
t	        j                  ||      }t        |
      dk  r#t        |      dk  r| j                  |
||       ydj                  t        j                   |
j#                  d	      |j#                  d	                  }|r| j                  |d
|       yy)aN  Fails with a useful error if a and b aren't equal.

  Comparison of repeated fields matches the semantics of
  unittest.TestCase.assertEqual(), ie order and extra duplicates fields matter.

  Args:
    self: googletest.TestCase
    a: proto2 PB instance, or text string representing one.
    b: proto2 PB instance -- message.Message or subclass thereof.
    check_initialized: boolean, whether to fail if either a or b isn't
      initialized.
    normalize_numbers: boolean, whether to normalize types and precision of
      numbers before comparison.
    msg: if specified, is used as the error message on failure.
    relative_tolerance: float, relative tolerance. If this is not provided, then
      all floats are compared using string comparison otherwise, floating point
      comparisons are done using the relative tolerance provided.
  r   zInitialization errors: 
Nr   i   )msg Tz :
)r   Default
isinstancestrr   Parse	__class__FindInitializationErrorsfailNormalizeNumberFieldsr/   MessageToStringlenassertMultiLineEqualjoindifflibunified_diff
splitlines)r0   r;   bcheck_initializednormalize_numbersr>   r   poolpberrorsa_strb_strdiffs                r   assertProtoEqualrX      s5   6 
	 	 	"$3!Q[[]DAAqD  b**,f			VR@AB  #q7I 
%
%a
>%

%
%a
>% 	Z%CJ.eU477U--d3U5E5Ed5KLND
iic4() r   c           	         | j                         D ]K  \  }}d}|j                  t        j                  j                  k7  rd}|g}d}|j
                  t        j                  j                  t        j                  j                  t        j                  j                  fv r|D cg c]  }t        |       }}n|j
                  t        j                  j                  t        j                  j                  t        j                  j                  t        j                  j                  fv r|D cg c]  }t        |       }}n|j
                  t        j                  j                  k(  r|D cg c]  }t        |d       }}nI|j
                  t        j                  j                   k(  r"|D cg c]  }t        t#        |      d       }}|]|rA| j%                  |j&                         t)        | |j&                        j+                  |       nt-        | |j&                  |d          |j
                  t        j                  j.                  k(  s)|j
                  t        j                  j0                  k(  sn|j
                  t        j                  j.                  k(  r|j2                  j4                  r|j2                  j7                         j8                  rk|j2                  j:                  d   j
                  t        j                  j.                  k(  st=        |j?                               D ]  }tA        |        :|D ]  }tA        |        N | S c c}w c c}w c c}w c c}w )a  Normalizes types and precisions of number fields in a protocol buffer.

  Due to subtleties in the python protocol buffer implementation, it is possible
  for values to have different types and precision depending on whether they
  were set and retrieved directly or deserialized from a protobuf. This function
  normalizes integer values to ints and longs based on width, 32-bit floats to
  five digits of precision to account for python always storing them as 64-bit,
  and ensures doubles are floating point for when they're set to integers.

  Modifies pb in place. Recurses into nested objects.

  Args:
    pb: proto2 message.

  Returns:
    the given pb, modified in place.
  TFN      r   r   )!r   r   r   r   r   r   
TYPE_INT64TYPE_UINT64TYPE_SINT64int
TYPE_INT32TYPE_UINT32TYPE_SINT32	TYPE_ENUMr    roundr!   float
ClearFieldr$   r#   extendr%   r&   r'   r(   r)   r*   r+   r,   r-   r.   rG   )rS   descr.   r3   normalized_valuesr   r:   s          r   rG   rG      s   $ mmo -#ldFKzzZ//>>>kxf
 yyZ//:://;;//;;= = ,22a3q622	z11<<!11==!11==!11;;= 
= ,22a3q622	j00;;	;06715A;77	j00<<	<7=>!5q1->>$	
dii DII%%&78DII034		Z//<<<		Z//:::
))z11>>
>



'
'



&
&
(
2
2..q166&&334( %a!!$%  	#A

"	#W-#^ 
)C 3
 37>s   %M"1M'1M,2M1c                 6    t        | t        j                        S N)rA   collections_abcMappingvalues    r   _IsMaprp   $  s    	E?22	33r   c                 \    t        | t              ry	 t        |        y# t        $ r Y yw xY w)NFT)rA   rB   r-   	TypeErrorrn   s    r   _IsRepeatedContainerrs   (  s0    sK	 s    	++c                 2   d } ||        ||      }} t        | t              rt        |t              s| |k(  S t        t        | j	                               t        |j	                               z        D ]   }|| vs||vr yt        | |   ||         r  y y)a8  Compares two proto2 objects for equality.

  Recurses into nested messages. Uses list (not set) semantics for comparing
  repeated fields, ie duplicates and order matter.

  Args:
    a: A proto2 message or a primitive.
    b: A proto2 message or a primitive.

  Returns:
    `True` if the messages are equal.
  c                    t        | t        j                        r t        d | j	                         D              S t        |       rt        | j                               S t        |       rt        t        t        |                   S | S )aV  Returns a dictionary or unchanged pb bases on its type.

    Specifically, this function returns a dictionary that maps tag
    number (for messages) or element index (for repeated fields) to
    value, or just pb unchanged if it's neither.

    Args:
      pb: A proto2 message or a primitive.
    Returns:
      A dict or unchanged pb.
    c              3   >   K   | ]  \  }}|j                   |f  y wrk   )number).0rh   ro   s      r   	<genexpr>z*ProtoEq.<locals>.Format.<locals>.<genexpr>L  s     J;44;;&Js   )
rA   r   Messagedictr   rp   itemsrs   r"   list)rS   s    r   FormatzProtoEq.<locals>.Format?  sb     "goo&J"--/JJJ	"((*	b	!)DH%&&ir   FT)rA   r{   sortedsetkeysProtoEq)r;   rO   r~   tags       r   r   r   2  s    * 
F1IQ! 
At	Jq$$76M
 CMCM12 c
!|s!| QsVQsV$ 
r   c                       e Zd ZdZd Zy)ProtoAssertionsa   Mix this into a googletest.TestCase class to get proto2 assertions.

  Usage:

  class SomeTestCase(compare.ProtoAssertions, googletest.TestCase):
    ...
    def testSomething(self):
      ...
      self.assertProtoEqual(a, b)

  See module-level definitions for method documentation.
  c                      t        | g|i |S rk   )rX   )r0   argskwargss      r   rX   z ProtoAssertions.assertProtoEqualx  s    D242622r   N)__name__
__module____qualname____doc__rX    r   r   r   r   i  s    3r   r   )TFNN)r   collections.abcabcrl   rL   r	   google.protobufr   r   r   r   r   r/   rX   rG   rp   rs   r   objectr   r   r   r   <module>r      sf    +Z *   & + # '@.BR 9*xAH44n3f 3r   