Bring Cython tests back online
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx
index 4349786..ed037b6 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx
@@ -29,6 +29,7 @@
 
 cimport cpython
 
+from grpc._cython._cygrpc cimport grpc
 from grpc._cython._cygrpc cimport records
 
 
@@ -49,7 +50,7 @@
     cpython.Py_INCREF(operation_tag)
     return grpc.grpc_call_start_batch(
         self.c_call, cy_operations.c_ops, cy_operations.c_nops,
-        <cpython.PyObject *>operation_tag)
+        <cpython.PyObject *>operation_tag, NULL)
 
   def cancel(self,
              grpc.grpc_status_code error_code=grpc.GRPC_STATUS__DO_NOT_USE,
@@ -67,9 +68,10 @@
       raise TypeError("expected details to be str or bytes")
     if error_code != grpc.GRPC_STATUS__DO_NOT_USE:
       self.references.append(details)
-      return grpc.grpc_call_cancel_with_status(self.c_call, error_code, details)
+      return grpc.grpc_call_cancel_with_status(self.c_call, error_code, details,
+                                               NULL)
     else:
-      return grpc.grpc_call_cancel(self.c_call)
+      return grpc.grpc_call_cancel(self.c_call, NULL)
 
   def __dealloc__(self):
     if self.c_call != NULL:
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
index b203138..b52ddb6 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
@@ -30,6 +30,7 @@
 from grpc._cython._cygrpc cimport call
 from grpc._cython._cygrpc cimport completion_queue
 from grpc._cython._cygrpc cimport credentials
+from grpc._cython._cygrpc cimport grpc
 from grpc._cython._cygrpc cimport records
 
 
@@ -49,15 +50,17 @@
     else:
       raise TypeError("expected target to be str or bytes")
     if client_credentials is None:
-      self.c_channel = grpc.grpc_channel_create(target, c_arguments)
+      self.c_channel = grpc.grpc_insecure_channel_create(target, c_arguments,
+                                                         NULL)
     else:
       self.c_channel = grpc.grpc_secure_channel_create(
-          client_credentials.c_credentials, target, c_arguments)
+          client_credentials.c_credentials, target, c_arguments, NULL)
       self.references.append(client_credentials)
     self.references.append(target)
     self.references.append(arguments)
 
-  def create_call(self, completion_queue.CompletionQueue queue not None,
+  def create_call(self, call.Call parent, int flags,
+                  completion_queue.CompletionQueue queue not None,
                   method, host, records.Timespec deadline not None):
     if queue.is_shutting_down:
       raise ValueError("queue must not be shutting down or shutdown")
@@ -75,8 +78,13 @@
       raise TypeError("expected host to be str or bytes")
     cdef call.Call operation_call = call.Call()
     operation_call.references = [self, method, host, queue]
+    cdef grpc.grpc_call *parent_call = NULL
+    if parent is not None:
+      parent_call = parent.c_call
     operation_call.c_call = grpc.grpc_channel_create_call(
-        self.c_channel, queue.c_completion_queue, method, host, deadline.c_time)
+        self.c_channel, parent_call, flags,
+        queue.c_completion_queue, method, host, deadline.c_time,
+        NULL)
     return operation_call
 
   def __dealloc__(self):
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx
index 886d853..a7a265e 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx
@@ -30,6 +30,7 @@
 cimport cpython
 
 from grpc._cython._cygrpc cimport call
+from grpc._cython._cygrpc cimport grpc
 from grpc._cython._cygrpc cimport records
 
 import threading
@@ -39,7 +40,7 @@
 cdef class CompletionQueue:
 
   def __cinit__(self):
-    self.c_completion_queue = grpc.grpc_completion_queue_create()
+    self.c_completion_queue = grpc.grpc_completion_queue_create(NULL)
     self.is_shutting_down = False
     self.is_shutdown = False
     self.poll_condition = threading.Condition()
@@ -48,7 +49,8 @@
   def poll(self, records.Timespec deadline=None):
     # We name this 'poll' to avoid problems with CPython's expectations for
     # 'special' methods (like next and __next__).
-    cdef grpc.gpr_timespec c_deadline = grpc.gpr_inf_future
+    cdef grpc.gpr_timespec c_deadline = grpc.gpr_inf_future(
+        grpc.GPR_CLOCK_REALTIME)
     cdef records.OperationTag tag = None
     cdef object user_tag = None
     cdef call.Call operation_call = None
