B
    )`#                 @   s   d Z ddlmZ ddlm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
dlmZ dddZdd Zdd Zdd Zdd ZG dd deZdS )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)
    )absolute_import)division)print_functionN)
descriptor)descriptor_pool)message)text_format   )collections_abcTFc          	   C   s   t  }t|tjr(tj|| |d}x>||fD ]2}|rX| }|rX| 	d||f  |r2t
| q2W tj||d}	tj||d}
t|	dk rt|
dk r| j|	|
|d n4ddt|	d|
d }| 	d||f  d	S )
ak  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.
  )r   zInitialization errors: %s
%si   )msg
 Tz%s : %sN)r   ZDefault
isinstancesixstring_typesr   ZMerge	__class__ZFindInitializationErrorsZfailNormalizeNumberFieldsZMessageToStringlenZassertMultiLineEqualjoindifflibZunified_diff
splitlines)selfabZcheck_initializedZnormalize_numbersr   poolpberrorsZa_strZb_strZdiff r   V/home/dcms/DCMS/lib/python3.7/site-packages/tensorflow/python/util/protobuf/compare.pyassertProtoEqualM   s"    r   c             C   s  x|   D ]\}}d}|jtjjk	r2d}|g}d}|jtjjtjjtjjfkrbdd |D }nl|jtjj	tjj
tjjtjjfkrdd |D }n:|jtjjkrdd |D }n|jtjjkrdd |D }|dk	r|r| |j t| |j| nt| |j|d	  |jtjjks,|jtjjkr|jtjjkr|jjr|j jr|jjd
 jtjjkrx6t|D ]}t| qxW qx|D ]}t| qW qW | S )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.
  TFNc             S   s   g | ]}t |qS r   )int).0xr   r   r   
<listcomp>   s    z)NormalizeNumberFields.<locals>.<listcomp>c             S   s   g | ]}t |qS r   )r    )r!   r"   r   r   r   r#      s    c             S   s   g | ]}t |d qS )   )round)r!   r"   r   r   r   r#      s    c             S   s   g | ]}t t|d qS )   )r%   float)r!   r"   r   r   r   r#      s    r   r	   )
ListFieldslabelr   ZFieldDescriptorZLABEL_REPEATEDtypeZ
TYPE_INT64ZTYPE_UINT64ZTYPE_SINT64Z
TYPE_INT32ZTYPE_UINT32ZTYPE_SINT32Z	TYPE_ENUMZ
TYPE_FLOATZTYPE_DOUBLEZ
ClearFieldnamegetattrextendsetattrZTYPE_MESSAGEZ
TYPE_GROUPZmessage_typeZhas_optionsZ
GetOptionsZ	map_entryZfields_by_numberr   
itervaluesr   )r   descvaluesZis_repeatedZnormalized_valuesvr   r   r   r   y   sH    




r   c             C   s   t | tjS )N)r   r
   Mapping)valuer   r   r   _IsMap   s    r5   c             C   s6   t | tjrdS yt|  dS  tk
r0   dS X d S )NFT)r   r   r   iter	TypeError)r4   r   r   r   _IsRepeatedContainer   s    r8   c             C   s   dd }|| || } }t | tr.t |ts6| |kS xNtt|  t| B D ].}|| ksh||krldS t| | || sTdS qTW dS )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             S   sV   t | tjr"tdd |  D S t| r6t|  S t| rNttt	| S | S d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             s   s   | ]\}}|j |fV  qd S )N)number)r!   r0   r4   r   r   r   	<genexpr>   s    z*ProtoEq.<locals>.Format.<locals>.<genexpr>N)
r   r   Messagedictr(   r5   itemsr8   	enumeratelist)r   r   r   r   Format   s    zProtoEq.<locals>.FormatFT)r   r<   sortedsetkeysProtoEq)r   r   r@   tagr   r   r   rD      s    "rD   c               @   s   e Zd ZdZdd ZdS )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             O   s   t | f||S )N)r   )r   argskwargsr   r   r   r     s    z ProtoAssertions.assertProtoEqualN)__name__
__module____qualname____doc__r   r   r   r   r   rF     s   rF   )TFN)rL   
__future__r   r   r   r   r   Zgoogle.protobufr   r   r   r   compatr
   r   r   r5   r8   rD   objectrF   r   r   r   r   <module>;   s"    
+D
7