Update Cython gRPC code
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx
index 8edee09..be89db8 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx
@@ -32,6 +32,32 @@
 from grpc._cython._cygrpc cimport server
 
 
+class ConnectivityState:
+  idle = grpc.GRPC_CHANNEL_IDLE
+  connecting = grpc.GRPC_CHANNEL_CONNECTING
+  ready = grpc.GRPC_CHANNEL_READY
+  transient_failure = grpc.GRPC_CHANNEL_TRANSIENT_FAILURE
+  fatal_failure = grpc.GRPC_CHANNEL_FATAL_FAILURE
+
+
+class ChannelArgKey:
+  enable_census = grpc.GRPC_ARG_ENABLE_CENSUS
+  max_concurrent_streams = grpc.GRPC_ARG_MAX_CONCURRENT_STREAMS
+  max_message_length = grpc.GRPC_ARG_MAX_MESSAGE_LENGTH
+  http2_initial_sequence_number = grpc.GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER
+  http2_hpack_table_size_decoder = grpc.GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER
+  http2_hpack_table_size_encoder = grpc.GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER
+  default_authority = grpc.GRPC_ARG_DEFAULT_AUTHORITY
+  primary_user_agent_string = grpc.GRPC_ARG_PRIMARY_USER_AGENT_STRING
+  secondary_user_agent_string = grpc.GRPC_ARG_SECONDARY_USER_AGENT_STRING
+  ssl_target_name_override = grpc.GRPC_SSL_TARGET_NAME_OVERRIDE_ARG
+
+
+class WriteFlag:
+  buffer_hint = grpc.GRPC_WRITE_BUFFER_HINT
+  no_compress = grpc.GRPC_WRITE_NO_COMPRESS
+
+
 class StatusCode:
   ok = grpc.GRPC_STATUS_OK
   cancelled = grpc.GRPC_STATUS_CANCELLED
@@ -88,7 +114,10 @@
   def __cinit__(self, time):
     if time is None:
       self.c_time = grpc.gpr_now(grpc.GPR_CLOCK_REALTIME)
-    elif isinstance(time, float):
+      return
+    if isinstance(time, int):
+      time = float(time)
+    if isinstance(time, float):
       if time == float("+inf"):
         self.c_time = grpc.gpr_inf_future(grpc.GPR_CLOCK_REALTIME)
       elif time == float("-inf"):
@@ -97,8 +126,11 @@
         self.c_time.seconds = time
         self.c_time.nanoseconds = (time - float(self.c_time.seconds)) * 1e9
         self.c_time.clock_type = grpc.GPR_CLOCK_REALTIME
+    elif isinstance(time, Timespec):
+      self.c_time = (<Timespec>time).c_time
     else:
-      raise TypeError("expected time to be float")
+      raise TypeError("expected time to be float, int, or Timespec, not {}"
+                          .format(type(time)))
 
   @property
   def seconds(self):
@@ -166,6 +198,7 @@
                 object tag, call.Call operation_call,
                 CallDetails request_call_details,
                 Metadata request_metadata,
+                bint is_new_request,
                 Operations batch_operations):
     self.type = type
     self.success = success
@@ -174,6 +207,7 @@
     self.request_call_details = request_call_details
     self.request_metadata = request_metadata
     self.batch_operations = batch_operations
+    self.is_new_request = is_new_request
 
 
 cdef class ByteBuffer:
@@ -186,8 +220,14 @@
       pass
     elif isinstance(data, basestring):
       data = data.encode()
+    elif isinstance(data, ByteBuffer):
+      data = (<ByteBuffer>data).bytes()
+      if data is None:
+        self.c_byte_buffer = NULL
+        return
     else:
-      raise TypeError("expected value to be of type str or bytes")
+      raise TypeError("expected value to be of type str, bytes, or "
+                      "ByteBuffer, not {}".format(type(data)))
 
     cdef char *c_data = data
     data_slice = grpc.gpr_slice_from_copied_buffer(c_data, len(data))
@@ -410,12 +450,22 @@
     return self.c_op.type
 
   @property
+  def has_status(self):
+    return self.c_op.type == grpc.GRPC_OP_RECV_STATUS_ON_CLIENT
+
+  @property
   def received_message(self):
     if self.c_op.type != grpc.GRPC_OP_RECV_MESSAGE:
       raise TypeError("self must be an operation receiving a message")
     return self._received_message
 
   @property
+  def received_message_or_none(self):
+    if self.c_op.type != grpc.GRPC_OP_RECV_MESSAGE:
+      return None
+    return self._received_message
+
+  @property
   def received_metadata(self):
     if (self.c_op.type != grpc.GRPC_OP_RECV_INITIAL_METADATA and
         self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT):
@@ -423,12 +473,25 @@
     return self._received_metadata
 
   @property
+  def received_metadata_or_none(self):
+    if (self.c_op.type != grpc.GRPC_OP_RECV_INITIAL_METADATA and
+        self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT):
+      return None
+    return self._received_metadata
+
+  @property
   def received_status_code(self):
     if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
       raise TypeError("self must be an operation receiving a status code")
     return self._received_status_code
 
   @property
+  def received_status_code_or_none(self):
+    if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
+      return None
+    return self._received_status_code
+
+  @property
   def received_status_details(self):
     if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
       raise TypeError("self must be an operation receiving status details")
@@ -438,12 +501,27 @@
       return None
 
   @property
+  def received_status_details_or_none(self):
+    if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
+      return None
+    if self._received_status_details:
+      return self._received_status_details
+    else:
+      return None
+
+  @property
   def received_cancelled(self):
     if self.c_op.type != grpc.GRPC_OP_RECV_CLOSE_ON_SERVER:
       raise TypeError("self must be an operation receiving cancellation "
                       "information")
     return False if self._received_cancelled == 0 else True
 
+  @property
+  def received_cancelled_or_none(self):
+    if self.c_op.type != grpc.GRPC_OP_RECV_CLOSE_ON_SERVER:
+      return None
+    return False if self._received_cancelled == 0 else True
+
   def __dealloc__(self):
     # We *almost* don't need to do anything; most of the objects are handled by
     # Python. The remaining one(s) are primitive fields filled in by GRPC core.