@@ -66,7 +68,7 @@
       self.is_polling = True
     with nogil:
       event = grpc.grpc_completion_queue_next(
-          self.c_completion_queue, c_deadline)
+          self.c_completion_queue, c_deadline, NULL)
     with self.poll_condition:
       self.is_polling = False
       self.poll_condition.notify()
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
index dc40a7a..608207f 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
@@ -27,6 +27,7 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+from grpc._cython._cygrpc cimport grpc
 from grpc._cython._cygrpc cimport records
 
 
@@ -81,13 +82,11 @@
     credentials.references.append(pem_root_certificates)
   if ssl_pem_key_cert_pair is not None:
     credentials.c_credentials = grpc.grpc_ssl_credentials_create(
-        c_pem_root_certificates, &ssl_pem_key_cert_pair.c_pair
-    )
+        c_pem_root_certificates, &ssl_pem_key_cert_pair.c_pair, NULL)
     credentials.references.append(ssl_pem_key_cert_pair)
   else:
     credentials.c_credentials = grpc.grpc_ssl_credentials_create(
-      c_pem_root_certificates, NULL
-    )
+      c_pem_root_certificates, NULL, NULL)
 
 def client_credentials_composite_credentials(
     ClientCredentials credentials_1 not None,
@@ -96,18 +95,20 @@
     raise ValueError("passed credentials must both be valid")
   cdef ClientCredentials credentials = ClientCredentials()
   credentials.c_credentials = grpc.grpc_composite_credentials_create(
-      credentials_1.c_credentials, credentials_2.c_credentials)
+      credentials_1.c_credentials, credentials_2.c_credentials, NULL)
   credentials.references.append(credentials_1)
   credentials.references.append(credentials_2)
   return credentials
 
-def client_credentials_compute_engine():
+def client_credentials_google_compute_engine():
   cdef ClientCredentials credentials = ClientCredentials()
-  credentials.c_credentials = grpc.grpc_compute_engine_credentials_create()
+  credentials.c_credentials = (
+      grpc.grpc_google_compute_engine_credentials_create(NULL))
   return credentials
 
 #TODO rename to something like client_credentials_service_account_jwt_access.
-def client_credentials_jwt(json_key, records.Timespec token_lifetime not None):
+def client_credentials_service_account_jwt_access(
+    json_key, records.Timespec token_lifetime not None):
   if isinstance(json_key, bytes):
     pass
   elif isinstance(json_key, basestring):
@@ -115,12 +116,13 @@
   else:
     raise TypeError("expected json_key to be str or bytes")
   cdef ClientCredentials credentials = ClientCredentials()
-  credentials.c_credentials = grpc.grpc_service_account_jwt_access_credentials_create(
-      json_key, token_lifetime.c_time)
+  credentials.c_credentials = (
+      grpc.grpc_service_account_jwt_access_credentials_create(
+          json_key, token_lifetime.c_time, NULL))
   credentials.references.append(json_key)
   return credentials
 
-def client_credentials_refresh_token(json_refresh_token):
+def client_credentials_google_refresh_token(json_refresh_token):
   if isinstance(json_refresh_token, bytes):
     pass
   elif isinstance(json_refresh_token, basestring):
@@ -128,12 +130,12 @@
   else:
     raise TypeError("expected json_refresh_token to be str or bytes")
   cdef ClientCredentials credentials = ClientCredentials()
-  credentials.c_credentials = grpc.grpc_refresh_token_credentials_create(
-      json_refresh_token)
+  credentials.c_credentials = grpc.grpc_google_refresh_token_credentials_create(
+      json_refresh_token, NULL)
   credentials.references.append(json_refresh_token)
   return credentials
 
-def client_credentials_iam(authorization_token, authority_selector):
+def client_credentials_google_iam(authorization_token, authority_selector):
   if isinstance(authorization_token, bytes):
     pass
   elif isinstance(authorization_token, basestring):
@@ -147,13 +149,14 @@
   else:
     raise TypeError("expected authority_selector to be str or bytes")
   cdef ClientCredentials credentials = ClientCredentials()
-  credentials.c_credentials = grpc.grpc_iam_credentials_create(
-      authorization_token, authority_selector)
+  credentials.c_credentials = grpc.grpc_google_iam_credentials_create(
+      authorization_token, authority_selector, NULL)
   credentials.references.append(authorization_token)
   credentials.references.append(authority_selector)
   return credentials
 
-def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs):
+def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs,
+                           bint force_client_auth):
   if pem_root_certs is None:
     pass
   elif isinstance(pem_root_certs, bytes):
@@ -181,7 +184,6 @@
         (<records.SslPemKeyCertPair>pem_key_cert_pairs[i]).c_pair)
   credentials.c_credentials = grpc.grpc_ssl_server_credentials_create(
       pem_root_certs, credentials.c_ssl_pem_key_cert_pairs,
-      credentials.c_ssl_pem_key_cert_pairs_count
-  )
+      credentials.c_ssl_pem_key_cert_pairs_count, force_client_auth, NULL)
   return credentials
 
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
index 8b46972..62d40e7 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
@@ -64,15 +64,25 @@
 
 cdef extern from "grpc/support/time.h":
 
+  ctypedef enum gpr_clock_type:
+    GPR_CLOCK_MONOTONIC
+    GPR_CLOCK_REALTIME
+    GPR_CLOCK_PRECISE
+    GPR_TIMESPAN
+
   ctypedef struct gpr_timespec:
     libc.time.time_t seconds "tv_sec"
     int nanoseconds "tv_nsec"
+    gpr_clock_type clock_type
 
-  cdef gpr_timespec gpr_time_0
-  cdef gpr_timespec gpr_inf_future
-  cdef gpr_timespec gpr_inf_past
+  gpr_timespec gpr_time_0(gpr_clock_type type)
+  gpr_timespec gpr_inf_future(gpr_clock_type type)
+  gpr_timespec gpr_inf_past(gpr_clock_type type)
 
-  gpr_timespec gpr_now()
+  gpr_timespec gpr_now(gpr_clock_type clock)
+
+  gpr_timespec gpr_convert_clock_type(gpr_timespec t,
+                                      gpr_clock_type target_clock)
 
 
 cdef extern from "grpc/status.h":
@@ -255,38 +265,44 @@
   void grpc_init()
   void grpc_shutdown()
 
-  grpc_completion_queue *grpc_completion_queue_create()
+  grpc_completion_queue *grpc_completion_queue_create(void *reserved)
   grpc_event grpc_completion_queue_next(grpc_completion_queue *cq,
-                                        gpr_timespec deadline) nogil
+                                        gpr_timespec deadline,
+                                        void *reserved) nogil
   void grpc_completion_queue_shutdown(grpc_completion_queue *cq)
   void grpc_completion_queue_destroy(grpc_completion_queue *cq)
 
   grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
-                                        size_t nops, void *tag)
-  grpc_call_error grpc_call_cancel(grpc_call *call)
+                                        size_t nops, void *tag, void *reserved)
+  grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved)
   grpc_call_error grpc_call_cancel_with_status(grpc_call *call,
                                                grpc_status_code status,
-                                               const char *description)
+                                               const char *description,
+                                               void *reserved)
   void grpc_call_destroy(grpc_call *call)
 
 
-  grpc_channel *grpc_channel_create(const char *target,
-                                    const grpc_channel_args *args)
+  grpc_channel *grpc_insecure_channel_create(const char *target,
+                                             const grpc_channel_args *args,
+                                             void *reserved)
   grpc_call *grpc_channel_create_call(grpc_channel *channel,
+                                      grpc_call *parent_call,
+                                      gpr_uint32 propagation_mask,
                                       grpc_completion_queue *completion_queue,
                                       const char *method, const char *host,
-                                      gpr_timespec deadline)
+                                      gpr_timespec deadline, void *reserved)
   void grpc_channel_destroy(grpc_channel *channel)
 
-  grpc_server *grpc_server_create(const grpc_channel_args *args)
+  grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved)
   grpc_call_error grpc_server_request_call(
       grpc_server *server, grpc_call **call, grpc_call_details *details,
       grpc_metadata_array *request_metadata, grpc_completion_queue
       *cq_bound_to_call, grpc_completion_queue *cq_for_notification, void
       *tag_new)
   void grpc_server_register_completion_queue(grpc_server *server,
-                                             grpc_completion_queue *cq)
-  int grpc_server_add_http2_port(grpc_server *server, const char *addr)
+                                             grpc_completion_queue *cq,
+                                             void *reserved)
+  int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr)
   void grpc_server_start(grpc_server *server)
   void grpc_server_shutdown_and_notify(
       grpc_server *server, grpc_completion_queue *cq, void *tag)
@@ -306,22 +322,27 @@
 
   grpc_credentials *grpc_google_default_credentials_create()
   grpc_credentials *grpc_ssl_credentials_create(
-      const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair)
+      const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
+      void *reserved)
 
   grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
-                                                      grpc_credentials *creds2)
-  grpc_credentials *grpc_compute_engine_credentials_create()
-  grpc_credentials *grpc_service_account_jwt_access_credentials_create(const char *json_key,
-                                                gpr_timespec token_lifetime)
-  grpc_credentials *grpc_refresh_token_credentials_create(
-      const char *json_refresh_token)
-  grpc_credentials *grpc_iam_credentials_create(const char *authorization_token,
-                                                const char *authority_selector)
+                                                      grpc_credentials *creds2,
+                                                      void *reserved)
+  grpc_credentials *grpc_google_compute_engine_credentials_create(
+      void *reserved)
+  grpc_credentials *grpc_service_account_jwt_access_credentials_create(
+      const char *json_key,
+      gpr_timespec token_lifetime, void *reserved)
+  grpc_credentials *grpc_google_refresh_token_credentials_create(
+      const char *json_refresh_token, void *reserved)
+  grpc_credentials *grpc_google_iam_credentials_create(
+      const char *authorization_token, const char *authority_selector,
+      void *reserved)
   void grpc_credentials_release(grpc_credentials *creds)
 
   grpc_channel *grpc_secure_channel_create(
       grpc_credentials *creds, const char *target,
-      const grpc_channel_args *args)
+      const grpc_channel_args *args, void *reserved)
 
   ctypedef struct grpc_server_credentials:
     # We don't care about the internals (and in fact don't know them)
@@ -330,7 +351,7 @@
   grpc_server_credentials *grpc_ssl_server_credentials_create(
       const char *pem_root_certs,
       grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
-      size_t num_key_cert_pairs)
+      size_t num_key_cert_pairs, int force_client_auth, void *reserved)
   void grpc_server_credentials_release(grpc_server_credentials *creds)
 
   int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx
index 4814769..8edee09 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx
@@ -87,28 +87,38 @@
 
   def __cinit__(self, time):
     if time is None:
-      self.c_time = grpc.gpr_now()
+      self.c_time = grpc.gpr_now(grpc.GPR_CLOCK_REALTIME)
     elif isinstance(time, float):
       if time == float("+inf"):
-        self.c_time = grpc.gpr_inf_future
+        self.c_time = grpc.gpr_inf_future(grpc.GPR_CLOCK_REALTIME)
       elif time == float("-inf"):
-        self.c_time = grpc.gpr_inf_past
+        self.c_time = grpc.gpr_inf_past(grpc.GPR_CLOCK_REALTIME)
       else:
         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
     else:
       raise TypeError("expected time to be float")
 
   @property
   def seconds(self):
-    return self.c_time.seconds
+    # TODO(atash) ensure that everywhere a Timespec is created that it's
+    # converted to GPR_CLOCK_REALTIME then and not every time someone wants to
+    # read values off in Python.
+    cdef grpc.gpr_timespec real_time = (
+        grpc.gpr_convert_clock_type(self.c_time, grpc.GPR_CLOCK_REALTIME))
+    return real_time.seconds
 
   @property
   def nanoseconds(self):
-    return self.c_time.nanoseconds
+    cdef grpc.gpr_timespec real_time = (
+        grpc.gpr_convert_clock_type(self.c_time, grpc.GPR_CLOCK_REALTIME))
+    return real_time.nanoseconds
 
   def __float__(self):
-    return <double>self.c_time.seconds + <double>self.c_time.nanoseconds / 1e9
+    cdef grpc.gpr_timespec real_time = (
+        grpc.gpr_convert_clock_type(self.c_time, grpc.GPR_CLOCK_REALTIME))
+    return <double>real_time.seconds + <double>real_time.nanoseconds / 1e9
 
   infinite_future = Timespec(float("+inf"))
   infinite_past = Timespec(float("-inf"))
@@ -339,13 +349,16 @@
     self.i = 0
     self.metadata = metadata
 
+  def __iter__(self):
+    return self
+
   def __next__(self):
     if self.i < len(self.metadata):
       result = self.metadata[self.i]
       self.i = self.i + 1
       return result
     else:
-      raise StopIteration()
+      raise StopIteration
 
 
 cdef class Metadata:
@@ -536,13 +549,16 @@
     self.i = 0
     self.operations = operations
 
+  def __iter__(self):
+    return self
+
   def __next__(self):
     if self.i < len(self.operations):
       result = self.operations[self.i]
       self.i = self.i + 1
       return result
     else:
-      raise StopIteration()
+      raise StopIteration
 
 
 cdef class Operations:
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx
index dcf9d38..6d20d29 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx
@@ -32,6 +32,7 @@
 from grpc._cython._cygrpc cimport call
 from grpc._cython._cygrpc cimport completion_queue
 from grpc._cython._cygrpc cimport credentials
+from grpc._cython._cygrpc cimport grpc
 from grpc._cython._cygrpc cimport records
 
 import time
@@ -46,7 +47,7 @@
     if arguments is not None:
       c_arguments = &arguments.c_args
       self.references.append(arguments)
-    self.c_server = grpc.grpc_server_create(c_arguments)
+    self.c_server = grpc.grpc_server_create(c_arguments, NULL)
     self.is_started = False
     self.is_shutting_down = False
     self.is_shutdown = False
@@ -78,7 +79,7 @@
     if self.is_started:
       raise ValueError("cannot register completion queues after start")
     grpc.grpc_server_register_completion_queue(
-        self.c_server, queue.c_completion_queue)
+        self.c_server, queue.c_completion_queue, NULL)
     self.registered_completion_queues.append(queue)
 
   def start(self):
@@ -103,7 +104,7 @@
       return grpc.grpc_server_add_secure_http2_port(
           self.c_server, address, server_credentials.c_credentials)
     else:
-      return grpc.grpc_server_add_http2_port(self.c_server, address)
+      return grpc.grpc_server_add_insecure_http2_port(self.c_server, address)
 
   def shutdown(self, completion_queue.CompletionQueue queue not None, tag):
     cdef records.OperationTag operation_tag
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx
index f4d9661..1ef2997 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pyx
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx
@@ -78,11 +78,13 @@
 client_credentials_ssl = credentials.client_credentials_ssl
 client_credentials_composite_credentials = (
     credentials.client_credentials_composite_credentials)
-client_credentials_compute_engine = (
-    credentials.client_credentials_compute_engine)
-client_credentials_jwt = credentials.client_credentials_jwt
-client_credentials_refresh_token = credentials.client_credentials_refresh_token
-client_credentials_iam = credentials.client_credentials_iam
+client_credentials_google_compute_engine = (
+    credentials.client_credentials_google_compute_engine)
+client_credentials_jwt_access = (
+    credentials.client_credentials_service_account_jwt_access)
+client_credentials_refresh_token = (
+    credentials.client_credentials_google_refresh_token)
+client_credentials_google_iam = credentials.client_credentials_google_iam
 server_credentials_ssl = credentials.server_credentials_ssl
 
 CompletionQueue = completion_queue.CompletionQueue
diff --git a/src/python/grpcio/requirements.txt b/src/python/grpcio/requirements.txt
index 77356e0..ee85681 100644
--- a/src/python/grpcio/requirements.txt
+++ b/src/python/grpcio/requirements.txt
@@ -1,2 +1,3 @@
 enum34>=1.0.4
 futures>=2.2.0
+cython>=0.23
diff --git a/src/python/grpcio/setup.py b/src/python/grpcio/setup.py
index 8b87c09..97fa4fe 100644
--- a/src/python/grpcio/setup.py
+++ b/src/python/grpcio/setup.py
@@ -34,6 +34,7 @@
 import sys
 
 from distutils import core as _core
+from distutils import extension as _extension
 import setuptools
 
 # Ensure we're in the proper directory whether or not we're being used by pip.
@@ -59,6 +60,18 @@
     'grpc/_adapter/_c/types/server.c',
 )
 
+_CYTHON_EXTENSION_PACKAGE_NAMES = ()
+
+_CYTHON_EXTENSION_MODULE_NAMES = (
+    'grpc._cython.cygrpc',
+    'grpc._cython._cygrpc.call',
+    'grpc._cython._cygrpc.channel',
+    'grpc._cython._cygrpc.completion_queue',
+    'grpc._cython._cygrpc.credentials',
+    'grpc._cython._cygrpc.records',
+    'grpc._cython._cygrpc.server',
+)
+
 _EXTENSION_INCLUDE_DIRECTORIES = (
     '.',
 )
@@ -78,9 +91,30 @@
 )
 _EXTENSION_MODULES = [_C_EXTENSION_MODULE]
 
-_PACKAGES = (
-    setuptools.find_packages('.', exclude=['*._cython', '*._cython.*'])
-)
+
+def cython_extensions(package_names, module_names, include_dirs, libraries,
+                      build_with_cython=False):
+  file_extension = 'pyx' if build_with_cython else 'c'
+  module_files = [name.replace('.', '/') + '.' + file_extension
+                  for name in module_names]
+  extensions = [
+      _extension.Extension(
+          name=module_name, sources=[module_file],
+          include_dirs=include_dirs, libraries=libraries
+      ) for (module_name, module_file) in zip(module_names, module_files)
+  ]
+  if build_with_cython:
+    import Cython.Build
+    return Cython.Build.cythonize(extensions)
+  else:
+    return extensions
+
+_CYTHON_EXTENSION_MODULES = cython_extensions(
+    list(_CYTHON_EXTENSION_PACKAGE_NAMES), list(_CYTHON_EXTENSION_MODULE_NAMES),
+    list(_EXTENSION_INCLUDE_DIRECTORIES), list(_EXTENSION_LIBRARIES),
+    bool(_BUILD_WITH_CYTHON))
+
+_PACKAGES = setuptools.find_packages('.')
 
 _PACKAGE_DIRECTORIES = {
     '': '.',
@@ -104,7 +138,7 @@
 setuptools.setup(
     name='grpcio',
     version='0.11.0b1',
-    ext_modules=_EXTENSION_MODULES,
+    ext_modules=_EXTENSION_MODULES + _CYTHON_EXTENSION_MODULES,
     packages=list(_PACKAGES),
     package_dir=_PACKAGE_DIRECTORIES,
     install_requires=_INSTALL_REQUIRES,
diff --git a/src/python/grpcio_test/.gitignore b/src/python/grpcio_test/.gitignore
index e3540ba..4bb4d42 100644
--- a/src/python/grpcio_test/.gitignore
+++ b/src/python/grpcio_test/.gitignore
@@ -7,5 +7,5 @@
 *.eggs/
 .coverage
 .coverage.*
-.cache
+.cache/
 nosetests.xml
diff --git a/src/python/grpcio_test/grpc_test/_cython/cygrpc_test.py b/src/python/grpcio_test/grpc_test/_cython/cygrpc_test.py
index 637506b..1307a30 100644
--- a/src/python/grpcio_test/grpc_test/_cython/cygrpc_test.py
+++ b/src/python/grpcio_test/grpc_test/_cython/cygrpc_test.py
@@ -32,6 +32,7 @@
 
 from grpc._cython import cygrpc
 from grpc_test._cython import test_utilities
+from grpc_test import test_common
 
 
 class TypeSmokeTest(unittest.TestCase):
@@ -139,7 +140,7 @@
     CLIENT_METADATA_BIN_VALUE = b'\0'*1000
     SERVER_INITIAL_METADATA_KEY = b'init_me_me_me'
     SERVER_INITIAL_METADATA_VALUE = b'whodawha?'
-    SERVER_TRAILING_METADATA_KEY = b'California_is_in_a_drought'
+    SERVER_TRAILING_METADATA_KEY = b'california_is_in_a_drought'
     SERVER_TRAILING_METADATA_VALUE = b'zomg it is'
     SERVER_STATUS_CODE = cygrpc.StatusCode.ok
     SERVER_STATUS_DETAILS = b'our work is never over'
@@ -158,8 +159,8 @@
     self.assertEqual(cygrpc.CallError.ok, request_call_result)
 
     client_call_tag = object()
-    client_call = self.client_channel.create_call(self.client_completion_queue,
-                                                  METHOD, HOST, cygrpc_deadline)
+    client_call = self.client_channel.create_call(
+        None, 0, self.client_completion_queue, METHOD, HOST, cygrpc_deadline)
     client_initial_metadata = cygrpc.Metadata([
         cygrpc.Metadatum(CLIENT_METADATA_ASCII_KEY,
                          CLIENT_METADATA_ASCII_VALUE),
@@ -182,8 +183,9 @@
     self.assertIsInstance(request_event.operation_call, cygrpc.Call)
     self.assertIs(server_request_tag, request_event.tag)
     self.assertEqual(0, len(request_event.batch_operations))
-    self.assertEqual(dict(client_initial_metadata),
-                      dict(request_event.request_metadata))
+    self.assertTrue(
+        test_common.metadata_transmitted(client_initial_metadata,
+                                         request_event.request_metadata))
     self.assertEqual(METHOD, request_event.request_call_details.method)
     self.assertEqual(HOST, request_event.request_call_details.host)
     self.assertLess(
@@ -218,13 +220,15 @@
       self.assertNotIn(client_result.type, found_client_op_types)
       found_client_op_types.add(client_result.type)
       if client_result.type == cygrpc.OperationType.receive_initial_metadata:
-        self.assertEqual(dict(server_initial_metadata),
-                         dict(client_result.received_metadata))
+        self.assertTrue(
+            test_common.metadata_transmitted(server_initial_metadata,
+                                             client_result.received_metadata))
       elif client_result.type == cygrpc.OperationType.receive_message:
         self.assertEqual(RESPONSE, client_result.received_message.bytes())
       elif client_result.type == cygrpc.OperationType.receive_status_on_client:
-        self.assertEqual(dict(server_trailing_metadata),
-                         dict(client_result.received_metadata))
+        self.assertTrue(
+            test_common.metadata_transmitted(server_trailing_metadata,
+                                             client_result.received_metadata))
         self.assertEqual(SERVER_STATUS_DETAILS,
                          client_result.received_status_details)
         self.assertEqual(SERVER_STATUS_CODE, client_result.received_status_code)
diff --git a/src/python/grpcio_test/grpc_test/test_common.py b/src/python/grpcio_test/grpc_test/test_common.py
index 44284be..29431bf 100644
--- a/src/python/grpcio_test/grpc_test/test_common.py
+++ b/src/python/grpcio_test/grpc_test/test_common.py
@@ -46,19 +46,23 @@
   the same key.
 
   Args:
-    original_metadata: A metadata value used in a test of gRPC.
+    original_metadata: A metadata value used in a test of gRPC. An iterable over
+      iterables of length 2.
     transmitted_metadata: A metadata value corresponding to original_metadata
-      after having been transmitted via gRPC.
+      after having been transmitted via gRPC. An iterable over iterables of
+      length 2.
 
   Returns:
      A boolean indicating whether transmitted_metadata accurately reflects
       original_metadata after having been transmitted via gRPC.
   """
   original = collections.defaultdict(list)
-  for key, value in original_metadata:
+  for key_value_pair in original_metadata:
+    key, value = tuple(key_value_pair)
     original[key].append(value)
   transmitted = collections.defaultdict(list)
-  for key, value in transmitted_metadata:
+  for key_value_pair in transmitted_metadata:
+    key, value = tuple(key_value_pair)
     transmitted[key].append(value)
 
   for key, values in original.iteritems():
diff --git a/src/python/grpcio_test/setup.cfg b/src/python/grpcio_test/setup.cfg
index b32d3f5..3be93cb 100644
--- a/src/python/grpcio_test/setup.cfg
+++ b/src/python/grpcio_test/setup.cfg
@@ -1,3 +1,2 @@
 [pytest]
-norecursedirs = _cython
 python_files = *_test.py
diff --git a/src/python/grpcio_test/setup.py b/src/python/grpcio_test/setup.py
index fe36bc9..0f43b4a 100644
--- a/src/python/grpcio_test/setup.py
+++ b/src/python/grpcio_test/setup.py
@@ -40,7 +40,7 @@
 # Break import-style to ensure we can actually find our commands module.
 import commands
 
-_PACKAGES = setuptools.find_packages('.', exclude=['*._cython', '*._cython.*'])
+_PACKAGES = setuptools.find_packages('.')
 
 _PACKAGE_DIRECTORIES = {
     '': '.',