diff --git a/.gitignore b/.gitignore
index f059eca2393b7f1a4d88bb8014e5997a64343a81..471649d7a04d8cceac6c50214dfbbd0615762329 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,8 +4,13 @@ gens
 libs
 objs
 
-# Python virtual environments
-python*_virtual_environment
+# Python items
+.coverage*
+.eggs
+.tox
+htmlcov/
+dist/
+*.egg
 
 # gcov coverage data
 reports
diff --git a/MANIFEST.md b/MANIFEST.md
new file mode 100644
index 0000000000000000000000000000000000000000..b523f8f6fa5ed620d92e8e07d8b612d7a941968d
--- /dev/null
+++ b/MANIFEST.md
@@ -0,0 +1,14 @@
+# Top-level Items by language
+
+## Node
+* [binding.gyp](binding.gyp)
+
+## Objective-C
+* [gRPC.podspec](gRPC.podspec)
+
+## Python
+* [requirements.txt](requirements.txt)
+* [setup.cfg](setup.cfg)
+* [setup.py](setup.py)
+* [tox.ini](tox.ini)
+* [PYTHON-MANIFEST.in](PYTHON-MANIFEST.in)
diff --git a/Makefile b/Makefile
index 9ac33d52ee634efd69ef60b3950437b47c955881..0905f7d705e4e91c3a63b4672df271d6d5f42560 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@
 # This file can be regenerated from the template by running
 # tools/buildgen/generate_projects.sh
 
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/PYTHON-MANIFEST.in b/PYTHON-MANIFEST.in
new file mode 100644
index 0000000000000000000000000000000000000000..02bd9b5229415f91cbad93350ffdbc655d3d3aab
--- /dev/null
+++ b/PYTHON-MANIFEST.in
@@ -0,0 +1,10 @@
+graft src/python/grpcio/grpc
+graft src/python/grpcio/tests
+graft src/core
+graft include/grpc
+graft third_party/boringssl
+include src/python/grpcio/commands.py
+include src/python/grpcio/grpc_core_dependencies.py
+include src/python/grpcio/README.rst
+include requirements.txt
+include etc/roots.pem
diff --git a/README.md b/README.md
index 9701930547e832d76eb4715d9e54844d6b98db51..e0553ecc861b115d1093f86cc816aeaeef5e74c6 100644
--- a/README.md
+++ b/README.md
@@ -11,16 +11,16 @@ You can find more detailed documentation and examples in the [doc](doc) and [exa
 
 #Installation
 
-See grpc/INSTALL for installation instructions for various platforms.
+See [grpc/INSTALL](INSTALL) for installation instructions for various platforms.
 
 #Repository Structure & Status
 
 This repository contains source code for gRPC libraries for multiple languages written on top of shared C core library [src/core] (src/core).
 
-Libraries in different languages are in different state of development. We are seeking contributions for all of these libraries.
+Libraries in different languages are in different states of development. We are seeking contributions for all of these libraries.
 
-| Language                | Source                              | Status                          |
-|-------------------------|-------------------------------------|---------------------------------|
+| Language                | Source                              | Status                           |
+|-------------------------|-------------------------------------|----------------------------------|
 | Shared C [core library] | [src/core] (src/core)               | Beta - the surface API is stable |
 | C++                     | [src/cpp] (src/cpp)                 | Beta - the surface API is stable |
 | Ruby                    | [src/ruby] (src/ruby)               | Beta - the surface API is stable |
@@ -31,10 +31,12 @@ Libraries in different languages are in different state of development. We are s
 | Objective-C             | [src/objective-c] (src/objective-c) | Beta - the surface API is stable |
 
 <small>
-Java source code is in [grpc-java] (http://github.com/grpc/grpc-java) repository.
-Go source code is in [grpc-go] (http://github.com/grpc/grpc-go) repository.
+Java source code is in the [grpc-java] (http://github.com/grpc/grpc-java) repository.
+Go source code is in the [grpc-go] (http://github.com/grpc/grpc-go) repository.
 </small>
 
+See [MANIFEST.md](MANIFEST.md) for a listing of top-level items in the
+repository.
 
 #Overview
 
diff --git a/build.yaml b/build.yaml
index 4909eaac200f29116428c3422f63504cabcdee51..a23197c12ca89e51003c6bf18f58ddb86e211e88 100644
--- a/build.yaml
+++ b/build.yaml
@@ -2492,3 +2492,8 @@ node_modules:
   - src/node/ext/server.cc
   - src/node/ext/server_credentials.cc
   - src/node/ext/timeval.cc
+python_dependencies:
+  deps:
+  - grpc
+  - gpr
+  - boringssl
diff --git a/include/grpc++/channel.h b/include/grpc++/channel.h
index d6d72a9cf981fb3178a6dc2090ce30d1d093fea2..541be1345f80de8c48520d05f2c9772b65ca9512 100644
--- a/include/grpc++/channel.h
+++ b/include/grpc++/channel.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -54,13 +54,13 @@ template <class R>
 class ClientReader;
 template <class W>
 class ClientWriter;
-template <class R, class W>
+template <class W, class R>
 class ClientReaderWriter;
 template <class R>
 class ClientAsyncReader;
 template <class W>
 class ClientAsyncWriter;
-template <class R, class W>
+template <class W, class R>
 class ClientAsyncReaderWriter;
 template <class R>
 class ClientAsyncResponseReader;
@@ -98,13 +98,13 @@ class Channel GRPC_FINAL : public GrpcLibrary,
   friend class ::grpc::ClientReader;
   template <class W>
   friend class ::grpc::ClientWriter;
-  template <class R, class W>
+  template <class W, class R>
   friend class ::grpc::ClientReaderWriter;
   template <class R>
   friend class ::grpc::ClientAsyncReader;
   template <class W>
   friend class ::grpc::ClientAsyncWriter;
-  template <class R, class W>
+  template <class W, class R>
   friend class ::grpc::ClientAsyncReaderWriter;
   template <class R>
   friend class ::grpc::ClientAsyncResponseReader;
diff --git a/include/grpc++/client_context.h b/include/grpc++/client_context.h
index ab8ffb6474f3272ad33d15ccd010d2bd7a582de0..a0d5c0e3c41757867c9a282e389b5cfe1cf0f524 100644
--- a/include/grpc++/client_context.h
+++ b/include/grpc++/client_context.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -76,13 +76,13 @@ template <class R>
 class ClientReader;
 template <class W>
 class ClientWriter;
-template <class R, class W>
+template <class W, class R>
 class ClientReaderWriter;
 template <class R>
 class ClientAsyncReader;
 template <class W>
 class ClientAsyncWriter;
-template <class R, class W>
+template <class W, class R>
 class ClientAsyncReaderWriter;
 template <class R>
 class ClientAsyncResponseReader;
@@ -304,13 +304,13 @@ class ClientContext {
   friend class ::grpc::ClientReader;
   template <class W>
   friend class ::grpc::ClientWriter;
-  template <class R, class W>
+  template <class W, class R>
   friend class ::grpc::ClientReaderWriter;
   template <class R>
   friend class ::grpc::ClientAsyncReader;
   template <class W>
   friend class ::grpc::ClientAsyncWriter;
-  template <class R, class W>
+  template <class W, class R>
   friend class ::grpc::ClientAsyncReaderWriter;
   template <class R>
   friend class ::grpc::ClientAsyncResponseReader;
diff --git a/include/grpc++/completion_queue.h b/include/grpc++/completion_queue.h
index 0ea970417e602d785a6f973f7b8e92b2334c9ab3..5c2bc202c334ef7ef8867a413385637a8d047c7d 100644
--- a/include/grpc++/completion_queue.h
+++ b/include/grpc++/completion_queue.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -49,13 +49,13 @@ template <class R>
 class ClientReader;
 template <class W>
 class ClientWriter;
-template <class R, class W>
+template <class W, class R>
 class ClientReaderWriter;
 template <class R>
 class ServerReader;
 template <class W>
 class ServerWriter;
-template <class R, class W>
+template <class W, class R>
 class ServerReaderWriter;
 template <class ServiceType, class RequestType, class ResponseType>
 class RpcMethodHandler;
@@ -151,13 +151,13 @@ class CompletionQueue : public GrpcLibrary {
   friend class ::grpc::ClientReader;
   template <class W>
   friend class ::grpc::ClientWriter;
-  template <class R, class W>
+  template <class W, class R>
   friend class ::grpc::ClientReaderWriter;
   template <class R>
   friend class ::grpc::ServerReader;
   template <class W>
   friend class ::grpc::ServerWriter;
-  template <class R, class W>
+  template <class W, class R>
   friend class ::grpc::ServerReaderWriter;
   template <class ServiceType, class RequestType, class ResponseType>
   friend class RpcMethodHandler;
diff --git a/include/grpc++/server_context.h b/include/grpc++/server_context.h
index 85f384d4773c87528ff440534ebcfd98cd0927af..8ba73486dc45c998251220d892e6e9c78214146d 100644
--- a/include/grpc++/server_context.h
+++ b/include/grpc++/server_context.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -58,13 +58,13 @@ template <class W>
 class ServerAsyncWriter;
 template <class W>
 class ServerAsyncResponseWriter;
-template <class R, class W>
+template <class W, class R>
 class ServerAsyncReaderWriter;
 template <class R>
 class ServerReader;
 template <class W>
 class ServerWriter;
-template <class R, class W>
+template <class W, class R>
 class ServerReaderWriter;
 template <class ServiceType, class RequestType, class ResponseType>
 class RpcMethodHandler;
@@ -145,13 +145,13 @@ class ServerContext {
   friend class ::grpc::ServerAsyncWriter;
   template <class W>
   friend class ::grpc::ServerAsyncResponseWriter;
-  template <class R, class W>
+  template <class W, class R>
   friend class ::grpc::ServerAsyncReaderWriter;
   template <class R>
   friend class ::grpc::ServerReader;
   template <class W>
   friend class ::grpc::ServerWriter;
-  template <class R, class W>
+  template <class W, class R>
   friend class ::grpc::ServerReaderWriter;
   template <class ServiceType, class RequestType, class ResponseType>
   friend class RpcMethodHandler;
diff --git a/include/grpc++/support/async_stream.h b/include/grpc++/support/async_stream.h
index 823fcd2e8e184fb42f34e02e6fa10c86fc66c88d..0c96352ccdda2c39ec608d001f76a56f18945575 100644
--- a/include/grpc++/support/async_stream.h
+++ b/include/grpc++/support/async_stream.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/python/grpcio/requirements.txt b/requirements.txt
similarity index 62%
rename from src/python/grpcio/requirements.txt
rename to requirements.txt
index 06516ee0d7bda76b504058d5cc7756ef48c42aa1..9d002744495767e1340cb68f4595ba2d0bf3bfb8 100644
--- a/src/python/grpcio/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,4 @@
+# GRPC Python setup requirements
 enum34>=1.0.4
 futures>=2.2.0
 cython>=0.23
diff --git a/src/python/grpcio/setup.cfg b/setup.cfg
similarity index 80%
rename from src/python/grpcio/setup.cfg
rename to setup.cfg
index 52b6b50900716c3c29ab17d5ef5c54befcba4c4c..add6ee8749205ca37fa85d0b092404ecfca1a78a 100644
--- a/src/python/grpcio/setup.cfg
+++ b/setup.cfg
@@ -1,3 +1,5 @@
+# Setup settings for GRPC Python
+
 [coverage:run]
 plugins = Cython.Coverage
 
diff --git a/src/python/grpcio/setup.py b/setup.py
similarity index 72%
rename from src/python/grpcio/setup.py
rename to setup.py
index 366ebe3b3fb59aa26c3cd9bffc4737d4924a7ef5..93b1a3ae473e2d1a7504bbf7882a714222ee3a28 100644
--- a/src/python/grpcio/setup.py
+++ b/setup.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,17 +31,28 @@
 
 import os
 import os.path
+import shutil
 import sys
 
 from distutils import core as _core
 from distutils import extension as _extension
 import setuptools
+from setuptools.command import egg_info
+
+# Redirect the manifest template from MANIFEST.in to PYTHON-MANIFEST.in.
+egg_info.manifest_maker.template = 'PYTHON-MANIFEST.in'
+
+PYTHON_STEM = './src/python/grpcio/'
+CORE_INCLUDE = ('./include', './',)
+BORINGSSL_INCLUDE = ('./third_party/boringssl/include',)
 
 # Ensure we're in the proper directory whether or not we're being used by pip.
 os.chdir(os.path.dirname(os.path.abspath(__file__)))
+sys.path.insert(0, PYTHON_STEM)
 
-# Break import-style to ensure we can actually find our commands module.
+# Break import-style to ensure we can actually find our in-repo dependencies.
 import commands
+import grpc_core_dependencies
 
 # Environment variable to determine whether or not the Cython extension should
 # *use* Cython or use the generated C files. Note that this requires the C files
@@ -59,44 +70,44 @@ INSTALL_TESTS = os.environ.get('GRPC_PYTHON_INSTALL_TESTS', False)
 
 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',
-)
+CYTHON_EXTENSION_MODULE_NAMES = ('grpc._cython.cygrpc',)
 
 EXTENSION_INCLUDE_DIRECTORIES = (
-    '.',
-)
+    (PYTHON_STEM,) + CORE_INCLUDE + BORINGSSL_INCLUDE)
 
-EXTENSION_LIBRARIES = (
-    'grpc',
-    'gpr',
-)
+EXTENSION_LIBRARIES = ()
 if not "darwin" in sys.platform:
     EXTENSION_LIBRARIES += ('rt',)
 
+EXTRA_COMPILE_ARGS = ()
+if not "win" in sys.platform:
+  EXTRA_COMPILE_ARGS = ('-pthread',)
+
+DEFINE_MACROS = (('OPENSSL_NO_ASM', 1),)
 
 def cython_extensions(package_names, module_names, include_dirs, libraries,
+                      define_macros, extra_compile_args,
                       build_with_cython=False):
+  if ENABLE_CYTHON_TRACING:
+    define_macros = define_macros + [('CYTHON_TRACE_NOGIL', 1)]
   file_extension = 'pyx' if build_with_cython else 'c'
-  module_files = [name.replace('.', '/') + '.' + file_extension
+  module_files = [os.path.join(PYTHON_STEM,
+                               name.replace('.', '/') + '.' + file_extension)
                   for name in module_names]
   extensions = [
       _extension.Extension(
-          name=module_name, sources=[module_file],
+          name=module_name,
+          sources=[module_file] + grpc_core_dependencies.CORE_SOURCE_FILES,
           include_dirs=include_dirs, libraries=libraries,
-          define_macros=[('CYTHON_TRACE_NOGIL', 1)] if ENABLE_CYTHON_TRACING else []
+          extra_compile_args=extra_compile_args,
+          define_macros=define_macros,
       ) for (module_name, module_file) in zip(module_names, module_files)
   ]
   if build_with_cython:
     import Cython.Build
     return Cython.Build.cythonize(
         extensions,
+        include_path=include_dirs,
         compiler_directives={'linetrace': bool(ENABLE_CYTHON_TRACING)})
   else:
     return extensions
@@ -104,10 +115,10 @@ def cython_extensions(package_names, module_names, include_dirs, libraries,
 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))
+    list(DEFINE_MACROS), list(EXTRA_COMPILE_ARGS), bool(BUILD_WITH_CYTHON))
 
 PACKAGE_DIRECTORIES = {
-    '': '.',
+    '': PYTHON_STEM,
 }
 
 INSTALL_REQUIRES = (
@@ -128,6 +139,14 @@ COMMAND_CLASS = {
     'run_interop': commands.RunInterop,
 }
 
+# Ensure that package data is copied over before any commands have been run:
+credentials_dir = os.path.join(PYTHON_STEM, 'grpc/_adapter/credentials')
+try:
+  os.mkdir(credentials_dir)
+except OSError:
+  pass
+shutil.copyfile('etc/roots.pem', os.path.join(credentials_dir, 'roots.pem'))
+
 TEST_PACKAGE_DATA = {
     'tests.interop': [
         'credentials/ca.pem',
@@ -142,6 +161,9 @@ TEST_PACKAGE_DATA = {
         'credentials/server1.key',
         'credentials/server1.pem',
     ],
+    'grpc._adapter': [
+        'credentials/roots.pem'
+    ],
 }
 
 TESTS_REQUIRE = (
@@ -157,16 +179,18 @@ TEST_RUNNER = 'tests:Runner'
 PACKAGE_DATA = {}
 if INSTALL_TESTS:
   PACKAGE_DATA = dict(PACKAGE_DATA, **TEST_PACKAGE_DATA)
-  PACKAGES = setuptools.find_packages('.')
+  PACKAGES = setuptools.find_packages(PYTHON_STEM)
 else:
-  PACKAGES = setuptools.find_packages('.', exclude=['tests', 'tests.*'])
+  PACKAGES = setuptools.find_packages(
+      PYTHON_STEM, exclude=['tests', 'tests.*'])
 
 setuptools.setup(
     name='grpcio',
-    version='0.12.0b0',
+    version='0.12.0b1',
     ext_modules=CYTHON_EXTENSION_MODULES,
     packages=list(PACKAGES),
     package_dir=PACKAGE_DIRECTORIES,
+    package_data=PACKAGE_DATA,
     install_requires=INSTALL_REQUIRES,
     setup_requires=SETUP_REQUIRES,
     cmdclass=COMMAND_CLASS,
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c
index 385ae3be9b94fd22073fa23cdf24e2553ac95751..a92a6ecaf2a58a7c2d18c57bb2acbff2bce2cb70 100644
--- a/src/core/channel/client_channel.c
+++ b/src/core/channel/client_channel.c
@@ -353,10 +353,13 @@ static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
     return 1;
   }
   if (chand->lb_policy != NULL) {
-    int r =
-        grpc_lb_policy_pick(exec_ctx, chand->lb_policy, calld->pollset,
-                            initial_metadata, connected_subchannel, on_ready);
+    grpc_lb_policy *lb_policy = chand->lb_policy;
+    int r;
+    GRPC_LB_POLICY_REF(lb_policy, "cc_pick_subchannel");
     gpr_mu_unlock(&chand->mu_config);
+    r = grpc_lb_policy_pick(exec_ctx, lb_policy, calld->pollset,
+                            initial_metadata, connected_subchannel, on_ready);
+    GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "cc_pick_subchannel");
     return r;
   }
   if (chand->resolver != NULL && !chand->started_resolving) {
diff --git a/src/core/client_config/lb_policies/pick_first.c b/src/core/client_config/lb_policies/pick_first.c
index 37de3e9f68182157e64851cd752952691e88742f..e6ddb1a11f1fac5a5b6855fab5d381ae4a38d684 100644
--- a/src/core/client_config/lb_policies/pick_first.c
+++ b/src/core/client_config/lb_policies/pick_first.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -55,12 +55,11 @@ typedef struct {
 
   grpc_closure connectivity_changed;
 
+  /** the selected channel (a grpc_connected_subchannel) */
+  gpr_atm selected;
+
   /** mutex protecting remaining members */
   gpr_mu mu;
-  /** the selected channel
-      TODO(ctiller): this should be atomically set so we don't
-                     need to take a mutex in the common case */
-  grpc_connected_subchannel *selected;
   /** have we started picking? */
   int started_picking;
   /** are we shut down? */
@@ -76,15 +75,19 @@ typedef struct {
   grpc_connectivity_state_tracker state_tracker;
 } pick_first_lb_policy;
 
+#define GET_SELECTED(p) \
+  ((grpc_connected_subchannel *)gpr_atm_no_barrier_load(&(p)->selected))
+
 void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
   pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
+  grpc_connected_subchannel *selected = GET_SELECTED(p);
   size_t i;
   GPR_ASSERT(p->pending_picks == NULL);
   for (i = 0; i < p->num_subchannels; i++) {
     GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "pick_first");
   }
-  if (p->selected) {
-    GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, p->selected, "picked_first");
+  if (selected != NULL) {
+    GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, selected, "picked_first");
   }
   grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker);
   gpr_free(p->subchannels);
@@ -95,16 +98,18 @@ void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
 void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
   pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
   pending_pick *pp;
+  grpc_connected_subchannel *selected;
   gpr_mu_lock(&p->mu);
+  selected = GET_SELECTED(p);
   p->shutdown = 1;
   pp = p->pending_picks;
   p->pending_picks = NULL;
   grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
                               GRPC_CHANNEL_FATAL_FAILURE, "shutdown");
   /* cancel subscription */
-  if (p->selected != NULL) {
+  if (selected != NULL) {
     grpc_connected_subchannel_notify_on_state_change(
-        exec_ctx, p->selected, NULL, NULL, &p->connectivity_changed);
+        exec_ctx, selected, NULL, NULL, &p->connectivity_changed);
   } else {
     grpc_subchannel_notify_on_state_change(
         exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL,
@@ -171,10 +176,20 @@ int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
             grpc_connected_subchannel **target, grpc_closure *on_complete) {
   pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
   pending_pick *pp;
+
+  /* Check atomically for a selected channel */
+  grpc_connected_subchannel *selected = GET_SELECTED(p);
+  if (selected != NULL) {
+    *target = selected;
+    return 1;
+  }
+
+  /* No subchannel selected yet, so acquire lock and then attempt again */
   gpr_mu_lock(&p->mu);
-  if (p->selected) {
+  selected = GET_SELECTED(p);
+  if (selected) {
     gpr_mu_unlock(&p->mu);
-    *target = p->selected;
+    *target = selected;
     return 1;
   } else {
     if (!p->started_picking) {
@@ -219,14 +234,17 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
   pick_first_lb_policy *p = arg;
   grpc_subchannel *selected_subchannel;
   pending_pick *pp;
+  grpc_connected_subchannel *selected;
 
   gpr_mu_lock(&p->mu);
 
+  selected = GET_SELECTED(p);
+
   if (p->shutdown) {
     gpr_mu_unlock(&p->mu);
     GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
     return;
-  } else if (p->selected != NULL) {
+  } else if (selected != NULL) {
     if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
       /* if the selected channel goes bad, we're done */
       p->checking_connectivity = GRPC_CHANNEL_FATAL_FAILURE;
@@ -235,7 +253,7 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
                                 p->checking_connectivity, "selected_changed");
     if (p->checking_connectivity != GRPC_CHANNEL_FATAL_FAILURE) {
       grpc_connected_subchannel_notify_on_state_change(
-          exec_ctx, p->selected, &p->base.interested_parties,
+          exec_ctx, selected, &p->base.interested_parties,
           &p->checking_connectivity, &p->connectivity_changed);
     } else {
       GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
@@ -247,10 +265,11 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
         grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
                                     GRPC_CHANNEL_READY, "connecting_ready");
         selected_subchannel = p->subchannels[p->checking_subchannel];
-        p->selected =
+        selected =
             grpc_subchannel_get_connected_subchannel(selected_subchannel);
-        GPR_ASSERT(p->selected);
-        GRPC_CONNECTED_SUBCHANNEL_REF(p->selected, "picked_first");
+        GPR_ASSERT(selected != NULL);
+        gpr_atm_no_barrier_store(&p->selected, (gpr_atm)selected);
+        GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked_first");
         /* drop the pick list: we are connected now */
         GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels");
         grpc_exec_ctx_enqueue(exec_ctx,
@@ -258,14 +277,14 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
         /* update any calls that were waiting for a pick */
         while ((pp = p->pending_picks)) {
           p->pending_picks = pp->next;
-          *pp->target = p->selected;
+          *pp->target = selected;
           grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
                                        pp->pollset);
           grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
           gpr_free(pp);
         }
         grpc_connected_subchannel_notify_on_state_change(
-            exec_ctx, p->selected, &p->base.interested_parties,
+            exec_ctx, selected, &p->base.interested_parties,
             &p->checking_connectivity, &p->connectivity_changed);
         break;
       case GRPC_CHANNEL_TRANSIENT_FAILURE:
@@ -351,13 +370,12 @@ void pf_notify_on_state_change(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
 void pf_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
                  grpc_closure *closure) {
   pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
-  gpr_mu_lock(&p->mu);
-  if (p->selected) {
-    grpc_connected_subchannel_ping(exec_ctx, p->selected, closure);
+  grpc_connected_subchannel *selected = GET_SELECTED(p);
+  if (selected) {
+    grpc_connected_subchannel_ping(exec_ctx, selected, closure);
   } else {
     grpc_exec_ctx_enqueue(exec_ctx, closure, 0);
   }
-  gpr_mu_unlock(&p->mu);
 }
 
 static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = {
diff --git a/src/core/iomgr/fd_posix.c b/src/core/iomgr/fd_posix.c
index 917307a4c0f64bd2c2ee13728e2e36735be146bc..89c938bc04844ad9e25e66675e4a2f346e53ca29 100644
--- a/src/core/iomgr/fd_posix.c
+++ b/src/core/iomgr/fd_posix.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -211,6 +211,16 @@ static int has_watchers(grpc_fd *fd) {
          fd->inactive_watcher_root.next != &fd->inactive_watcher_root;
 }
 
+static void close_fd_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
+  fd->closed = 1;
+  if (!fd->released) {
+    close(fd->fd);
+  } else {
+    grpc_remove_fd_from_all_epoll_sets(fd->fd);
+  }
+  grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, 1);
+}
+
 int grpc_fd_wrapped_fd(grpc_fd *fd) {
   if (fd->released || fd->closed) {
     return -1;
@@ -231,11 +241,7 @@ void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
   gpr_mu_lock(&fd->mu);
   REF_BY(fd, 1, reason); /* remove active status, but keep referenced */
   if (!has_watchers(fd)) {
-    fd->closed = 1;
-    if (!fd->released) {
-      close(fd->fd);
-    }
-    grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, 1);
+    close_fd_locked(exec_ctx, fd);
   } else {
     wake_all_watchers_locked(fd);
   }
@@ -425,11 +431,7 @@ void grpc_fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *watcher,
     maybe_wake_one_watcher_locked(fd);
   }
   if (grpc_fd_is_orphaned(fd) && !has_watchers(fd) && !fd->closed) {
-    fd->closed = 1;
-    if (!fd->released) {
-      close(fd->fd);
-    }
-    grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, 1);
+    close_fd_locked(exec_ctx, fd);
   }
   gpr_mu_unlock(&fd->mu);
 
diff --git a/src/core/iomgr/fd_posix.h b/src/core/iomgr/fd_posix.h
index 8062dd01dbe0fc4c65563248fedf38428ee66bbb..17e7de88ffaa64b476a6e24491e75cda276ce592 100644
--- a/src/core/iomgr/fd_posix.h
+++ b/src/core/iomgr/fd_posix.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/core/iomgr/pollset_multipoller_with_epoll.c b/src/core/iomgr/pollset_multipoller_with_epoll.c
index 6e31efa013d8b3b3926200628b109a41e981d6b5..911d820fc7789aee429a466b44457727f72d0bf8 100644
--- a/src/core/iomgr/pollset_multipoller_with_epoll.c
+++ b/src/core/iomgr/pollset_multipoller_with_epoll.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,9 +43,66 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/useful.h>
 #include "src/core/iomgr/fd_posix.h"
-#include "src/core/support/block_annotate.h"
 #include "src/core/profiling/timers.h"
+#include "src/core/support/block_annotate.h"
+
+struct epoll_fd_list {
+  int *epoll_fds;
+  size_t count;
+  size_t capacity;
+};
+
+static struct epoll_fd_list epoll_fd_global_list;
+static gpr_once init_epoll_fd_list_mu = GPR_ONCE_INIT;
+static gpr_mu epoll_fd_list_mu;
+
+static void init_mu(void) { gpr_mu_init(&epoll_fd_list_mu); }
+
+static void add_epoll_fd_to_global_list(int epoll_fd) {
+  gpr_once_init(&init_epoll_fd_list_mu, init_mu);
+
+  gpr_mu_lock(&epoll_fd_list_mu);
+  if (epoll_fd_global_list.count == epoll_fd_global_list.capacity) {
+    epoll_fd_global_list.capacity =
+        GPR_MAX((size_t)8, epoll_fd_global_list.capacity * 2);
+    epoll_fd_global_list.epoll_fds =
+        gpr_realloc(epoll_fd_global_list.epoll_fds,
+                    epoll_fd_global_list.capacity * sizeof(int));
+  }
+  epoll_fd_global_list.epoll_fds[epoll_fd_global_list.count++] = epoll_fd;
+  gpr_mu_unlock(&epoll_fd_list_mu);
+}
+
+static void remove_epoll_fd_from_global_list(int epoll_fd) {
+  gpr_mu_lock(&epoll_fd_list_mu);
+  GPR_ASSERT(epoll_fd_global_list.count > 0);
+  for (size_t i = 0; i < epoll_fd_global_list.count; i++) {
+    if (epoll_fd == epoll_fd_global_list.epoll_fds[i]) {
+      epoll_fd_global_list.epoll_fds[i] =
+          epoll_fd_global_list.epoll_fds[--(epoll_fd_global_list.count)];
+      break;
+    }
+  }
+  gpr_mu_unlock(&epoll_fd_list_mu);
+}
+
+void grpc_remove_fd_from_all_epoll_sets(int fd) {
+  int err;
+  gpr_mu_lock(&epoll_fd_list_mu);
+  if (epoll_fd_global_list.count == 0) {
+    return;
+  }
+  for (size_t i = 0; i < epoll_fd_global_list.count; i++) {
+    err = epoll_ctl(epoll_fd_global_list.epoll_fds[i], EPOLL_CTL_DEL, fd, NULL);
+    if (err < 0 && errno != ENOENT) {
+      gpr_log(GPR_ERROR, "epoll_ctl del for %d failed: %s", fd,
+              strerror(errno));
+    }
+  }
+  gpr_mu_unlock(&epoll_fd_list_mu);
+}
 
 typedef struct {
   grpc_pollset *pollset;
@@ -211,6 +268,7 @@ static void multipoll_with_epoll_pollset_finish_shutdown(
 static void multipoll_with_epoll_pollset_destroy(grpc_pollset *pollset) {
   pollset_hdr *h = pollset->data.ptr;
   close(h->epoll_fd);
+  remove_epoll_fd_from_global_list(h->epoll_fd);
   gpr_free(h);
 }
 
@@ -236,6 +294,7 @@ static void epoll_become_multipoller(grpc_exec_ctx *exec_ctx,
     gpr_log(GPR_ERROR, "epoll_create1 failed: %s", strerror(errno));
     abort();
   }
+  add_epoll_fd_to_global_list(h->epoll_fd);
 
   ev.events = (uint32_t)(EPOLLIN | EPOLLET);
   ev.data.ptr = NULL;
@@ -255,4 +314,8 @@ static void epoll_become_multipoller(grpc_exec_ctx *exec_ctx,
 grpc_platform_become_multipoller_type grpc_platform_become_multipoller =
     epoll_become_multipoller;
 
+#else /* GPR_LINUX_MULTIPOLL_WITH_EPOLL */
+
+void grpc_remove_fd_from_all_epoll_sets(int fd) {}
+
 #endif /* GPR_LINUX_MULTIPOLL_WITH_EPOLL */
diff --git a/src/core/iomgr/pollset_multipoller_with_poll_posix.c b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
index a7282b9896e62370f7a7d78cf83ef6a44a1b1de7..809f8f39daababae2bfdf22a6f8bf93ce8c238a1 100644
--- a/src/core/iomgr/pollset_multipoller_with_poll_posix.c
+++ b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/core/iomgr/pollset_posix.h b/src/core/iomgr/pollset_posix.h
index 78fc27d2b37f8d725219d0805aeb7eb2e38cf50a..b34bb094268229b92bdbf8b09ad431133564b0ce 100644
--- a/src/core/iomgr/pollset_posix.h
+++ b/src/core/iomgr/pollset_posix.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -139,6 +139,8 @@ void grpc_poll_become_multipoller(grpc_exec_ctx *exec_ctx,
  * be locked) */
 int grpc_pollset_has_workers(grpc_pollset *pollset);
 
+void grpc_remove_fd_from_all_epoll_sets(int fd);
+
 /* override to allow tests to hook poll() usage */
 typedef int (*grpc_poll_function_type)(struct pollfd *, nfds_t, int);
 extern grpc_poll_function_type grpc_poll_function;
diff --git a/src/core/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c
index 65783a7afaa47de3083c6e50770771136faa6fac..4fa8ca8c7112c0cccec7760d9740f1ac2b347f1b 100644
--- a/src/core/iomgr/tcp_posix.c
+++ b/src/core/iomgr/tcp_posix.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/core/iomgr/tcp_posix.h b/src/core/iomgr/tcp_posix.h
index 495ed009c8d270113af7cee9992e1abebb3d2b1b..2a40cdd38590b20f75464b4e3822949994ffa75e 100644
--- a/src/core/iomgr/tcp_posix.h
+++ b/src/core/iomgr/tcp_posix.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/core/security/base64.c b/src/core/security/base64.c
index e68359602e6d6e070ffaf0d49e29374b057012de..8367c160c3672f877033ddf195375a0109687623 100644
--- a/src/core/security/base64.c
+++ b/src/core/security/base64.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,7 @@
 
 #include "src/core/security/base64.h"
 
+#include <stdint.h>
 #include <string.h>
 
 #include <grpc/support/alloc.h>
@@ -41,7 +42,7 @@
 
 /* --- Constants. --- */
 
-static const char base64_bytes[] = {
+static const int8_t base64_bytes[] = {
     -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
     -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
     -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
diff --git a/src/core/support/sync_posix.c b/src/core/support/sync_posix.c
index 4d59a100024b0adbfb0c1fee97eb4f31d32b0fbc..d3c483f1b538c9e22c4169516de465f038881834 100644
--- a/src/core/support/sync_posix.c
+++ b/src/core/support/sync_posix.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/core/transport/chttp2/internal.h b/src/core/transport/chttp2/internal.h
index 0b0fccfcd484007755da62d0aca538f8ba5fd2a8..a8262b7af2cd1b9d64b451e1dcbdc89694b25201 100644
--- a/src/core/transport/chttp2/internal.h
+++ b/src/core/transport/chttp2/internal.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index c154c07772f095d7cc30054787f86e6a70540857..05b25fd8b01f526282783d1fbc31b11ce2d5bf4c 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh
index 8e75fea9d0438b75d3a8ff8ce4bc143c1182b2a2..3aeda21ba3a3736c779e14829493dcc94dc0e29b 100755
--- a/src/csharp/generate_proto_csharp.sh
+++ b/src/csharp/generate_proto_csharp.sh
@@ -1,5 +1,5 @@
 #!/bin/sh
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js
index 7e65d20be2b8b18f9ea0bf2a4abbfa3399975a45..db383e4d0006d1cfad19e831eee1dd40eac3ca98 100644
--- a/src/node/interop/interop_client.js
+++ b/src/node/interop/interop_client.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/node/interop/interop_server.js b/src/node/interop/interop_server.js
index 72807623054cff8df0bda0f1fce0f26106dde3ea..c09481712aa3d26559dedc79d7dd8b811d8ead0c 100644
--- a/src/node/interop/interop_server.js
+++ b/src/node/interop/interop_server.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/node/performance/benchmark_client.js b/src/node/performance/benchmark_client.js
index 9e956d4027878662627b0d415b9817c637b8daf4..620aecde97b22635ee057769c9c4f402b1a18def 100644
--- a/src/node/performance/benchmark_client.js
+++ b/src/node/performance/benchmark_client.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/node/performance/benchmark_server.js b/src/node/performance/benchmark_server.js
index 858f21945b46e87a1c206a9bd87fa61be97b78fb..ba61e52ba1b8b5aecc9e7e269ca31a0aa71b6f15 100644
--- a/src/node/performance/benchmark_server.js
+++ b/src/node/performance/benchmark_server.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/node/performance/worker_server.js b/src/node/performance/worker_server.js
index 98577bdbc977a6913bc71fa5038671f60de469da..7c8ab00026538ae03182a3ec03042036f876bf40 100644
--- a/src/node/performance/worker_server.js
+++ b/src/node/performance/worker_server.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/python/grpcio/.gitignore b/src/python/grpcio/.gitignore
index 95b96f7c1e9f7c368801e14f6848639f2b13485b..1d804e1ffc8f51ed6e7dabcea082d8e25f19b28e 100644
--- a/src/python/grpcio/.gitignore
+++ b/src/python/grpcio/.gitignore
@@ -14,3 +14,4 @@ nosetests.xml
 doc/
 _grpcio_metadata.py
 htmlcov/
+grpc/_adapter/credentials
diff --git a/src/python/grpcio/MANIFEST.in b/src/python/grpcio/MANIFEST.in
deleted file mode 100644
index 407eeabc1792555014d5ca27bdbf2281eccc90d9..0000000000000000000000000000000000000000
--- a/src/python/grpcio/MANIFEST.in
+++ /dev/null
@@ -1,4 +0,0 @@
-graft grpc
-graft tests
-include commands.py
-include requirements.txt
diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py
index d9fd023b214923f5bbb442104c69d3bca87f8a18..81dab1b51860f91888cc370c7679684283246557 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -40,6 +40,8 @@ import setuptools
 from setuptools.command import build_py
 from setuptools.command import test
 
+PYTHON_STEM = os.path.dirname(os.path.abspath(__file__))
+
 CONF_PY_ADDENDUM = """
 extensions.append('sphinx.ext.napoleon')
 napoleon_google_docstring = True
@@ -68,7 +70,7 @@ class SphinxDocumentation(setuptools.Command):
     import sphinx.apidoc
     metadata = self.distribution.metadata
     src_dir = os.path.join(
-        os.getcwd(), self.distribution.package_dir[''], 'grpc')
+        PYTHON_STEM, self.distribution.package_dir[''], 'grpc')
     sys.path.append(src_dir)
     sphinx.apidoc.main([
         '', '--force', '--full', '-H', metadata.name, '-A', metadata.author,
@@ -101,10 +103,15 @@ class BuildProtoModules(setuptools.Command):
         'grpc_python_plugin')
 
   def run(self):
+    if not self.protoc_command:
+      raise Exception('could not find protoc')
+    if not self.grpc_python_plugin_command:
+      raise Exception('could not find grpc_python_plugin '
+                      '(protoc plugin for GRPC Python)')
     include_regex = re.compile(self.include)
     exclude_regex = re.compile(self.exclude) if self.exclude else None
     paths = []
-    root_directory = os.getcwd()
+    root_directory = PYTHON_STEM
     for walk_root, directories, filenames in os.walk(root_directory):
       for filename in filenames:
         path = os.path.join(walk_root, filename)
@@ -140,7 +147,7 @@ class BuildProjectMetadata(setuptools.Command):
     pass
 
   def run(self):
-    with open('grpc/_grpcio_metadata.py', 'w') as module_file:
+    with open(os.path.join(PYTHON_STEM, 'grpc/_grpcio_metadata.py'), 'w') as module_file:
       module_file.write('__version__ = """{}"""'.format(
           self.distribution.get_version()))
 
@@ -149,6 +156,8 @@ class BuildPy(build_py.build_py):
   """Custom project build command."""
 
   def run(self):
+    # TODO(atash): make this warn if the proto modules couldn't be built rather
+    # than cause build failure
     self.run_command('build_proto_modules')
     self.run_command('build_project_metadata')
     build_py.build_py.run(self)
diff --git a/src/python/grpcio/grpc/_adapter/_low.py b/src/python/grpcio/grpc/_adapter/_low.py
index b13d8dd9dda1f8e92e45d3fc5c18be1e7be2896f..a850c577414315b1c3e817c460fb2b0bde0f3c0b 100644
--- a/src/python/grpcio/grpc/_adapter/_low.py
+++ b/src/python/grpcio/grpc/_adapter/_low.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -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.
 
+import pkg_resources
 import threading
 
 from grpc import _grpcio_metadata
@@ -34,6 +35,7 @@ from grpc._cython import cygrpc
 from grpc._adapter import _implementations
 from grpc._adapter import _types
 
+_ROOT_CERTIFICATES_RESOURCE_PATH = 'credentials/roots.pem'
 _USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__)
 
 ChannelCredentials = cygrpc.ChannelCredentials
@@ -54,6 +56,9 @@ def channel_credentials_ssl(
   pair = None
   if private_key is not None or certificate_chain is not None:
     pair = cygrpc.SslPemKeyCertPair(private_key, certificate_chain)
+  if root_certificates is None:
+    root_certificates = pkg_resources.resource_string(
+      __name__, _ROOT_CERTIFICATES_RESOURCE_PATH)
   return cygrpc.channel_credentials_ssl(root_certificates, pair)
 
 
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/call.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/call.pxd.pxi
similarity index 95%
rename from src/python/grpcio/grpc/_cython/_cygrpc/call.pxd
rename to src/python/grpcio/grpc/_cython/_cygrpc/call.pxd.pxi
index fe9b81e3d3a7017a495b6b4a17e788a7406296b9..6a316746fbd32967bd0a48a9f9ac2475aa86a546 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/call.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/call.pxd.pxi
@@ -27,11 +27,9 @@
 # (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
-
 
 cdef class Call:
 
-  cdef grpc.grpc_call *c_call
+  cdef grpc_call *c_call
   cdef list references
 
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
similarity index 77%
rename from src/python/grpcio/grpc/_cython/_cygrpc/call.pyx
rename to src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
index 1c07f9f4f4c6870dd3451844a188eee58d998e0b..80f4da51e8c4ee537400dd115a14cd4dfc5a5e74 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
@@ -29,10 +29,6 @@
 
 cimport cpython
 
-from grpc._cython._cygrpc cimport credentials
-from grpc._cython._cygrpc cimport grpc
-from grpc._cython._cygrpc cimport records
-
 
 cdef class Call:
 
@@ -44,24 +40,24 @@ cdef class Call:
   def start_batch(self, operations, tag):
     if not self.is_valid:
       raise ValueError("invalid call object cannot be used from Python")
-    cdef records.Operations cy_operations = records.Operations(operations)
-    cdef records.OperationTag operation_tag = records.OperationTag(tag)
+    cdef Operations cy_operations = Operations(operations)
+    cdef OperationTag operation_tag = OperationTag(tag)
     operation_tag.operation_call = self
     operation_tag.batch_operations = cy_operations
     cpython.Py_INCREF(operation_tag)
-    return grpc.grpc_call_start_batch(
+    return grpc_call_start_batch(
         self.c_call, cy_operations.c_ops, cy_operations.c_nops,
         <cpython.PyObject *>operation_tag, NULL)
 
   def cancel(
-      self, grpc.grpc_status_code error_code=grpc.GRPC_STATUS__DO_NOT_USE,
+      self, grpc_status_code error_code=GRPC_STATUS__DO_NOT_USE,
       details=None):
     if not self.is_valid:
       raise ValueError("invalid call object cannot be used from Python")
-    if (details is None) != (error_code == grpc.GRPC_STATUS__DO_NOT_USE):
+    if (details is None) != (error_code == GRPC_STATUS__DO_NOT_USE):
       raise ValueError("if error_code is specified, so must details "
                        "(and vice-versa)")
-    if error_code != grpc.GRPC_STATUS__DO_NOT_USE:
+    if error_code != GRPC_STATUS__DO_NOT_USE:
       if isinstance(details, bytes):
         pass
       elif isinstance(details, basestring):
@@ -69,25 +65,25 @@ cdef class Call:
       else:
         raise TypeError("expected details to be str or bytes")
       self.references.append(details)
-      return grpc.grpc_call_cancel_with_status(
+      return grpc_call_cancel_with_status(
           self.c_call, error_code, details, NULL)
     else:
-      return grpc.grpc_call_cancel(self.c_call, NULL)
+      return grpc_call_cancel(self.c_call, NULL)
 
   def set_credentials(
-      self, credentials.CallCredentials call_credentials not None):
-    return grpc.grpc_call_set_credentials(
+      self, CallCredentials call_credentials not None):
+    return grpc_call_set_credentials(
         self.c_call, call_credentials.c_credentials)
 
   def peer(self):
-    cdef char *peer = grpc.grpc_call_get_peer(self.c_call)
+    cdef char *peer = grpc_call_get_peer(self.c_call)
     result = <bytes>peer
-    grpc.gpr_free(peer)
+    gpr_free(peer)
     return result
 
   def __dealloc__(self):
     if self.c_call != NULL:
-      grpc.grpc_call_destroy(self.c_call)
+      grpc_call_destroy(self.c_call)
 
   # The object *should* always be valid from Python. Used for debugging.
   @property
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pxd.pxi
similarity index 95%
rename from src/python/grpcio/grpc/_cython/_cygrpc/channel.pxd
rename to src/python/grpcio/grpc/_cython/_cygrpc/channel.pxd.pxi
index 3e341bf2225f6746856e802943e8725ca4ed601d..70da63db978c241ceeeee6f29b8c5339b5d147d3 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pxd.pxi
@@ -27,10 +27,8 @@
 # (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
-
 
 cdef class Channel:
 
-  cdef grpc.grpc_channel *c_channel
+  cdef grpc_channel *c_channel
   cdef list references
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
similarity index 72%
rename from src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
rename to src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
index a944a83576c5dfe393124af74df9573e74ba5295..ac67f32d923aee5bd597b4c73d9df6ec1362ae15 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
@@ -29,18 +29,12 @@
 
 cimport cpython
 
-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
-
 
 cdef class Channel:
 
-  def __cinit__(self, target, records.ChannelArgs arguments=None,
-                credentials.ChannelCredentials channel_credentials=None):
-    cdef grpc.grpc_channel_args *c_arguments = NULL
+  def __cinit__(self, target, ChannelArgs arguments=None,
+                ChannelCredentials channel_credentials=None):
+    cdef grpc_channel_args *c_arguments = NULL
     self.c_channel = NULL
     self.references = []
     if arguments is not None:
@@ -52,18 +46,18 @@ cdef class Channel:
     else:
       raise TypeError("expected target to be str or bytes")
     if channel_credentials is None:
-      self.c_channel = grpc.grpc_insecure_channel_create(target, c_arguments,
+      self.c_channel = grpc_insecure_channel_create(target, c_arguments,
                                                          NULL)
     else:
-      self.c_channel = grpc.grpc_secure_channel_create(
+      self.c_channel = grpc_secure_channel_create(
           channel_credentials.c_credentials, target, c_arguments, NULL)
       self.references.append(channel_credentials)
     self.references.append(target)
     self.references.append(arguments)
 
-  def create_call(self, call.Call parent, int flags,
-                  completion_queue.CompletionQueue queue not None,
-                  method, host, records.Timespec deadline not None):
+  def create_call(self, Call parent, int flags,
+                  CompletionQueue queue not None,
+                  method, host, Timespec deadline not None):
     if queue.is_shutting_down:
       raise ValueError("queue must not be shutting down or shutdown")
     if isinstance(method, bytes):
@@ -82,36 +76,36 @@ cdef class Channel:
       host_c_string = host
     else:
       raise TypeError("expected host to be str, bytes, or None")
-    cdef call.Call operation_call = call.Call()
+    cdef Call operation_call = Call()
     operation_call.references = [self, method, host, queue]
-    cdef grpc.grpc_call *parent_call = NULL
+    cdef grpc_call *parent_call = NULL
     if parent is not None:
       parent_call = parent.c_call
-    operation_call.c_call = grpc.grpc_channel_create_call(
+    operation_call.c_call = grpc_channel_create_call(
         self.c_channel, parent_call, flags,
         queue.c_completion_queue, method, host_c_string, deadline.c_time,
         NULL)
     return operation_call
 
   def check_connectivity_state(self, bint try_to_connect):
-    return grpc.grpc_channel_check_connectivity_state(self.c_channel,
+    return grpc_channel_check_connectivity_state(self.c_channel,
                                                       try_to_connect)
 
   def watch_connectivity_state(
-      self, last_observed_state, records.Timespec deadline not None,
-      completion_queue.CompletionQueue queue not None, tag):
-    cdef records.OperationTag operation_tag = records.OperationTag(tag)
+      self, last_observed_state, Timespec deadline not None,
+      CompletionQueue queue not None, tag):
+    cdef OperationTag operation_tag = OperationTag(tag)
     cpython.Py_INCREF(operation_tag)
-    grpc.grpc_channel_watch_connectivity_state(
+    grpc_channel_watch_connectivity_state(
         self.c_channel, last_observed_state, deadline.c_time,
         queue.c_completion_queue, <cpython.PyObject *>operation_tag)
 
   def target(self):
-    cdef char * target = grpc.grpc_channel_get_target(self.c_channel)
+    cdef char * target = grpc_channel_get_target(self.c_channel)
     result = <bytes>target
-    grpc.gpr_free(target)
+    gpr_free(target)
     return result
 
   def __dealloc__(self):
     if self.c_channel != NULL:
-      grpc.grpc_channel_destroy(self.c_channel)
+      grpc_channel_destroy(self.c_channel)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pxd.pxi
similarity index 91%
rename from src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pxd
rename to src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pxd.pxi
index 1ed5d4b229981eda35b12c6d2a0bbaa2edeb4473..757f1245e85a18cc8f77e44579af35faf8acf740 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pxd.pxi
@@ -27,15 +27,13 @@
 # (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
-
 
 cdef class CompletionQueue:
 
-  cdef grpc.grpc_completion_queue *c_completion_queue
+  cdef grpc_completion_queue *c_completion_queue
   cdef object poll_condition
   cdef bint is_polling
   cdef bint is_shutting_down
   cdef bint is_shutdown
 
-  cdef _interpret_event(self, grpc.grpc_event event)
+  cdef _interpret_event(self, grpc_event event)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
similarity index 77%
rename from src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx
rename to src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
index 635a38fe28e04af1ecd81b3150ce79323535d65a..bbf841329938c486da86b4dae9eba777c4bca35b 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
@@ -29,10 +29,6 @@
 
 cimport cpython
 
-from grpc._cython._cygrpc cimport call
-from grpc._cython._cygrpc cimport grpc
-from grpc._cython._cygrpc cimport records
-
 import threading
 import time
 
@@ -40,29 +36,29 @@ import time
 cdef class CompletionQueue:
 
   def __cinit__(self):
-    self.c_completion_queue = grpc.grpc_completion_queue_create(NULL)
+    self.c_completion_queue = grpc_completion_queue_create(NULL)
     self.is_shutting_down = False
     self.is_shutdown = False
     self.poll_condition = threading.Condition()
     self.is_polling = False
 
-  cdef _interpret_event(self, grpc.grpc_event event):
-    cdef records.OperationTag tag = None
+  cdef _interpret_event(self, grpc_event event):
+    cdef OperationTag tag = None
     cdef object user_tag = None
-    cdef call.Call operation_call = None
-    cdef records.CallDetails request_call_details = None
-    cdef records.Metadata request_metadata = None
-    cdef records.Operations batch_operations = None
-    if event.type == grpc.GRPC_QUEUE_TIMEOUT:
-      return records.Event(
+    cdef Call operation_call = None
+    cdef CallDetails request_call_details = None
+    cdef Metadata request_metadata = None
+    cdef Operations batch_operations = None
+    if event.type == GRPC_QUEUE_TIMEOUT:
+      return Event(
           event.type, False, None, None, None, None, False, None)
-    elif event.type == grpc.GRPC_QUEUE_SHUTDOWN:
+    elif event.type == GRPC_QUEUE_SHUTDOWN:
       self.is_shutdown = True
-      return records.Event(
+      return Event(
           event.type, True, None, None, None, None, False, None)
     else:
       if event.tag != NULL:
-        tag = <records.OperationTag>event.tag
+        tag = <OperationTag>event.tag
         # We receive event tags only after they've been inc-ref'd elsewhere in
         # the code.
         cpython.Py_DECREF(tag)
@@ -77,19 +73,19 @@ cdef class CompletionQueue:
           # Stuff in the tag not explicitly handled by us needs to live through
           # the life of the call
           operation_call.references.extend(tag.references)
-      return records.Event(
+      return Event(
           event.type, event.success, user_tag, operation_call,
           request_call_details, request_metadata, tag.is_new_request,
           batch_operations)
 
-  def poll(self, records.Timespec deadline=None):
+  def poll(self, 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(
-        grpc.GPR_CLOCK_REALTIME)
+    cdef gpr_timespec c_deadline = gpr_inf_future(
+        GPR_CLOCK_REALTIME)
     if deadline is not None:
       c_deadline = deadline.c_time
-    cdef grpc.grpc_event event
+    cdef grpc_event event
 
     # Poll within a critical section
     # TODO(atash) consider making queue polling contention a hard error to
@@ -99,21 +95,21 @@ cdef class CompletionQueue:
         self.poll_condition.wait(float(deadline) - time.time())
       self.is_polling = True
     with nogil:
-      event = grpc.grpc_completion_queue_next(
+      event = grpc_completion_queue_next(
           self.c_completion_queue, c_deadline, NULL)
     with self.poll_condition:
       self.is_polling = False
       self.poll_condition.notify()
     return self._interpret_event(event)
 
-  def pluck(self, records.OperationTag tag, records.Timespec deadline=None):
+  def pluck(self, OperationTag tag, Timespec deadline=None):
     # Plucking a 'None' tag is equivalent to passing control to GRPC core until
     # the deadline.
-    cdef grpc.gpr_timespec c_deadline = grpc.gpr_inf_future(
-        grpc.GPR_CLOCK_REALTIME)
+    cdef gpr_timespec c_deadline = gpr_inf_future(
+        GPR_CLOCK_REALTIME)
     if deadline is not None:
       c_deadline = deadline.c_time
-    cdef grpc.grpc_event event
+    cdef grpc_event event
 
     # Poll within a critical section
     # TODO(atash) consider making queue polling contention a hard error to
@@ -123,7 +119,7 @@ cdef class CompletionQueue:
         self.poll_condition.wait(float(deadline) - time.time())
       self.is_polling = True
     with nogil:
-      event = grpc.grpc_completion_queue_pluck(
+      event = grpc_completion_queue_pluck(
           self.c_completion_queue, <cpython.PyObject *>tag, c_deadline, NULL)
     with self.poll_condition:
       self.is_polling = False
@@ -131,13 +127,13 @@ cdef class CompletionQueue:
     return self._interpret_event(event)
 
   def shutdown(self):
-    grpc.grpc_completion_queue_shutdown(self.c_completion_queue)
+    grpc_completion_queue_shutdown(self.c_completion_queue)
     self.is_shutting_down = True
 
   def clear(self):
     if not self.is_shutting_down:
       raise ValueError('queue must be shutting down to be cleared')
-    while self.poll().type != grpc.GRPC_QUEUE_SHUTDOWN:
+    while self.poll().type != GRPC_QUEUE_SHUTDOWN:
       pass
 
   def __dealloc__(self):
@@ -147,4 +143,4 @@ cdef class CompletionQueue:
         self.shutdown()
       while not self.is_shutdown:
         self.poll()
-      grpc.grpc_completion_queue_destroy(self.c_completion_queue)
+      grpc_completion_queue_destroy(self.c_completion_queue)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi
similarity index 76%
rename from src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd
rename to src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi
index db9f8ddec9936ab6ecdf9a0464f05cebac49a2d6..c793c8f5e588a7d5996a2ba96033b5a341ebd5da 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi
@@ -29,27 +29,24 @@
 
 cimport cpython
 
-from grpc._cython._cygrpc cimport grpc
-from grpc._cython._cygrpc cimport records
-
 
 cdef class ChannelCredentials:
 
-  cdef grpc.grpc_channel_credentials *c_credentials
-  cdef grpc.grpc_ssl_pem_key_cert_pair c_ssl_pem_key_cert_pair
+  cdef grpc_channel_credentials *c_credentials
+  cdef grpc_ssl_pem_key_cert_pair c_ssl_pem_key_cert_pair
   cdef list references
 
 
 cdef class CallCredentials:
 
-  cdef grpc.grpc_call_credentials *c_credentials
+  cdef grpc_call_credentials *c_credentials
   cdef list references
 
 
 cdef class ServerCredentials:
 
-  cdef grpc.grpc_server_credentials *c_credentials
-  cdef grpc.grpc_ssl_pem_key_cert_pair *c_ssl_pem_key_cert_pairs
+  cdef grpc_server_credentials *c_credentials
+  cdef grpc_ssl_pem_key_cert_pair *c_ssl_pem_key_cert_pairs
   cdef size_t c_ssl_pem_key_cert_pairs_count
   cdef list references
 
@@ -59,16 +56,16 @@ cdef class CredentialsMetadataPlugin:
   cdef object plugin_callback
   cdef str plugin_name
 
-  cdef grpc.grpc_metadata_credentials_plugin make_c_plugin(self)
+  cdef grpc_metadata_credentials_plugin make_c_plugin(self)
 
 
 cdef class AuthMetadataContext:
 
-  cdef grpc.grpc_auth_metadata_context context
+  cdef grpc_auth_metadata_context context
 
 
 cdef void plugin_get_metadata(
-    void *state, grpc.grpc_auth_metadata_context context,
-    grpc.grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil
+    void *state, grpc_auth_metadata_context context,
+    grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil
 
 cdef void plugin_destroy_c_plugin_state(void *state)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
similarity index 83%
rename from src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
rename to src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
index a968894967a542ec059f98bbfd4fd12c6f0d3f18..3f439c8900fdcd7889828659d5cf9d1059819b44 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
@@ -29,9 +29,6 @@
 
 cimport cpython
 
-from grpc._cython._cygrpc cimport grpc
-from grpc._cython._cygrpc cimport records
-
 
 cdef class ChannelCredentials:
 
@@ -49,7 +46,7 @@ cdef class ChannelCredentials:
 
   def __dealloc__(self):
     if self.c_credentials != NULL:
-      grpc.grpc_channel_credentials_release(self.c_credentials)
+      grpc_channel_credentials_release(self.c_credentials)
 
 
 cdef class CallCredentials:
@@ -66,7 +63,7 @@ cdef class CallCredentials:
 
   def __dealloc__(self):
     if self.c_credentials != NULL:
-      grpc.grpc_call_credentials_release(self.c_credentials)
+      grpc_call_credentials_release(self.c_credentials)
 
 
 cdef class ServerCredentials:
@@ -77,7 +74,7 @@ cdef class ServerCredentials:
 
   def __dealloc__(self):
     if self.c_credentials != NULL:
-      grpc.grpc_server_credentials_release(self.c_credentials)
+      grpc_server_credentials_release(self.c_credentials)
 
 
 cdef class CredentialsMetadataPlugin:
@@ -86,8 +83,8 @@ cdef class CredentialsMetadataPlugin:
     """
     Args:
       plugin_callback (callable): Callback accepting a service URL (str/bytes)
-        and callback object (accepting a records.Metadata,
-        grpc.grpc_status_code, and a str/bytes error message). This argument
+        and callback object (accepting a Metadata,
+        grpc_status_code, and a str/bytes error message). This argument
         when called should be non-blocking and eventually call the callback
         object with the appropriate status code/details and metadata (if
         successful).
@@ -99,8 +96,8 @@ cdef class CredentialsMetadataPlugin:
     self.plugin_name = name
 
   @staticmethod
-  cdef grpc.grpc_metadata_credentials_plugin make_c_plugin(self):
-    cdef grpc.grpc_metadata_credentials_plugin result
+  cdef grpc_metadata_credentials_plugin make_c_plugin(self):
+    cdef grpc_metadata_credentials_plugin result
     result.get_metadata = plugin_get_metadata
     result.destroy = plugin_destroy_c_plugin_state
     result.state = <void *>self
@@ -125,10 +122,10 @@ cdef class AuthMetadataContext:
 
 
 cdef void plugin_get_metadata(
-    void *state, grpc.grpc_auth_metadata_context context,
-    grpc.grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil:
+    void *state, grpc_auth_metadata_context context,
+    grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil:
   def python_callback(
-      records.Metadata metadata, grpc.grpc_status_code status,
+      Metadata metadata, grpc_status_code status,
       const char *error_details):
     cb(user_data, metadata.c_metadata_array.metadata,
        metadata.c_metadata_array.count, status, error_details)
@@ -142,11 +139,11 @@ cdef void plugin_destroy_c_plugin_state(void *state):
 
 def channel_credentials_google_default():
   cdef ChannelCredentials credentials = ChannelCredentials();
-  credentials.c_credentials = grpc.grpc_google_default_credentials_create()
+  credentials.c_credentials = grpc_google_default_credentials_create()
   return credentials
 
 def channel_credentials_ssl(pem_root_certificates,
-                            records.SslPemKeyCertPair ssl_pem_key_cert_pair):
+                            SslPemKeyCertPair ssl_pem_key_cert_pair):
   if pem_root_certificates is None:
     pass
   elif isinstance(pem_root_certificates, bytes):
@@ -161,11 +158,11 @@ def channel_credentials_ssl(pem_root_certificates,
     c_pem_root_certificates = pem_root_certificates
     credentials.references.append(pem_root_certificates)
   if ssl_pem_key_cert_pair is not None:
-    credentials.c_credentials = grpc.grpc_ssl_credentials_create(
+    credentials.c_credentials = grpc_ssl_credentials_create(
         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(
+    credentials.c_credentials = grpc_ssl_credentials_create(
       c_pem_root_certificates, NULL, NULL)
   return credentials
 
@@ -175,7 +172,7 @@ def channel_credentials_composite(
   if not credentials_1.is_valid or not credentials_2.is_valid:
     raise ValueError("passed credentials must both be valid")
   cdef ChannelCredentials credentials = ChannelCredentials()
-  credentials.c_credentials = grpc.grpc_composite_channel_credentials_create(
+  credentials.c_credentials = grpc_composite_channel_credentials_create(
       credentials_1.c_credentials, credentials_2.c_credentials, NULL)
   credentials.references.append(credentials_1)
   credentials.references.append(credentials_2)
@@ -187,7 +184,7 @@ def call_credentials_composite(
   if not credentials_1.is_valid or not credentials_2.is_valid:
     raise ValueError("passed credentials must both be valid")
   cdef CallCredentials credentials = CallCredentials()
-  credentials.c_credentials = grpc.grpc_composite_call_credentials_create(
+  credentials.c_credentials = grpc_composite_call_credentials_create(
       credentials_1.c_credentials, credentials_2.c_credentials, NULL)
   credentials.references.append(credentials_1)
   credentials.references.append(credentials_2)
@@ -196,11 +193,11 @@ def call_credentials_composite(
 def call_credentials_google_compute_engine():
   cdef CallCredentials credentials = CallCredentials()
   credentials.c_credentials = (
-      grpc.grpc_google_compute_engine_credentials_create(NULL))
+      grpc_google_compute_engine_credentials_create(NULL))
   return credentials
 
 def call_credentials_service_account_jwt_access(
-    json_key, records.Timespec token_lifetime not None):
+    json_key, Timespec token_lifetime not None):
   if isinstance(json_key, bytes):
     pass
   elif isinstance(json_key, basestring):
@@ -209,7 +206,7 @@ def call_credentials_service_account_jwt_access(
     raise TypeError("expected json_key to be str or bytes")
   cdef CallCredentials credentials = CallCredentials()
   credentials.c_credentials = (
-      grpc.grpc_service_account_jwt_access_credentials_create(
+      grpc_service_account_jwt_access_credentials_create(
           json_key, token_lifetime.c_time, NULL))
   credentials.references.append(json_key)
   return credentials
@@ -222,7 +219,7 @@ def call_credentials_google_refresh_token(json_refresh_token):
   else:
     raise TypeError("expected json_refresh_token to be str or bytes")
   cdef CallCredentials credentials = CallCredentials()
-  credentials.c_credentials = grpc.grpc_google_refresh_token_credentials_create(
+  credentials.c_credentials = grpc_google_refresh_token_credentials_create(
       json_refresh_token, NULL)
   credentials.references.append(json_refresh_token)
   return credentials
@@ -241,7 +238,7 @@ def call_credentials_google_iam(authorization_token, authority_selector):
   else:
     raise TypeError("expected authority_selector to be str or bytes")
   cdef CallCredentials credentials = CallCredentials()
-  credentials.c_credentials = grpc.grpc_google_iam_credentials_create(
+  credentials.c_credentials = grpc_google_iam_credentials_create(
       authorization_token, authority_selector, NULL)
   credentials.references.append(authorization_token)
   credentials.references.append(authority_selector)
@@ -250,7 +247,7 @@ def call_credentials_google_iam(authorization_token, authority_selector):
 def call_credentials_metadata_plugin(CredentialsMetadataPlugin plugin):
   cdef CallCredentials credentials = CallCredentials()
   credentials.c_credentials = (
-      grpc.grpc_metadata_credentials_create_from_plugin(plugin.make_c_plugin(),
+      grpc_metadata_credentials_create_from_plugin(plugin.make_c_plugin(),
                                                         NULL))
   # TODO(atash): the following held reference is *probably* never necessary
   credentials.references.append(plugin)
@@ -270,22 +267,22 @@ def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs,
     raise TypeError("expected pem_root_certs to be str or bytes")
   pem_key_cert_pairs = list(pem_key_cert_pairs)
   for pair in pem_key_cert_pairs:
-    if not isinstance(pair, records.SslPemKeyCertPair):
+    if not isinstance(pair, SslPemKeyCertPair):
       raise TypeError("expected pem_key_cert_pairs to be sequence of "
-                      "records.SslPemKeyCertPair")
+                      "SslPemKeyCertPair")
   cdef ServerCredentials credentials = ServerCredentials()
   credentials.references.append(pem_key_cert_pairs)
   credentials.references.append(pem_root_certs)
   credentials.c_ssl_pem_key_cert_pairs_count = len(pem_key_cert_pairs)
   credentials.c_ssl_pem_key_cert_pairs = (
-      <grpc.grpc_ssl_pem_key_cert_pair *>grpc.gpr_malloc(
-          sizeof(grpc.grpc_ssl_pem_key_cert_pair) *
+      <grpc_ssl_pem_key_cert_pair *>gpr_malloc(
+          sizeof(grpc_ssl_pem_key_cert_pair) *
               credentials.c_ssl_pem_key_cert_pairs_count
       ))
   for i in range(credentials.c_ssl_pem_key_cert_pairs_count):
     credentials.c_ssl_pem_key_cert_pairs[i] = (
-        (<records.SslPemKeyCertPair>pem_key_cert_pairs[i]).c_pair)
-  credentials.c_credentials = grpc.grpc_ssl_server_credentials_create(
+        (<SslPemKeyCertPair>pem_key_cert_pairs[i]).c_pair)
+  credentials.c_credentials = grpc_ssl_server_credentials_create(
       c_pem_root_certs, credentials.c_ssl_pem_key_cert_pairs,
       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.pxi
similarity index 100%
rename from src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
rename to src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi
similarity index 80%
rename from src/python/grpcio/grpc/_cython/_cygrpc/records.pxd
rename to src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi
index 4c844e4cb6cd8be385a1ff82f168ff63fdb93464..30397818a15a9496552ce3836e0fd7454cd80414 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi
@@ -27,19 +27,15 @@
 # (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 call
-from grpc._cython._cygrpc cimport server
-
 
 cdef class Timespec:
 
-  cdef grpc.gpr_timespec c_time
+  cdef gpr_timespec c_time
 
 
 cdef class CallDetails:
 
-  cdef grpc.grpc_call_details c_details
+  cdef grpc_call_details c_details
 
 
 cdef class OperationTag:
@@ -48,8 +44,8 @@ cdef class OperationTag:
   cdef list references
   # This allows CompletionQueue to notify the Python Server object that the
   # underlying GRPC core server has shutdown
-  cdef server.Server shutting_down_server
-  cdef call.Call operation_call
+  cdef Server shutting_down_server
+  cdef Call operation_call
   cdef CallDetails request_call_details
   cdef Metadata request_metadata
   cdef Operations batch_operations
@@ -58,12 +54,12 @@ cdef class OperationTag:
 
 cdef class Event:
 
-  cdef readonly grpc.grpc_completion_type type
+  cdef readonly grpc_completion_type type
   cdef readonly bint success
   cdef readonly object tag
 
   # For operations with calls
-  cdef readonly call.Call operation_call
+  cdef readonly Call operation_call
 
   # For Server.request_call
   cdef readonly bint is_new_request
@@ -76,45 +72,45 @@ cdef class Event:
 
 cdef class ByteBuffer:
 
-  cdef grpc.grpc_byte_buffer *c_byte_buffer
+  cdef grpc_byte_buffer *c_byte_buffer
 
 
 cdef class SslPemKeyCertPair:
 
-  cdef grpc.grpc_ssl_pem_key_cert_pair c_pair
+  cdef grpc_ssl_pem_key_cert_pair c_pair
   cdef readonly object private_key, certificate_chain
 
 
 cdef class ChannelArg:
 
-  cdef grpc.grpc_arg c_arg
+  cdef grpc_arg c_arg
   cdef readonly object key, value
 
 
 cdef class ChannelArgs:
 
-  cdef grpc.grpc_channel_args c_args
+  cdef grpc_channel_args c_args
   cdef list args
 
 
 cdef class Metadatum:
 
-  cdef grpc.grpc_metadata c_metadata
+  cdef grpc_metadata c_metadata
   cdef object _key, _value
 
 
 cdef class Metadata:
 
-  cdef grpc.grpc_metadata_array c_metadata_array
+  cdef grpc_metadata_array c_metadata_array
   cdef object metadata
 
 
 cdef class Operation:
 
-  cdef grpc.grpc_op c_op
+  cdef grpc_op c_op
   cdef ByteBuffer _received_message
   cdef Metadata _received_metadata
-  cdef grpc.grpc_status_code _received_status_code
+  cdef grpc_status_code _received_status_code
   cdef char *_received_status_details
   cdef size_t _received_status_details_capacity
   cdef int _received_cancelled
@@ -124,7 +120,7 @@ cdef class Operation:
 
 cdef class Operations:
 
-  cdef grpc.grpc_op *c_ops
+  cdef grpc_op *c_ops
   cdef size_t c_nops
   cdef list operations
 
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
similarity index 70%
rename from src/python/grpcio/grpc/_cython/_cygrpc/records.pyx
rename to src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
index 79a7f8f563b8812c0f886c63689f21a328563c40..d7ad9e5215bdfb98697df0cbf6af89e9f0bef95f 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
@@ -27,103 +27,99 @@
 # (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 call
-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
+  idle = GRPC_CHANNEL_IDLE
+  connecting = GRPC_CHANNEL_CONNECTING
+  ready = GRPC_CHANNEL_READY
+  transient_failure = GRPC_CHANNEL_TRANSIENT_FAILURE
+  fatal_failure = 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
-  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
+  enable_census = GRPC_ARG_ENABLE_CENSUS
+  max_concurrent_streams = GRPC_ARG_MAX_CONCURRENT_STREAMS
+  max_message_length = GRPC_ARG_MAX_MESSAGE_LENGTH
+  http2_initial_sequence_number = GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER
+  default_authority = GRPC_ARG_DEFAULT_AUTHORITY
+  primary_user_agent_string = GRPC_ARG_PRIMARY_USER_AGENT_STRING
+  secondary_user_agent_string = GRPC_ARG_SECONDARY_USER_AGENT_STRING
+  ssl_target_name_override = GRPC_SSL_TARGET_NAME_OVERRIDE_ARG
 
 
 class WriteFlag:
-  buffer_hint = grpc.GRPC_WRITE_BUFFER_HINT
-  no_compress = grpc.GRPC_WRITE_NO_COMPRESS
+  buffer_hint = GRPC_WRITE_BUFFER_HINT
+  no_compress = GRPC_WRITE_NO_COMPRESS
 
 
 class StatusCode:
-  ok = grpc.GRPC_STATUS_OK
-  cancelled = grpc.GRPC_STATUS_CANCELLED
-  unknown = grpc.GRPC_STATUS_UNKNOWN
-  invalid_argument = grpc.GRPC_STATUS_INVALID_ARGUMENT
-  deadline_exceeded = grpc.GRPC_STATUS_DEADLINE_EXCEEDED
-  not_found = grpc.GRPC_STATUS_NOT_FOUND
-  already_exists = grpc.GRPC_STATUS_ALREADY_EXISTS
-  permission_denied = grpc.GRPC_STATUS_PERMISSION_DENIED
-  unauthenticated = grpc.GRPC_STATUS_UNAUTHENTICATED
-  resource_exhausted = grpc.GRPC_STATUS_RESOURCE_EXHAUSTED
-  failed_precondition = grpc.GRPC_STATUS_FAILED_PRECONDITION
-  aborted = grpc.GRPC_STATUS_ABORTED
-  out_of_range = grpc.GRPC_STATUS_OUT_OF_RANGE
-  unimplemented = grpc.GRPC_STATUS_UNIMPLEMENTED
-  internal = grpc.GRPC_STATUS_INTERNAL
-  unavailable = grpc.GRPC_STATUS_UNAVAILABLE
-  data_loss = grpc.GRPC_STATUS_DATA_LOSS
+  ok = GRPC_STATUS_OK
+  cancelled = GRPC_STATUS_CANCELLED
+  unknown = GRPC_STATUS_UNKNOWN
+  invalid_argument = GRPC_STATUS_INVALID_ARGUMENT
+  deadline_exceeded = GRPC_STATUS_DEADLINE_EXCEEDED
+  not_found = GRPC_STATUS_NOT_FOUND
+  already_exists = GRPC_STATUS_ALREADY_EXISTS
+  permission_denied = GRPC_STATUS_PERMISSION_DENIED
+  unauthenticated = GRPC_STATUS_UNAUTHENTICATED
+  resource_exhausted = GRPC_STATUS_RESOURCE_EXHAUSTED
+  failed_precondition = GRPC_STATUS_FAILED_PRECONDITION
+  aborted = GRPC_STATUS_ABORTED
+  out_of_range = GRPC_STATUS_OUT_OF_RANGE
+  unimplemented = GRPC_STATUS_UNIMPLEMENTED
+  internal = GRPC_STATUS_INTERNAL
+  unavailable = GRPC_STATUS_UNAVAILABLE
+  data_loss = GRPC_STATUS_DATA_LOSS
 
 
 class CallError:
-  ok = grpc.GRPC_CALL_OK
-  error = grpc.GRPC_CALL_ERROR
-  not_on_server = grpc.GRPC_CALL_ERROR_NOT_ON_SERVER
-  not_on_client = grpc.GRPC_CALL_ERROR_NOT_ON_CLIENT
-  already_accepted = grpc.GRPC_CALL_ERROR_ALREADY_ACCEPTED
-  already_invoked = grpc.GRPC_CALL_ERROR_ALREADY_INVOKED
-  not_invoked = grpc.GRPC_CALL_ERROR_NOT_INVOKED
-  already_finished = grpc.GRPC_CALL_ERROR_ALREADY_FINISHED
-  too_many_operations = grpc.GRPC_CALL_ERROR_TOO_MANY_OPERATIONS
-  invalid_flags = grpc.GRPC_CALL_ERROR_INVALID_FLAGS
-  invalid_metadata = grpc.GRPC_CALL_ERROR_INVALID_METADATA
+  ok = GRPC_CALL_OK
+  error = GRPC_CALL_ERROR
+  not_on_server = GRPC_CALL_ERROR_NOT_ON_SERVER
+  not_on_client = GRPC_CALL_ERROR_NOT_ON_CLIENT
+  already_accepted = GRPC_CALL_ERROR_ALREADY_ACCEPTED
+  already_invoked = GRPC_CALL_ERROR_ALREADY_INVOKED
+  not_invoked = GRPC_CALL_ERROR_NOT_INVOKED
+  already_finished = GRPC_CALL_ERROR_ALREADY_FINISHED
+  too_many_operations = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS
+  invalid_flags = GRPC_CALL_ERROR_INVALID_FLAGS
+  invalid_metadata = GRPC_CALL_ERROR_INVALID_METADATA
 
 
 class CompletionType:
-  queue_shutdown = grpc.GRPC_QUEUE_SHUTDOWN
-  queue_timeout = grpc.GRPC_QUEUE_TIMEOUT
-  operation_complete = grpc.GRPC_OP_COMPLETE
+  queue_shutdown = GRPC_QUEUE_SHUTDOWN
+  queue_timeout = GRPC_QUEUE_TIMEOUT
+  operation_complete = GRPC_OP_COMPLETE
 
 
 class OperationType:
-  send_initial_metadata = grpc.GRPC_OP_SEND_INITIAL_METADATA
-  send_message = grpc.GRPC_OP_SEND_MESSAGE
-  send_close_from_client = grpc.GRPC_OP_SEND_CLOSE_FROM_CLIENT
-  send_status_from_server = grpc.GRPC_OP_SEND_STATUS_FROM_SERVER
-  receive_initial_metadata = grpc.GRPC_OP_RECV_INITIAL_METADATA
-  receive_message = grpc.GRPC_OP_RECV_MESSAGE
-  receive_status_on_client = grpc.GRPC_OP_RECV_STATUS_ON_CLIENT
-  receive_close_on_server = grpc.GRPC_OP_RECV_CLOSE_ON_SERVER
+  send_initial_metadata = GRPC_OP_SEND_INITIAL_METADATA
+  send_message = GRPC_OP_SEND_MESSAGE
+  send_close_from_client = GRPC_OP_SEND_CLOSE_FROM_CLIENT
+  send_status_from_server = GRPC_OP_SEND_STATUS_FROM_SERVER
+  receive_initial_metadata = GRPC_OP_RECV_INITIAL_METADATA
+  receive_message = GRPC_OP_RECV_MESSAGE
+  receive_status_on_client = GRPC_OP_RECV_STATUS_ON_CLIENT
+  receive_close_on_server = GRPC_OP_RECV_CLOSE_ON_SERVER
 
 
 cdef class Timespec:
 
   def __cinit__(self, time):
     if time is None:
-      self.c_time = grpc.gpr_now(grpc.GPR_CLOCK_REALTIME)
+      self.c_time = gpr_now(GPR_CLOCK_REALTIME)
       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)
+        self.c_time = gpr_inf_future(GPR_CLOCK_REALTIME)
       elif time == float("-inf"):
-        self.c_time = grpc.gpr_inf_past(grpc.GPR_CLOCK_REALTIME)
+        self.c_time = gpr_inf_past(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
+        self.c_time.clock_type = GPR_CLOCK_REALTIME
     elif isinstance(time, Timespec):
       self.c_time = (<Timespec>time).c_time
     else:
@@ -135,19 +131,19 @@ cdef class Timespec:
     # 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))
+    cdef gpr_timespec real_time = (
+        gpr_convert_clock_type(self.c_time, GPR_CLOCK_REALTIME))
     return real_time.seconds
 
   @property
   def nanoseconds(self):
-    cdef grpc.gpr_timespec real_time = (
-        grpc.gpr_convert_clock_type(self.c_time, grpc.GPR_CLOCK_REALTIME))
+    cdef gpr_timespec real_time = (
+        gpr_convert_clock_type(self.c_time, GPR_CLOCK_REALTIME))
     return real_time.nanoseconds
 
   def __float__(self):
-    cdef grpc.gpr_timespec real_time = (
-        grpc.gpr_convert_clock_type(self.c_time, grpc.GPR_CLOCK_REALTIME))
+    cdef gpr_timespec real_time = (
+        gpr_convert_clock_type(self.c_time, GPR_CLOCK_REALTIME))
     return <double>real_time.seconds + <double>real_time.nanoseconds / 1e9
 
   infinite_future = Timespec(float("+inf"))
@@ -157,10 +153,10 @@ cdef class Timespec:
 cdef class CallDetails:
 
   def __cinit__(self):
-    grpc.grpc_call_details_init(&self.c_details)
+    grpc_call_details_init(&self.c_details)
 
   def __dealloc__(self):
-    grpc.grpc_call_details_destroy(&self.c_details)
+    grpc_call_details_destroy(&self.c_details)
 
   @property
   def method(self):
@@ -192,8 +188,8 @@ cdef class OperationTag:
 
 cdef class Event:
 
-  def __cinit__(self, grpc.grpc_completion_type type, bint success,
-                object tag, call.Call operation_call,
+  def __cinit__(self, grpc_completion_type type, bint success,
+                object tag, Call operation_call,
                 CallDetails request_call_details,
                 Metadata request_metadata,
                 bint is_new_request,
@@ -228,31 +224,31 @@ cdef class ByteBuffer:
                       "ByteBuffer, not {}".format(type(data)))
 
     cdef char *c_data = data
-    data_slice = grpc.gpr_slice_from_copied_buffer(c_data, len(data))
-    self.c_byte_buffer = grpc.grpc_raw_byte_buffer_create(
+    data_slice = gpr_slice_from_copied_buffer(c_data, len(data))
+    self.c_byte_buffer = grpc_raw_byte_buffer_create(
         &data_slice, 1)
-    grpc.gpr_slice_unref(data_slice)
+    gpr_slice_unref(data_slice)
 
   def bytes(self):
-    cdef grpc.grpc_byte_buffer_reader reader
-    cdef grpc.gpr_slice data_slice
+    cdef grpc_byte_buffer_reader reader
+    cdef gpr_slice data_slice
     cdef size_t data_slice_length
     cdef void *data_slice_pointer
     if self.c_byte_buffer != NULL:
-      grpc.grpc_byte_buffer_reader_init(&reader, self.c_byte_buffer)
+      grpc_byte_buffer_reader_init(&reader, self.c_byte_buffer)
       result = b""
-      while grpc.grpc_byte_buffer_reader_next(&reader, &data_slice):
-        data_slice_pointer = grpc.gpr_slice_start_ptr(data_slice)
-        data_slice_length = grpc.gpr_slice_length(data_slice)
+      while grpc_byte_buffer_reader_next(&reader, &data_slice):
+        data_slice_pointer = gpr_slice_start_ptr(data_slice)
+        data_slice_length = gpr_slice_length(data_slice)
         result += (<char *>data_slice_pointer)[:data_slice_length]
-      grpc.grpc_byte_buffer_reader_destroy(&reader)
+      grpc_byte_buffer_reader_destroy(&reader)
       return result
     else:
       return None
 
   def __len__(self):
     if self.c_byte_buffer != NULL:
-      return grpc.grpc_byte_buffer_length(self.c_byte_buffer)
+      return grpc_byte_buffer_length(self.c_byte_buffer)
     else:
       return 0
 
@@ -261,7 +257,7 @@ cdef class ByteBuffer:
 
   def __dealloc__(self):
     if self.c_byte_buffer != NULL:
-      grpc.grpc_byte_buffer_destroy(self.c_byte_buffer)
+      grpc_byte_buffer_destroy(self.c_byte_buffer)
 
 
 cdef class SslPemKeyCertPair:
@@ -295,15 +291,15 @@ cdef class ChannelArg:
       raise TypeError("expected key to be of type str or bytes")
     if isinstance(value, bytes):
       self.value = value
-      self.c_arg.type = grpc.GRPC_ARG_STRING
+      self.c_arg.type = GRPC_ARG_STRING
       self.c_arg.value.string = self.value
     elif isinstance(value, basestring):
       self.value = value.encode()
-      self.c_arg.type = grpc.GRPC_ARG_STRING
+      self.c_arg.type = GRPC_ARG_STRING
       self.c_arg.value.string = self.value
     elif isinstance(value, int):
       self.value = int(value)
-      self.c_arg.type = grpc.GRPC_ARG_INTEGER
+      self.c_arg.type = GRPC_ARG_INTEGER
       self.c_arg.value.integer = self.value
     else:
       raise TypeError("expected value to be of type str or bytes or int")
@@ -318,14 +314,14 @@ cdef class ChannelArgs:
       if not isinstance(arg, ChannelArg):
         raise TypeError("expected list of ChannelArg")
     self.c_args.arguments_length = len(self.args)
-    self.c_args.arguments = <grpc.grpc_arg *>grpc.gpr_malloc(
-        self.c_args.arguments_length*sizeof(grpc.grpc_arg)
+    self.c_args.arguments = <grpc_arg *>gpr_malloc(
+        self.c_args.arguments_length*sizeof(grpc_arg)
     )
     for i in range(self.c_args.arguments_length):
       self.c_args.arguments[i] = (<ChannelArg>self.args[i]).c_arg
 
   def __dealloc__(self):
-    grpc.gpr_free(self.c_args.arguments)
+    gpr_free(self.c_args.arguments)
 
   def __len__(self):
     # self.args is never stale; it's only updated from this file
@@ -406,11 +402,11 @@ cdef class Metadata:
     for metadatum in metadata:
       if not isinstance(metadatum, Metadatum):
         raise TypeError("expected list of Metadatum")
-    grpc.grpc_metadata_array_init(&self.c_metadata_array)
+    grpc_metadata_array_init(&self.c_metadata_array)
     self.c_metadata_array.count = len(self.metadata)
     self.c_metadata_array.capacity = len(self.metadata)
-    self.c_metadata_array.metadata = <grpc.grpc_metadata *>grpc.gpr_malloc(
-        self.c_metadata_array.count*sizeof(grpc.grpc_metadata)
+    self.c_metadata_array.metadata = <grpc_metadata *>gpr_malloc(
+        self.c_metadata_array.count*sizeof(grpc_metadata)
     )
     for i in range(self.c_metadata_array.count):
       self.c_metadata_array.metadata[i] = (
@@ -420,7 +416,7 @@ cdef class Metadata:
     # this frees the allocated memory for the grpc_metadata_array (although
     # it'd be nice if that were documented somewhere...) TODO(atash): document
     # this in the C core
-    grpc.grpc_metadata_array_destroy(&self.c_metadata_array)
+    grpc_metadata_array_destroy(&self.c_metadata_array)
 
   def __len__(self):
     return self.c_metadata_array.count
@@ -449,49 +445,49 @@ cdef class Operation:
 
   @property
   def has_status(self):
-    return self.c_op.type == grpc.GRPC_OP_RECV_STATUS_ON_CLIENT
+    return self.c_op.type == GRPC_OP_RECV_STATUS_ON_CLIENT
 
   @property
   def received_message(self):
-    if self.c_op.type != grpc.GRPC_OP_RECV_MESSAGE:
+    if self.c_op.type != 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:
+    if self.c_op.type != 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):
+    if (self.c_op.type != GRPC_OP_RECV_INITIAL_METADATA and
+        self.c_op.type != GRPC_OP_RECV_STATUS_ON_CLIENT):
       raise TypeError("self must be an operation receiving metadata")
     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):
+    if (self.c_op.type != GRPC_OP_RECV_INITIAL_METADATA and
+        self.c_op.type != 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:
+    if self.c_op.type != 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:
+    if self.c_op.type != 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:
+    if self.c_op.type != GRPC_OP_RECV_STATUS_ON_CLIENT:
       raise TypeError("self must be an operation receiving status details")
     if self._received_status_details:
       return self._received_status_details
@@ -500,7 +496,7 @@ cdef class Operation:
 
   @property
   def received_status_details_or_none(self):
-    if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
+    if self.c_op.type != GRPC_OP_RECV_STATUS_ON_CLIENT:
       return None
     if self._received_status_details:
       return self._received_status_details
@@ -509,14 +505,14 @@ cdef class Operation:
 
   @property
   def received_cancelled(self):
-    if self.c_op.type != grpc.GRPC_OP_RECV_CLOSE_ON_SERVER:
+    if self.c_op.type != 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:
+    if self.c_op.type != GRPC_OP_RECV_CLOSE_ON_SERVER:
       return None
     return False if self._received_cancelled == 0 else True
 
@@ -524,12 +520,12 @@ cdef class Operation:
     # 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.
     # This means that we need to clean up after receive_status_on_client.
-    if self.c_op.type == grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
-      grpc.gpr_free(self._received_status_details)
+    if self.c_op.type == GRPC_OP_RECV_STATUS_ON_CLIENT:
+      gpr_free(self._received_status_details)
 
 def operation_send_initial_metadata(Metadata metadata):
   cdef Operation op = Operation()
-  op.c_op.type = grpc.GRPC_OP_SEND_INITIAL_METADATA
+  op.c_op.type = GRPC_OP_SEND_INITIAL_METADATA
   op.c_op.data.send_initial_metadata.count = metadata.c_metadata_array.count
   op.c_op.data.send_initial_metadata.metadata = (
       metadata.c_metadata_array.metadata)
@@ -539,7 +535,7 @@ def operation_send_initial_metadata(Metadata metadata):
 
 def operation_send_message(data):
   cdef Operation op = Operation()
-  op.c_op.type = grpc.GRPC_OP_SEND_MESSAGE
+  op.c_op.type = GRPC_OP_SEND_MESSAGE
   byte_buffer = ByteBuffer(data)
   op.c_op.data.send_message = byte_buffer.c_byte_buffer
   op.references.append(byte_buffer)
@@ -548,12 +544,12 @@ def operation_send_message(data):
 
 def operation_send_close_from_client():
   cdef Operation op = Operation()
-  op.c_op.type = grpc.GRPC_OP_SEND_CLOSE_FROM_CLIENT
+  op.c_op.type = GRPC_OP_SEND_CLOSE_FROM_CLIENT
   op.is_valid = True
   return op
 
 def operation_send_status_from_server(
-    Metadata metadata, grpc.grpc_status_code code, details):
+    Metadata metadata, grpc_status_code code, details):
   if isinstance(details, bytes):
     pass
   elif isinstance(details, basestring):
@@ -561,7 +557,7 @@ def operation_send_status_from_server(
   else:
     raise TypeError("expected a str or bytes object for details")
   cdef Operation op = Operation()
-  op.c_op.type = grpc.GRPC_OP_SEND_STATUS_FROM_SERVER
+  op.c_op.type = GRPC_OP_SEND_STATUS_FROM_SERVER
   op.c_op.data.send_status_from_server.trailing_metadata_count = (
       metadata.c_metadata_array.count)
   op.c_op.data.send_status_from_server.trailing_metadata = (
@@ -575,7 +571,7 @@ def operation_send_status_from_server(
 
 def operation_receive_initial_metadata():
   cdef Operation op = Operation()
-  op.c_op.type = grpc.GRPC_OP_RECV_INITIAL_METADATA
+  op.c_op.type = GRPC_OP_RECV_INITIAL_METADATA
   op._received_metadata = Metadata([])
   op.c_op.data.receive_initial_metadata = (
       &op._received_metadata.c_metadata_array)
@@ -584,7 +580,7 @@ def operation_receive_initial_metadata():
 
 def operation_receive_message():
   cdef Operation op = Operation()
-  op.c_op.type = grpc.GRPC_OP_RECV_MESSAGE
+  op.c_op.type = GRPC_OP_RECV_MESSAGE
   op._received_message = ByteBuffer(None)
   # n.b. the c_op.data.receive_message field needs to be deleted by us,
   # anyway, so we just let that be handled by the ByteBuffer() we allocated
@@ -595,7 +591,7 @@ def operation_receive_message():
 
 def operation_receive_status_on_client():
   cdef Operation op = Operation()
-  op.c_op.type = grpc.GRPC_OP_RECV_STATUS_ON_CLIENT
+  op.c_op.type = GRPC_OP_RECV_STATUS_ON_CLIENT
   op._received_metadata = Metadata([])
   op.c_op.data.receive_status_on_client.trailing_metadata = (
       &op._received_metadata.c_metadata_array)
@@ -610,7 +606,7 @@ def operation_receive_status_on_client():
 
 def operation_receive_close_on_server():
   cdef Operation op = Operation()
-  op.c_op.type = grpc.GRPC_OP_RECV_CLOSE_ON_SERVER
+  op.c_op.type = GRPC_OP_RECV_CLOSE_ON_SERVER
   op.c_op.data.receive_close_on_server.cancelled = &op._received_cancelled
   op.is_valid = True
   return op
@@ -647,8 +643,8 @@ cdef class Operations:
       if not isinstance(operation, Operation):
         raise TypeError("expected operations to be iterable of Operation")
     self.c_nops = len(self.operations)
-    self.c_ops = <grpc.grpc_op *>grpc.gpr_malloc(
-        sizeof(grpc.grpc_op)*self.c_nops)
+    self.c_ops = <grpc_op *>gpr_malloc(
+        sizeof(grpc_op)*self.c_nops)
     for i in range(self.c_nops):
       self.c_ops[i] = (<Operation>(self.operations[i])).c_op
 
@@ -660,7 +656,7 @@ cdef class Operations:
     return self.operations[i]
 
   def __dealloc__(self):
-    grpc.gpr_free(self.c_ops)
+    gpr_free(self.c_ops)
 
   def __iter__(self):
     return _OperationsIterator(self)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/server.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/server.pxd.pxi
similarity index 90%
rename from src/python/grpcio/grpc/_cython/_cygrpc/server.pxd
rename to src/python/grpcio/grpc/_cython/_cygrpc/server.pxd.pxi
index 0257542a037713a0a47135c8fe89010866343e03..9db49e4d307ae9f932836470b6448eb3a77b229c 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pxd.pxi
@@ -27,18 +27,15 @@
 # (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 completion_queue
-
 
 cdef class Server:
 
-  cdef grpc.grpc_server *c_server
+  cdef grpc_server *c_server
   cdef bint is_started  # start has been called
   cdef bint is_shutting_down  # shutdown has been called
   cdef bint is_shutdown  # notification of complete shutdown received
   # used at dealloc when user forgets to shutdown
-  cdef completion_queue.CompletionQueue backup_shutdown_queue
+  cdef CompletionQueue backup_shutdown_queue
   cdef list references
   cdef list registered_completion_queues
 
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
similarity index 75%
rename from src/python/grpcio/grpc/_cython/_cygrpc/server.pyx
rename to src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
index b0bafbc1f49158e415e2ab7854c3c75dfca4eeeb..8b65935c3b9394c0f2d57bb4c7bb3eca39c9b82f 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
@@ -29,45 +29,39 @@
 
 cimport cpython
 
-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
 
 
 cdef class Server:
 
-  def __cinit__(self, records.ChannelArgs arguments=None):
-    cdef grpc.grpc_channel_args *c_arguments = NULL
+  def __cinit__(self, ChannelArgs arguments=None):
+    cdef grpc_channel_args *c_arguments = NULL
     self.references = []
     self.registered_completion_queues = []
     if arguments is not None:
       c_arguments = &arguments.c_args
       self.references.append(arguments)
-    self.c_server = grpc.grpc_server_create(c_arguments, NULL)
+    self.c_server = grpc_server_create(c_arguments, NULL)
     self.is_started = False
     self.is_shutting_down = False
     self.is_shutdown = False
 
   def request_call(
-      self, completion_queue.CompletionQueue call_queue not None,
-      completion_queue.CompletionQueue server_queue not None, tag):
+      self, CompletionQueue call_queue not None,
+      CompletionQueue server_queue not None, tag):
     if not self.is_started or self.is_shutting_down:
       raise ValueError("server must be started and not shutting down")
     if server_queue not in self.registered_completion_queues:
       raise ValueError("server_queue must be a registered completion queue")
-    cdef records.OperationTag operation_tag = records.OperationTag(tag)
-    operation_tag.operation_call = call.Call()
-    operation_tag.request_call_details = records.CallDetails()
-    operation_tag.request_metadata = records.Metadata([])
+    cdef OperationTag operation_tag = OperationTag(tag)
+    operation_tag.operation_call = Call()
+    operation_tag.request_call_details = CallDetails()
+    operation_tag.request_metadata = Metadata([])
     operation_tag.references.extend([self, call_queue, server_queue])
     operation_tag.is_new_request = True
-    operation_tag.batch_operations = records.Operations([])
+    operation_tag.batch_operations = Operations([])
     cpython.Py_INCREF(operation_tag)
-    return grpc.grpc_server_request_call(
+    return grpc_server_request_call(
         self.c_server, &operation_tag.operation_call.c_call,
         &operation_tag.request_call_details.c_details,
         &operation_tag.request_metadata.c_metadata_array,
@@ -75,25 +69,25 @@ cdef class Server:
         <cpython.PyObject *>operation_tag)
 
   def register_completion_queue(
-      self, completion_queue.CompletionQueue queue not None):
+      self, CompletionQueue queue not None):
     if self.is_started:
       raise ValueError("cannot register completion queues after start")
-    grpc.grpc_server_register_completion_queue(
+    grpc_server_register_completion_queue(
         self.c_server, queue.c_completion_queue, NULL)
     self.registered_completion_queues.append(queue)
 
   def start(self):
     if self.is_started:
       raise ValueError("the server has already started")
-    self.backup_shutdown_queue = completion_queue.CompletionQueue()
+    self.backup_shutdown_queue = CompletionQueue()
     self.register_completion_queue(self.backup_shutdown_queue)
     self.is_started = True
-    grpc.grpc_server_start(self.c_server)
+    grpc_server_start(self.c_server)
     # Ensure the core has gotten a chance to do the start-up work
-    self.backup_shutdown_queue.pluck(None, records.Timespec(None))
+    self.backup_shutdown_queue.pluck(None, Timespec(None))
 
   def add_http2_port(self, address,
-                     credentials.ServerCredentials server_credentials=None):
+                     ServerCredentials server_credentials=None):
     if isinstance(address, bytes):
       pass
     elif isinstance(address, basestring):
@@ -103,13 +97,13 @@ cdef class Server:
     self.references.append(address)
     if server_credentials is not None:
       self.references.append(server_credentials)
-      return grpc.grpc_server_add_secure_http2_port(
+      return grpc_server_add_secure_http2_port(
           self.c_server, address, server_credentials.c_credentials)
     else:
-      return grpc.grpc_server_add_insecure_http2_port(self.c_server, address)
+      return 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
+  def shutdown(self, CompletionQueue queue not None, tag):
+    cdef OperationTag operation_tag
     if queue.is_shutting_down:
       raise ValueError("queue must be live")
     elif not self.is_started:
@@ -120,11 +114,11 @@ cdef class Server:
       raise ValueError("expected registered completion queue")
     else:
       self.is_shutting_down = True
-      operation_tag = records.OperationTag(tag)
+      operation_tag = OperationTag(tag)
       operation_tag.shutting_down_server = self
       operation_tag.references.extend([self, queue])
       cpython.Py_INCREF(operation_tag)
-      grpc.grpc_server_shutdown_and_notify(
+      grpc_server_shutdown_and_notify(
           self.c_server, queue.c_completion_queue,
           <cpython.PyObject *>operation_tag)
 
@@ -138,7 +132,7 @@ cdef class Server:
     elif self.is_shutdown:
       return
     else:
-      grpc.grpc_server_cancel_all_calls(self.c_server)
+      grpc_server_cancel_all_calls(self.c_server)
 
   def __dealloc__(self):
     if self.c_server != NULL:
@@ -157,5 +151,5 @@ cdef class Server:
         # much but repeatedly release the GIL and wait
         while not self.is_shutdown:
           time.sleep(0)
-      grpc.grpc_server_destroy(self.c_server)
+      grpc_server_destroy(self.c_server)
 
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pxd b/src/python/grpcio/grpc/_cython/cygrpc.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..f22346c4f3bfc2131549675b3f33044bb147881c
--- /dev/null
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pxd
@@ -0,0 +1,37 @@
+# Copyright 2015-2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include "grpc/_cython/_cygrpc/grpc.pxi"
+
+include "grpc/_cython/_cygrpc/call.pxd.pxi"
+include "grpc/_cython/_cygrpc/channel.pxd.pxi"
+include "grpc/_cython/_cygrpc/credentials.pxd.pxi"
+include "grpc/_cython/_cygrpc/completion_queue.pxd.pxi"
+include "grpc/_cython/_cygrpc/records.pxd.pxi"
+include "grpc/_cython/_cygrpc/server.pxd.pxi"
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx
index 16ec12dac0d9510f50f22aac8242a88206acf93b..297c8001c5e2f36b08ae62cd24a088d3401f873b 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pyx
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx
@@ -29,78 +29,14 @@
 
 cimport cpython
 
-from grpc._cython._cygrpc cimport grpc
-from grpc._cython._cygrpc cimport call
-from grpc._cython._cygrpc cimport channel
-from grpc._cython._cygrpc cimport credentials
-from grpc._cython._cygrpc cimport completion_queue
-from grpc._cython._cygrpc cimport records
-from grpc._cython._cygrpc cimport server
-
-from grpc._cython._cygrpc import call
-from grpc._cython._cygrpc import channel
-from grpc._cython._cygrpc import credentials
-from grpc._cython._cygrpc import completion_queue
-from grpc._cython._cygrpc import records
-from grpc._cython._cygrpc import server
-
-ConnectivityState = records.ConnectivityState
-ChannelArgKey = records.ChannelArgKey
-WriteFlag = records.WriteFlag
-StatusCode = records.StatusCode
-CallError = records.CallError
-CompletionType = records.CompletionType
-OperationType = records.OperationType
-Timespec = records.Timespec
-CallDetails = records.CallDetails
-Event = records.Event
-ByteBuffer = records.ByteBuffer
-SslPemKeyCertPair = records.SslPemKeyCertPair
-ChannelArg = records.ChannelArg
-ChannelArgs = records.ChannelArgs
-Metadatum = records.Metadatum
-Metadata = records.Metadata
-Operation = records.Operation
-
-operation_send_initial_metadata = records.operation_send_initial_metadata
-operation_send_message = records.operation_send_message
-operation_send_close_from_client = records.operation_send_close_from_client
-operation_send_status_from_server = records.operation_send_status_from_server
-operation_receive_initial_metadata = records.operation_receive_initial_metadata
-operation_receive_message = records.operation_receive_message
-operation_receive_status_on_client = records.operation_receive_status_on_client
-operation_receive_close_on_server = records.operation_receive_close_on_server
-
-Operations = records.Operations
-
-CallCredentials = credentials.CallCredentials
-ChannelCredentials = credentials.ChannelCredentials
-ServerCredentials = credentials.ServerCredentials
-CredentialsMetadataPlugin = credentials.CredentialsMetadataPlugin
-AuthMetadataContext = credentials.AuthMetadataContext
-
-channel_credentials_google_default = (
-    credentials.channel_credentials_google_default)
-channel_credentials_ssl = credentials.channel_credentials_ssl
-channel_credentials_composite = (
-    credentials.channel_credentials_composite)
-call_credentials_composite = (
-    credentials.call_credentials_composite)
-call_credentials_google_compute_engine = (
-    credentials.call_credentials_google_compute_engine)
-call_credentials_jwt_access = (
-    credentials.call_credentials_service_account_jwt_access)
-call_credentials_refresh_token = (
-    credentials.call_credentials_google_refresh_token)
-call_credentials_google_iam = credentials.call_credentials_google_iam
-call_credentials_metadata_plugin = credentials.call_credentials_metadata_plugin
-server_credentials_ssl = credentials.server_credentials_ssl
-
-CompletionQueue = completion_queue.CompletionQueue
-Channel = channel.Channel
-Server = server.Server
-Call = call.Call
-
+# TODO(atash): figure out why the coverage tool gets confused about the Cython
+# coverage plugin when the following files don't have a '.pxi' suffix.
+include "grpc/_cython/_cygrpc/call.pyx.pxi"
+include "grpc/_cython/_cygrpc/channel.pyx.pxi"
+include "grpc/_cython/_cygrpc/credentials.pyx.pxi"
+include "grpc/_cython/_cygrpc/completion_queue.pyx.pxi"
+include "grpc/_cython/_cygrpc/records.pyx.pxi"
+include "grpc/_cython/_cygrpc/server.pyx.pxi"
 
 #
 # Global state
@@ -109,10 +45,10 @@ Call = call.Call
 cdef class _ModuleState:
 
   def __cinit__(self):
-    grpc.grpc_init()
+    grpc_init()
 
   def __dealloc__(self):
-    grpc.grpc_shutdown()
+    grpc_shutdown()
 
 _module_state = _ModuleState()
 
diff --git a/src/python/grpcio/grpc/framework/interfaces/face/face.py b/src/python/grpcio/grpc/framework/interfaces/face/face.py
index 59da83dc9c34ddc8d2f82351cce3fb0bfdd807ff..404c3a7937aa58b9f958df1bab27977cc85e6128 100644
--- a/src/python/grpcio/grpc/framework/interfaces/face/face.py
+++ b/src/python/grpcio/grpc/framework/interfaces/face/face.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
new file mode 100644
index 0000000000000000000000000000000000000000..63cf0a4c74c36e7b44d57630eb447e75b35df795
--- /dev/null
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -0,0 +1,518 @@
+# Copyright 2015-2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_core_dependencies.py.template`!!!
+
+CORE_SOURCE_FILES = [
+  'src/core/profiling/basic_timers.c',
+  'src/core/profiling/stap_timers.c',
+  'src/core/support/alloc.c',
+  'src/core/support/avl.c',
+  'src/core/support/cmdline.c',
+  'src/core/support/cpu_iphone.c',
+  'src/core/support/cpu_linux.c',
+  'src/core/support/cpu_posix.c',
+  'src/core/support/cpu_windows.c',
+  'src/core/support/env_linux.c',
+  'src/core/support/env_posix.c',
+  'src/core/support/env_win32.c',
+  'src/core/support/file.c',
+  'src/core/support/file_posix.c',
+  'src/core/support/file_win32.c',
+  'src/core/support/histogram.c',
+  'src/core/support/host_port.c',
+  'src/core/support/log.c',
+  'src/core/support/log_android.c',
+  'src/core/support/log_linux.c',
+  'src/core/support/log_posix.c',
+  'src/core/support/log_win32.c',
+  'src/core/support/murmur_hash.c',
+  'src/core/support/slice.c',
+  'src/core/support/slice_buffer.c',
+  'src/core/support/stack_lockfree.c',
+  'src/core/support/string.c',
+  'src/core/support/string_posix.c',
+  'src/core/support/string_win32.c',
+  'src/core/support/subprocess_posix.c',
+  'src/core/support/sync.c',
+  'src/core/support/sync_posix.c',
+  'src/core/support/sync_win32.c',
+  'src/core/support/thd.c',
+  'src/core/support/thd_posix.c',
+  'src/core/support/thd_win32.c',
+  'src/core/support/time.c',
+  'src/core/support/time_posix.c',
+  'src/core/support/time_precise.c',
+  'src/core/support/time_win32.c',
+  'src/core/support/tls_pthread.c',
+  'src/core/httpcli/httpcli_security_connector.c',
+  'src/core/security/base64.c',
+  'src/core/security/client_auth_filter.c',
+  'src/core/security/credentials.c',
+  'src/core/security/credentials_metadata.c',
+  'src/core/security/credentials_posix.c',
+  'src/core/security/credentials_win32.c',
+  'src/core/security/google_default_credentials.c',
+  'src/core/security/handshake.c',
+  'src/core/security/json_token.c',
+  'src/core/security/jwt_verifier.c',
+  'src/core/security/secure_endpoint.c',
+  'src/core/security/security_connector.c',
+  'src/core/security/security_context.c',
+  'src/core/security/server_auth_filter.c',
+  'src/core/security/server_secure_chttp2.c',
+  'src/core/surface/init_secure.c',
+  'src/core/surface/secure_channel_create.c',
+  'src/core/tsi/fake_transport_security.c',
+  'src/core/tsi/ssl_transport_security.c',
+  'src/core/tsi/transport_security.c',
+  'src/core/census/grpc_context.c',
+  'src/core/census/grpc_filter.c',
+  'src/core/channel/channel_args.c',
+  'src/core/channel/channel_stack.c',
+  'src/core/channel/client_channel.c',
+  'src/core/channel/client_uchannel.c',
+  'src/core/channel/compress_filter.c',
+  'src/core/channel/connected_channel.c',
+  'src/core/channel/http_client_filter.c',
+  'src/core/channel/http_server_filter.c',
+  'src/core/channel/subchannel_call_holder.c',
+  'src/core/client_config/client_config.c',
+  'src/core/client_config/connector.c',
+  'src/core/client_config/default_initial_connect_string.c',
+  'src/core/client_config/initial_connect_string.c',
+  'src/core/client_config/lb_policies/pick_first.c',
+  'src/core/client_config/lb_policies/round_robin.c',
+  'src/core/client_config/lb_policy.c',
+  'src/core/client_config/lb_policy_factory.c',
+  'src/core/client_config/lb_policy_registry.c',
+  'src/core/client_config/resolver.c',
+  'src/core/client_config/resolver_factory.c',
+  'src/core/client_config/resolver_registry.c',
+  'src/core/client_config/resolvers/dns_resolver.c',
+  'src/core/client_config/resolvers/sockaddr_resolver.c',
+  'src/core/client_config/subchannel.c',
+  'src/core/client_config/subchannel_factory.c',
+  'src/core/client_config/uri_parser.c',
+  'src/core/compression/algorithm.c',
+  'src/core/compression/message_compress.c',
+  'src/core/debug/trace.c',
+  'src/core/httpcli/format_request.c',
+  'src/core/httpcli/httpcli.c',
+  'src/core/httpcli/parser.c',
+  'src/core/iomgr/closure.c',
+  'src/core/iomgr/endpoint.c',
+  'src/core/iomgr/endpoint_pair_posix.c',
+  'src/core/iomgr/endpoint_pair_windows.c',
+  'src/core/iomgr/exec_ctx.c',
+  'src/core/iomgr/executor.c',
+  'src/core/iomgr/fd_posix.c',
+  'src/core/iomgr/iocp_windows.c',
+  'src/core/iomgr/iomgr.c',
+  'src/core/iomgr/iomgr_posix.c',
+  'src/core/iomgr/iomgr_windows.c',
+  'src/core/iomgr/pollset_multipoller_with_epoll.c',
+  'src/core/iomgr/pollset_multipoller_with_poll_posix.c',
+  'src/core/iomgr/pollset_posix.c',
+  'src/core/iomgr/pollset_set_posix.c',
+  'src/core/iomgr/pollset_set_windows.c',
+  'src/core/iomgr/pollset_windows.c',
+  'src/core/iomgr/resolve_address_posix.c',
+  'src/core/iomgr/resolve_address_windows.c',
+  'src/core/iomgr/sockaddr_utils.c',
+  'src/core/iomgr/socket_utils_common_posix.c',
+  'src/core/iomgr/socket_utils_linux.c',
+  'src/core/iomgr/socket_utils_posix.c',
+  'src/core/iomgr/socket_windows.c',
+  'src/core/iomgr/tcp_client_posix.c',
+  'src/core/iomgr/tcp_client_windows.c',
+  'src/core/iomgr/tcp_posix.c',
+  'src/core/iomgr/tcp_server_posix.c',
+  'src/core/iomgr/tcp_server_windows.c',
+  'src/core/iomgr/tcp_windows.c',
+  'src/core/iomgr/time_averaged_stats.c',
+  'src/core/iomgr/timer.c',
+  'src/core/iomgr/timer_heap.c',
+  'src/core/iomgr/udp_server.c',
+  'src/core/iomgr/wakeup_fd_eventfd.c',
+  'src/core/iomgr/wakeup_fd_nospecial.c',
+  'src/core/iomgr/wakeup_fd_pipe.c',
+  'src/core/iomgr/wakeup_fd_posix.c',
+  'src/core/iomgr/workqueue_posix.c',
+  'src/core/iomgr/workqueue_windows.c',
+  'src/core/json/json.c',
+  'src/core/json/json_reader.c',
+  'src/core/json/json_string.c',
+  'src/core/json/json_writer.c',
+  'src/core/surface/api_trace.c',
+  'src/core/surface/byte_buffer.c',
+  'src/core/surface/byte_buffer_reader.c',
+  'src/core/surface/call.c',
+  'src/core/surface/call_details.c',
+  'src/core/surface/call_log_batch.c',
+  'src/core/surface/channel.c',
+  'src/core/surface/channel_connectivity.c',
+  'src/core/surface/channel_create.c',
+  'src/core/surface/channel_ping.c',
+  'src/core/surface/completion_queue.c',
+  'src/core/surface/event_string.c',
+  'src/core/surface/init.c',
+  'src/core/surface/lame_client.c',
+  'src/core/surface/metadata_array.c',
+  'src/core/surface/server.c',
+  'src/core/surface/server_chttp2.c',
+  'src/core/surface/server_create.c',
+  'src/core/surface/version.c',
+  'src/core/transport/byte_stream.c',
+  'src/core/transport/chttp2/alpn.c',
+  'src/core/transport/chttp2/bin_encoder.c',
+  'src/core/transport/chttp2/frame_data.c',
+  'src/core/transport/chttp2/frame_goaway.c',
+  'src/core/transport/chttp2/frame_ping.c',
+  'src/core/transport/chttp2/frame_rst_stream.c',
+  'src/core/transport/chttp2/frame_settings.c',
+  'src/core/transport/chttp2/frame_window_update.c',
+  'src/core/transport/chttp2/hpack_encoder.c',
+  'src/core/transport/chttp2/hpack_parser.c',
+  'src/core/transport/chttp2/hpack_table.c',
+  'src/core/transport/chttp2/huffsyms.c',
+  'src/core/transport/chttp2/incoming_metadata.c',
+  'src/core/transport/chttp2/parsing.c',
+  'src/core/transport/chttp2/status_conversion.c',
+  'src/core/transport/chttp2/stream_lists.c',
+  'src/core/transport/chttp2/stream_map.c',
+  'src/core/transport/chttp2/timeout_encoding.c',
+  'src/core/transport/chttp2/varint.c',
+  'src/core/transport/chttp2/writing.c',
+  'src/core/transport/chttp2_transport.c',
+  'src/core/transport/connectivity_state.c',
+  'src/core/transport/metadata.c',
+  'src/core/transport/metadata_batch.c',
+  'src/core/transport/static_metadata.c',
+  'src/core/transport/transport.c',
+  'src/core/transport/transport_op_string.c',
+  'src/core/census/context.c',
+  'src/core/census/initialize.c',
+  'src/core/census/operation.c',
+  'src/core/census/tracing.c',
+  'src/boringssl/err_data.c',
+  'third_party/boringssl/crypto/aes/aes.c',
+  'third_party/boringssl/crypto/aes/mode_wrappers.c',
+  'third_party/boringssl/crypto/asn1/a_bitstr.c',
+  'third_party/boringssl/crypto/asn1/a_bool.c',
+  'third_party/boringssl/crypto/asn1/a_bytes.c',
+  'third_party/boringssl/crypto/asn1/a_d2i_fp.c',
+  'third_party/boringssl/crypto/asn1/a_dup.c',
+  'third_party/boringssl/crypto/asn1/a_enum.c',
+  'third_party/boringssl/crypto/asn1/a_gentm.c',
+  'third_party/boringssl/crypto/asn1/a_i2d_fp.c',
+  'third_party/boringssl/crypto/asn1/a_int.c',
+  'third_party/boringssl/crypto/asn1/a_mbstr.c',
+  'third_party/boringssl/crypto/asn1/a_object.c',
+  'third_party/boringssl/crypto/asn1/a_octet.c',
+  'third_party/boringssl/crypto/asn1/a_print.c',
+  'third_party/boringssl/crypto/asn1/a_strnid.c',
+  'third_party/boringssl/crypto/asn1/a_time.c',
+  'third_party/boringssl/crypto/asn1/a_type.c',
+  'third_party/boringssl/crypto/asn1/a_utctm.c',
+  'third_party/boringssl/crypto/asn1/a_utf8.c',
+  'third_party/boringssl/crypto/asn1/asn1_lib.c',
+  'third_party/boringssl/crypto/asn1/asn1_par.c',
+  'third_party/boringssl/crypto/asn1/asn_pack.c',
+  'third_party/boringssl/crypto/asn1/bio_asn1.c',
+  'third_party/boringssl/crypto/asn1/bio_ndef.c',
+  'third_party/boringssl/crypto/asn1/f_enum.c',
+  'third_party/boringssl/crypto/asn1/f_int.c',
+  'third_party/boringssl/crypto/asn1/f_string.c',
+  'third_party/boringssl/crypto/asn1/t_bitst.c',
+  'third_party/boringssl/crypto/asn1/t_pkey.c',
+  'third_party/boringssl/crypto/asn1/tasn_dec.c',
+  'third_party/boringssl/crypto/asn1/tasn_enc.c',
+  'third_party/boringssl/crypto/asn1/tasn_fre.c',
+  'third_party/boringssl/crypto/asn1/tasn_new.c',
+  'third_party/boringssl/crypto/asn1/tasn_prn.c',
+  'third_party/boringssl/crypto/asn1/tasn_typ.c',
+  'third_party/boringssl/crypto/asn1/tasn_utl.c',
+  'third_party/boringssl/crypto/asn1/x_bignum.c',
+  'third_party/boringssl/crypto/asn1/x_long.c',
+  'third_party/boringssl/crypto/base64/base64.c',
+  'third_party/boringssl/crypto/bio/bio.c',
+  'third_party/boringssl/crypto/bio/bio_mem.c',
+  'third_party/boringssl/crypto/bio/buffer.c',
+  'third_party/boringssl/crypto/bio/connect.c',
+  'third_party/boringssl/crypto/bio/fd.c',
+  'third_party/boringssl/crypto/bio/file.c',
+  'third_party/boringssl/crypto/bio/hexdump.c',
+  'third_party/boringssl/crypto/bio/pair.c',
+  'third_party/boringssl/crypto/bio/printf.c',
+  'third_party/boringssl/crypto/bio/socket.c',
+  'third_party/boringssl/crypto/bio/socket_helper.c',
+  'third_party/boringssl/crypto/bn/add.c',
+  'third_party/boringssl/crypto/bn/asm/x86_64-gcc.c',
+  'third_party/boringssl/crypto/bn/bn.c',
+  'third_party/boringssl/crypto/bn/bn_asn1.c',
+  'third_party/boringssl/crypto/bn/cmp.c',
+  'third_party/boringssl/crypto/bn/convert.c',
+  'third_party/boringssl/crypto/bn/ctx.c',
+  'third_party/boringssl/crypto/bn/div.c',
+  'third_party/boringssl/crypto/bn/exponentiation.c',
+  'third_party/boringssl/crypto/bn/gcd.c',
+  'third_party/boringssl/crypto/bn/generic.c',
+  'third_party/boringssl/crypto/bn/kronecker.c',
+  'third_party/boringssl/crypto/bn/montgomery.c',
+  'third_party/boringssl/crypto/bn/mul.c',
+  'third_party/boringssl/crypto/bn/prime.c',
+  'third_party/boringssl/crypto/bn/random.c',
+  'third_party/boringssl/crypto/bn/rsaz_exp.c',
+  'third_party/boringssl/crypto/bn/shift.c',
+  'third_party/boringssl/crypto/bn/sqrt.c',
+  'third_party/boringssl/crypto/buf/buf.c',
+  'third_party/boringssl/crypto/bytestring/ber.c',
+  'third_party/boringssl/crypto/bytestring/cbb.c',
+  'third_party/boringssl/crypto/bytestring/cbs.c',
+  'third_party/boringssl/crypto/chacha/chacha_generic.c',
+  'third_party/boringssl/crypto/chacha/chacha_vec.c',
+  'third_party/boringssl/crypto/cipher/aead.c',
+  'third_party/boringssl/crypto/cipher/cipher.c',
+  'third_party/boringssl/crypto/cipher/derive_key.c',
+  'third_party/boringssl/crypto/cipher/e_aes.c',
+  'third_party/boringssl/crypto/cipher/e_chacha20poly1305.c',
+  'third_party/boringssl/crypto/cipher/e_des.c',
+  'third_party/boringssl/crypto/cipher/e_null.c',
+  'third_party/boringssl/crypto/cipher/e_rc2.c',
+  'third_party/boringssl/crypto/cipher/e_rc4.c',
+  'third_party/boringssl/crypto/cipher/e_ssl3.c',
+  'third_party/boringssl/crypto/cipher/e_tls.c',
+  'third_party/boringssl/crypto/cipher/tls_cbc.c',
+  'third_party/boringssl/crypto/cmac/cmac.c',
+  'third_party/boringssl/crypto/conf/conf.c',
+  'third_party/boringssl/crypto/cpu-arm.c',
+  'third_party/boringssl/crypto/cpu-intel.c',
+  'third_party/boringssl/crypto/crypto.c',
+  'third_party/boringssl/crypto/curve25519/curve25519.c',
+  'third_party/boringssl/crypto/des/des.c',
+  'third_party/boringssl/crypto/dh/check.c',
+  'third_party/boringssl/crypto/dh/dh.c',
+  'third_party/boringssl/crypto/dh/dh_asn1.c',
+  'third_party/boringssl/crypto/dh/params.c',
+  'third_party/boringssl/crypto/digest/digest.c',
+  'third_party/boringssl/crypto/digest/digests.c',
+  'third_party/boringssl/crypto/directory_posix.c',
+  'third_party/boringssl/crypto/directory_win.c',
+  'third_party/boringssl/crypto/dsa/dsa.c',
+  'third_party/boringssl/crypto/dsa/dsa_asn1.c',
+  'third_party/boringssl/crypto/ec/ec.c',
+  'third_party/boringssl/crypto/ec/ec_asn1.c',
+  'third_party/boringssl/crypto/ec/ec_key.c',
+  'third_party/boringssl/crypto/ec/ec_montgomery.c',
+  'third_party/boringssl/crypto/ec/oct.c',
+  'third_party/boringssl/crypto/ec/p224-64.c',
+  'third_party/boringssl/crypto/ec/p256-64.c',
+  'third_party/boringssl/crypto/ec/p256-x86_64.c',
+  'third_party/boringssl/crypto/ec/simple.c',
+  'third_party/boringssl/crypto/ec/util-64.c',
+  'third_party/boringssl/crypto/ec/wnaf.c',
+  'third_party/boringssl/crypto/ecdh/ecdh.c',
+  'third_party/boringssl/crypto/ecdsa/ecdsa.c',
+  'third_party/boringssl/crypto/ecdsa/ecdsa_asn1.c',
+  'third_party/boringssl/crypto/engine/engine.c',
+  'third_party/boringssl/crypto/err/err.c',
+  'third_party/boringssl/crypto/evp/algorithm.c',
+  'third_party/boringssl/crypto/evp/digestsign.c',
+  'third_party/boringssl/crypto/evp/evp.c',
+  'third_party/boringssl/crypto/evp/evp_asn1.c',
+  'third_party/boringssl/crypto/evp/evp_ctx.c',
+  'third_party/boringssl/crypto/evp/p_dsa_asn1.c',
+  'third_party/boringssl/crypto/evp/p_ec.c',
+  'third_party/boringssl/crypto/evp/p_ec_asn1.c',
+  'third_party/boringssl/crypto/evp/p_rsa.c',
+  'third_party/boringssl/crypto/evp/p_rsa_asn1.c',
+  'third_party/boringssl/crypto/evp/pbkdf.c',
+  'third_party/boringssl/crypto/evp/sign.c',
+  'third_party/boringssl/crypto/ex_data.c',
+  'third_party/boringssl/crypto/hkdf/hkdf.c',
+  'third_party/boringssl/crypto/hmac/hmac.c',
+  'third_party/boringssl/crypto/lhash/lhash.c',
+  'third_party/boringssl/crypto/md4/md4.c',
+  'third_party/boringssl/crypto/md5/md5.c',
+  'third_party/boringssl/crypto/mem.c',
+  'third_party/boringssl/crypto/modes/cbc.c',
+  'third_party/boringssl/crypto/modes/cfb.c',
+  'third_party/boringssl/crypto/modes/ctr.c',
+  'third_party/boringssl/crypto/modes/gcm.c',
+  'third_party/boringssl/crypto/modes/ofb.c',
+  'third_party/boringssl/crypto/obj/obj.c',
+  'third_party/boringssl/crypto/obj/obj_xref.c',
+  'third_party/boringssl/crypto/pem/pem_all.c',
+  'third_party/boringssl/crypto/pem/pem_info.c',
+  'third_party/boringssl/crypto/pem/pem_lib.c',
+  'third_party/boringssl/crypto/pem/pem_oth.c',
+  'third_party/boringssl/crypto/pem/pem_pk8.c',
+  'third_party/boringssl/crypto/pem/pem_pkey.c',
+  'third_party/boringssl/crypto/pem/pem_x509.c',
+  'third_party/boringssl/crypto/pem/pem_xaux.c',
+  'third_party/boringssl/crypto/pkcs8/p5_pbe.c',
+  'third_party/boringssl/crypto/pkcs8/p5_pbev2.c',
+  'third_party/boringssl/crypto/pkcs8/p8_pkey.c',
+  'third_party/boringssl/crypto/pkcs8/pkcs8.c',
+  'third_party/boringssl/crypto/poly1305/poly1305.c',
+  'third_party/boringssl/crypto/poly1305/poly1305_arm.c',
+  'third_party/boringssl/crypto/poly1305/poly1305_vec.c',
+  'third_party/boringssl/crypto/rand/rand.c',
+  'third_party/boringssl/crypto/rand/urandom.c',
+  'third_party/boringssl/crypto/rand/windows.c',
+  'third_party/boringssl/crypto/rc4/rc4.c',
+  'third_party/boringssl/crypto/refcount_c11.c',
+  'third_party/boringssl/crypto/refcount_lock.c',
+  'third_party/boringssl/crypto/rsa/blinding.c',
+  'third_party/boringssl/crypto/rsa/padding.c',
+  'third_party/boringssl/crypto/rsa/rsa.c',
+  'third_party/boringssl/crypto/rsa/rsa_asn1.c',
+  'third_party/boringssl/crypto/rsa/rsa_impl.c',
+  'third_party/boringssl/crypto/sha/sha1.c',
+  'third_party/boringssl/crypto/sha/sha256.c',
+  'third_party/boringssl/crypto/sha/sha512.c',
+  'third_party/boringssl/crypto/stack/stack.c',
+  'third_party/boringssl/crypto/thread.c',
+  'third_party/boringssl/crypto/thread_none.c',
+  'third_party/boringssl/crypto/thread_pthread.c',
+  'third_party/boringssl/crypto/thread_win.c',
+  'third_party/boringssl/crypto/time_support.c',
+  'third_party/boringssl/crypto/x509/a_digest.c',
+  'third_party/boringssl/crypto/x509/a_sign.c',
+  'third_party/boringssl/crypto/x509/a_strex.c',
+  'third_party/boringssl/crypto/x509/a_verify.c',
+  'third_party/boringssl/crypto/x509/asn1_gen.c',
+  'third_party/boringssl/crypto/x509/by_dir.c',
+  'third_party/boringssl/crypto/x509/by_file.c',
+  'third_party/boringssl/crypto/x509/i2d_pr.c',
+  'third_party/boringssl/crypto/x509/pkcs7.c',
+  'third_party/boringssl/crypto/x509/t_crl.c',
+  'third_party/boringssl/crypto/x509/t_req.c',
+  'third_party/boringssl/crypto/x509/t_x509.c',
+  'third_party/boringssl/crypto/x509/t_x509a.c',
+  'third_party/boringssl/crypto/x509/x509.c',
+  'third_party/boringssl/crypto/x509/x509_att.c',
+  'third_party/boringssl/crypto/x509/x509_cmp.c',
+  'third_party/boringssl/crypto/x509/x509_d2.c',
+  'third_party/boringssl/crypto/x509/x509_def.c',
+  'third_party/boringssl/crypto/x509/x509_ext.c',
+  'third_party/boringssl/crypto/x509/x509_lu.c',
+  'third_party/boringssl/crypto/x509/x509_obj.c',
+  'third_party/boringssl/crypto/x509/x509_r2x.c',
+  'third_party/boringssl/crypto/x509/x509_req.c',
+  'third_party/boringssl/crypto/x509/x509_set.c',
+  'third_party/boringssl/crypto/x509/x509_trs.c',
+  'third_party/boringssl/crypto/x509/x509_txt.c',
+  'third_party/boringssl/crypto/x509/x509_v3.c',
+  'third_party/boringssl/crypto/x509/x509_vfy.c',
+  'third_party/boringssl/crypto/x509/x509_vpm.c',
+  'third_party/boringssl/crypto/x509/x509cset.c',
+  'third_party/boringssl/crypto/x509/x509name.c',
+  'third_party/boringssl/crypto/x509/x509rset.c',
+  'third_party/boringssl/crypto/x509/x509spki.c',
+  'third_party/boringssl/crypto/x509/x509type.c',
+  'third_party/boringssl/crypto/x509/x_algor.c',
+  'third_party/boringssl/crypto/x509/x_all.c',
+  'third_party/boringssl/crypto/x509/x_attrib.c',
+  'third_party/boringssl/crypto/x509/x_crl.c',
+  'third_party/boringssl/crypto/x509/x_exten.c',
+  'third_party/boringssl/crypto/x509/x_info.c',
+  'third_party/boringssl/crypto/x509/x_name.c',
+  'third_party/boringssl/crypto/x509/x_pkey.c',
+  'third_party/boringssl/crypto/x509/x_pubkey.c',
+  'third_party/boringssl/crypto/x509/x_req.c',
+  'third_party/boringssl/crypto/x509/x_sig.c',
+  'third_party/boringssl/crypto/x509/x_spki.c',
+  'third_party/boringssl/crypto/x509/x_val.c',
+  'third_party/boringssl/crypto/x509/x_x509.c',
+  'third_party/boringssl/crypto/x509/x_x509a.c',
+  'third_party/boringssl/crypto/x509v3/pcy_cache.c',
+  'third_party/boringssl/crypto/x509v3/pcy_data.c',
+  'third_party/boringssl/crypto/x509v3/pcy_lib.c',
+  'third_party/boringssl/crypto/x509v3/pcy_map.c',
+  'third_party/boringssl/crypto/x509v3/pcy_node.c',
+  'third_party/boringssl/crypto/x509v3/pcy_tree.c',
+  'third_party/boringssl/crypto/x509v3/v3_akey.c',
+  'third_party/boringssl/crypto/x509v3/v3_akeya.c',
+  'third_party/boringssl/crypto/x509v3/v3_alt.c',
+  'third_party/boringssl/crypto/x509v3/v3_bcons.c',
+  'third_party/boringssl/crypto/x509v3/v3_bitst.c',
+  'third_party/boringssl/crypto/x509v3/v3_conf.c',
+  'third_party/boringssl/crypto/x509v3/v3_cpols.c',
+  'third_party/boringssl/crypto/x509v3/v3_crld.c',
+  'third_party/boringssl/crypto/x509v3/v3_enum.c',
+  'third_party/boringssl/crypto/x509v3/v3_extku.c',
+  'third_party/boringssl/crypto/x509v3/v3_genn.c',
+  'third_party/boringssl/crypto/x509v3/v3_ia5.c',
+  'third_party/boringssl/crypto/x509v3/v3_info.c',
+  'third_party/boringssl/crypto/x509v3/v3_int.c',
+  'third_party/boringssl/crypto/x509v3/v3_lib.c',
+  'third_party/boringssl/crypto/x509v3/v3_ncons.c',
+  'third_party/boringssl/crypto/x509v3/v3_pci.c',
+  'third_party/boringssl/crypto/x509v3/v3_pcia.c',
+  'third_party/boringssl/crypto/x509v3/v3_pcons.c',
+  'third_party/boringssl/crypto/x509v3/v3_pku.c',
+  'third_party/boringssl/crypto/x509v3/v3_pmaps.c',
+  'third_party/boringssl/crypto/x509v3/v3_prn.c',
+  'third_party/boringssl/crypto/x509v3/v3_purp.c',
+  'third_party/boringssl/crypto/x509v3/v3_skey.c',
+  'third_party/boringssl/crypto/x509v3/v3_sxnet.c',
+  'third_party/boringssl/crypto/x509v3/v3_utl.c',
+  'third_party/boringssl/ssl/custom_extensions.c',
+  'third_party/boringssl/ssl/d1_both.c',
+  'third_party/boringssl/ssl/d1_clnt.c',
+  'third_party/boringssl/ssl/d1_lib.c',
+  'third_party/boringssl/ssl/d1_meth.c',
+  'third_party/boringssl/ssl/d1_pkt.c',
+  'third_party/boringssl/ssl/d1_srtp.c',
+  'third_party/boringssl/ssl/d1_srvr.c',
+  'third_party/boringssl/ssl/dtls_record.c',
+  'third_party/boringssl/ssl/pqueue/pqueue.c',
+  'third_party/boringssl/ssl/s3_both.c',
+  'third_party/boringssl/ssl/s3_clnt.c',
+  'third_party/boringssl/ssl/s3_enc.c',
+  'third_party/boringssl/ssl/s3_lib.c',
+  'third_party/boringssl/ssl/s3_meth.c',
+  'third_party/boringssl/ssl/s3_pkt.c',
+  'third_party/boringssl/ssl/s3_srvr.c',
+  'third_party/boringssl/ssl/ssl_aead_ctx.c',
+  'third_party/boringssl/ssl/ssl_asn1.c',
+  'third_party/boringssl/ssl/ssl_buffer.c',
+  'third_party/boringssl/ssl/ssl_cert.c',
+  'third_party/boringssl/ssl/ssl_cipher.c',
+  'third_party/boringssl/ssl/ssl_file.c',
+  'third_party/boringssl/ssl/ssl_lib.c',
+  'third_party/boringssl/ssl/ssl_rsa.c',
+  'third_party/boringssl/ssl/ssl_session.c',
+  'third_party/boringssl/ssl/ssl_stat.c',
+  'third_party/boringssl/ssl/t1_enc.c',
+  'third_party/boringssl/ssl/t1_lib.c',
+  'third_party/boringssl/ssl/tls_record.c',
+]
diff --git a/src/python/grpcio/tests/unit/_cython/test_utilities.py b/src/python/grpcio/tests/unit/_cython/test_utilities.py
index 21ea3075b47fa48f8e296baa460b08987abc9cd7..6a09739643176392acf80d1814238368d537a34c 100644
--- a/src/python/grpcio/tests/unit/_cython/test_utilities.py
+++ b/src/python/grpcio/tests/unit/_cython/test_utilities.py
@@ -29,7 +29,7 @@
 
 import threading
 
-from grpc._cython._cygrpc import completion_queue
+from grpc._cython import cygrpc
 
 
 class CompletionQueuePollFuture:
diff --git a/src/python/grpcio/tox.ini b/src/python/grpcio/tox.ini
deleted file mode 100644
index bfb1ca0cfada221126fd49fdf7b560d9d5cded8b..0000000000000000000000000000000000000000
--- a/src/python/grpcio/tox.ini
+++ /dev/null
@@ -1,19 +0,0 @@
-# Tox (http://tox.testrun.org/) is a tool for running tests
-# in multiple virtualenvs. This configuration file will run the
-# test suite on all supported python versions. To use it, "pip install tox"
-# and then run "tox" from this directory.
-
-[tox]
-skipsdist = true
-envlist = py27
-
-[testenv]
-commands =
-    {envpython} setup.py build_py
-    {envpython} setup.py test
-    coverage combine
-    coverage html --include='grpc/*' --omit='grpc/framework/alpha/*','grpc/early_adopter/*','grpc/framework/base/*','grpc/framework/face/*','grpc/_adapter/fore.py','grpc/_adapter/rear.py'
-    coverage report --include='grpc/*' --omit='grpc/framework/alpha/*','grpc/early_adopter/*','grpc/framework/base/*','grpc/framework/face/*','grpc/_adapter/fore.py','grpc/_adapter/rear.py'
-deps =
-    -rrequirements.txt
-passenv = *
diff --git a/templates/Makefile.template b/templates/Makefile.template
index ba5a80659c047697df790fa04ecd2176be03303b..1582cae20acfdf8e56f193819e18810c1976ee18 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -7,7 +7,7 @@
   # This file can be regenerated from the template by running
   # tools/buildgen/generate_projects.sh
 
-  # Copyright 2015, Google Inc.
+  # Copyright 2015-2016, Google Inc.
   # All rights reserved.
   #
   # Redistribution and use in source and binary forms, with or without
diff --git a/templates/src/python/grpcio/grpc_core_dependencies.py.template b/templates/src/python/grpcio/grpc_core_dependencies.py.template
new file mode 100644
index 0000000000000000000000000000000000000000..2fc7a03f18148baf839ad610c3b84c2dec3b3451
--- /dev/null
+++ b/templates/src/python/grpcio/grpc_core_dependencies.py.template
@@ -0,0 +1,42 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_core_dependencies.py.template`!!!
+
+  CORE_SOURCE_FILES = [
+  % for lib in libs:
+  % if lib.name in python_dependencies.transitive_deps:
+  % for src in lib.src:
+    '${src}',
+  % endfor
+  % endif
+  % endfor
+  ]
diff --git a/templates/test/core/end2end/end2end_defs.include b/templates/test/core/end2end/end2end_defs.include
index 1b13bba94cb532fef60216946e4a40f59d6f9771..929827e145334f44cf90408d20467eb21990b310 100644
--- a/templates/test/core/end2end/end2end_defs.include
+++ b/templates/test/core/end2end/end2end_defs.include
@@ -61,7 +61,7 @@ void grpc_end2end_tests(int argc, char **argv,
       continue;
     }
 % endfor
-    gpr_log(GPR_DEBUG, "not a test: '%%s'", argv[i]);
+    gpr_log(GPR_DEBUG, "not a test: '%s'", argv[i]);
     abort();
   }
 }</%def>
\ No newline at end of file
diff --git a/test/core/end2end/end2end_nosec_tests.c b/test/core/end2end/end2end_nosec_tests.c
index d9df5fd7f05aec897204163e39bafaa7ed21d963..9ff46d62e49e03b46e7242c9d04327f37dd391ee 100644
--- a/test/core/end2end/end2end_nosec_tests.c
+++ b/test/core/end2end/end2end_nosec_tests.c
@@ -258,7 +258,7 @@ void grpc_end2end_tests(int argc, char **argv,
       trailing_metadata(config);
       continue;
     }
-    gpr_log(GPR_DEBUG, "not a test: '%%s'", argv[i]);
+    gpr_log(GPR_DEBUG, "not a test: '%s'", argv[i]);
     abort();
   }
 }
diff --git a/test/core/end2end/end2end_tests.c b/test/core/end2end/end2end_tests.c
index 7b1471eb892da7df03525dbf7af256051cb1cc06..397ff446a9cff0f52d607a079bf59e3e1826808c 100644
--- a/test/core/end2end/end2end_tests.c
+++ b/test/core/end2end/end2end_tests.c
@@ -264,7 +264,7 @@ void grpc_end2end_tests(int argc, char **argv,
       trailing_metadata(config);
       continue;
     }
-    gpr_log(GPR_DEBUG, "not a test: '%%s'", argv[i]);
+    gpr_log(GPR_DEBUG, "not a test: '%s'", argv[i]);
     abort();
   }
 }
diff --git a/test/core/iomgr/tcp_posix_test.c b/test/core/iomgr/tcp_posix_test.c
index b59ba1014b16343b13bb7a85c185c122e465c46c..e0136b3cd7590a459e3564f702561311d5efd2b3 100644
--- a/test/core/iomgr/tcp_posix_test.c
+++ b/test/core/iomgr/tcp_posix_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/test/core/security/jwt_verifier_test.c b/test/core/security/jwt_verifier_test.c
index 9f37e0374c4c45425ae12687e934282740020b66..f396398cefb424852a3bdc8cc25c6b88cb97aa27 100644
--- a/test/core/security/jwt_verifier_test.c
+++ b/test/core/security/jwt_verifier_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/test/core/support/cpu_test.c b/test/core/support/cpu_test.c
index a5c52442ad4c67e2d2ca015abee44f3b1112b257..da16f13fd85799de452a498b6b707d5a34badeab 100644
--- a/test/core/support/cpu_test.c
+++ b/test/core/support/cpu_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index dc07eb67774a452f720e761f83f8344672686f34..62023b24fd265a40ad11109b425b3f8072fc5b8e 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/test/cpp/end2end/generic_end2end_test.cc b/test/cpp/end2end/generic_end2end_test.cc
index f8ceca5f1d64bfd3191e8f228bd8a8ea41ea4bd8..14b534fbd20f257b05b9f948ddc1608dd0bd281d 100644
--- a/test/cpp/end2end/generic_end2end_test.cc
+++ b/test/cpp/end2end/generic_end2end_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc
index 6747127c225c37827e9a80dda5e31de1f5fa9aa2..b06310781a247d06bbb57d70d99ec4a2e6b2139f 100644
--- a/test/cpp/interop/interop_client.cc
+++ b/test/cpp/interop/interop_client.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/test/cpp/interop/reconnect_interop_server.cc b/test/cpp/interop/reconnect_interop_server.cc
index e0165476d09bfa038244b86234966025bd7012b7..3602b8c2b05a4e7bbc31269f445c91073105a7ba 100644
--- a/test/cpp/interop/reconnect_interop_server.cc
+++ b/test/cpp/interop/reconnect_interop_server.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/test/cpp/interop/stress_interop_client.cc b/test/cpp/interop/stress_interop_client.cc
index 04671fb935ed39d28f53d9c33a16d6dc36d48497..b581e9b33cc3162d6a8a7bcdbefd65cbe631f68a 100644
--- a/test/cpp/interop/stress_interop_client.cc
+++ b/test/cpp/interop/stress_interop_client.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/test/cpp/interop/stress_test.cc b/test/cpp/interop/stress_test.cc
index 05d5f2e339f968436320c1f7e048e63174b778ca..702354dc87d20976fb978a710d6a88a485e34c9d 100644
--- a/test/cpp/interop/stress_test.cc
+++ b/test/cpp/interop/stress_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/tools/buildgen/plugins/transitive_dependencies.py b/tools/buildgen/plugins/transitive_dependencies.py
index c2d3da3a3b264dd95256fb7c24e2a9a554651d06..01e7f61ea9d630c4537cb4201d1f78bd9330f215 100644
--- a/tools/buildgen/plugins/transitive_dependencies.py
+++ b/tools/buildgen/plugins/transitive_dependencies.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -36,10 +36,13 @@ of the list of dependencies.
 """
 
 def get_lib(libs, name):
-  return next(lib for lib in libs if lib['name']==name)
+  try:
+    return next(lib for lib in libs if lib['name']==name)
+  except StopIteration:
+    return None
 
 def transitive_deps(lib, libs):
-  if 'deps' in lib:
+  if lib is not None and 'deps' in lib:
     # Recursively call transitive_deps on each dependency, and take the union
     return set.union(set(lib['deps']),
                      *[set(transitive_deps(get_lib(libs, dep), libs))
@@ -58,6 +61,10 @@ def mako_plugin(dictionary):
   node_modules = dictionary.get('node_modules')
   targets = dictionary.get('targets')
 
-  for target_list in (libs, node_modules, targets):
+  for target_list in (libs, targets, node_modules):
     for target in target_list:
       target['transitive_deps'] = transitive_deps(target, libs)
+
+  python_dependencies = dictionary.get('python_dependencies')
+  python_dependencies['transitive_deps'] = (
+      transitive_deps(python_dependencies, libs))
diff --git a/tools/distrib/check_copyright.py b/tools/distrib/check_copyright.py
index f54e5fad807d9b4217d47609218df37e0ff4c54d..5e948e2deeb6f8827c56600cf606f703b98f3f73 100755
--- a/tools/distrib/check_copyright.py
+++ b/tools/distrib/check_copyright.py
@@ -54,6 +54,9 @@ argp.add_argument('-a', '--ancient',
                   default=0,
                   action='store_const',
                   const=1)
+argp.add_argument('-f', '--fix',
+                  default=False,
+                  action='store_true');
 args = argp.parse_args()
 
 # open the license text
@@ -90,7 +93,7 @@ KNOWN_BAD = set([
 ])
 
 
-RE_YEAR = r'Copyright (?:[0-9]+\-)?([0-9]+), Google Inc\.'
+RE_YEAR = r'Copyright (?P<first_year>[0-9]+\-)?(?P<last_year>[0-9]+), Google Inc\.'
 RE_LICENSE = dict(
     (k, r'\n'.join(
         LICENSE_PREFIX[k] +
@@ -103,6 +106,9 @@ def load(name):
   with open(name) as f:
     return '\n'.join(line.rstrip() for line in f.read().splitlines())
 
+def save(name, text):
+  with open(name, 'w') as f:
+    f.write(text)
 
 assert(re.search(RE_LICENSE['LICENSE'], load('LICENSE')))
 assert(re.search(RE_LICENSE['Makefile'], load('Makefile')))
@@ -117,6 +123,7 @@ def log(cond, why, filename):
 
 
 # scan files, validate the text
+ok = True
 for filename in subprocess.check_output('git ls-tree -r --name-only -r HEAD',
                                         shell=True).splitlines():
   if filename in KNOWN_BAD: continue
@@ -130,14 +137,25 @@ for filename in subprocess.check_output('git ls-tree -r --name-only -r HEAD',
     log(args.skips, 'skip', filename)
     continue
   text = load(filename)
-  ok = True
   m = re.search(re_license, text)
   if m:
+    gdict = m.groupdict()
     last_modified = int(subprocess.check_output('git log -1 --format="%ad" --date=short -- ' + filename, shell=True)[0:4])
-    latest_claimed = int(m.group(1))
+    latest_claimed = int(gdict['last_year'])
     if last_modified > latest_claimed:
       print '%s modified %d but copyright only extends to %d' % (filename, last_modified, latest_claimed)
       ok = False
+      if args.fix:
+        span_start, span_end = m.span(2)
+        if not gdict['first_year']:
+          # prepend the old year to the current one.
+          text = '{}-{}{}'.format(text[:span_end], last_modified, text[span_end:])
+        else:  # already a year range
+          # simply update the last year
+          text = '{}{}{}'.format(text[:span_start], last_modified, text[span_end:])
+        save(filename, text)
+        print 'Fixed!'
+        ok = True
   elif 'DO NOT EDIT' not in text and 'AssemblyInfo.cs' not in filename and filename != 'src/boringssl/err_data.c':
     log(1, 'copyright missing', filename)
     ok = False
diff --git a/tools/distrib/python/submit.py b/tools/distrib/python/submit.py
index dffbefd5fe4cd1b0af5ac9737aff243cf3c47aba..08ace7c69015b814380aab553472907232bc454b 100755
--- a/tools/distrib/python/submit.py
+++ b/tools/distrib/python/submit.py
@@ -59,7 +59,7 @@ args = parser.parse_args()
 
 # Move to the root directory of Python GRPC.
 pkgdir = os.path.join(os.path.dirname(os.path.abspath(__file__)),
-                      '../../../src/python/grpcio')
+                      '../../../')
 # Remove previous distributions; they somehow confuse twine.
 try:
   shutil.rmtree(os.path.join(pkgdir, 'dist/'))
diff --git a/tools/jenkins/grpc_interop_python/Dockerfile b/tools/jenkins/grpc_interop_python/Dockerfile
index 6034cbf95504719cc3fc9649d48902cd5cc51859..047604b1b7975b11c0cf0d719ad1ae46e4990965 100644
--- a/tools/jenkins/grpc_interop_python/Dockerfile
+++ b/tools/jenkins/grpc_interop_python/Dockerfile
@@ -48,6 +48,7 @@ RUN apt-get update && apt-get install -y \
   libc6-dbg \
   libc6-dev \
   libgtest-dev \
+  libssl-dev \
   libtool \
   make \
   strace \
diff --git a/tools/jenkins/grpc_interop_python/build_interop.sh b/tools/jenkins/grpc_interop_python/build_interop.sh
index 8f5bfd11e20dd778a4209d014e29b5823c8ad515..39c93677d8ba006a44b22d4676a485bc304a7e7c 100755
--- a/tools/jenkins/grpc_interop_python/build_interop.sh
+++ b/tools/jenkins/grpc_interop_python/build_interop.sh
@@ -43,5 +43,5 @@ make install-certs
 make
 
 # build Python interop client and server
-CONFIG=opt ./tools/run_tests/build_python.sh 2.7
+CONFIG=opt ./tools/run_tests/build_python.sh
 
diff --git a/tools/jenkins/grpc_jenkins_slave/Dockerfile b/tools/jenkins/grpc_jenkins_slave/Dockerfile
index f3bf6bc4f0d1185ca206ddeb1fc35181c19ea885..b1ac024dfb3faa1ba57050a24e02ae3fc9cd1e27 100644
--- a/tools/jenkins/grpc_jenkins_slave/Dockerfile
+++ b/tools/jenkins/grpc_jenkins_slave/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_jenkins_slave_32bits/Dockerfile b/tools/jenkins/grpc_jenkins_slave_32bits/Dockerfile
index 1a86c5a5d7dbb0e0ac2e1f532f74ee8882d5b134..348a333d3e600b644f6289edcd6912308241e1f1 100644
--- a/tools/jenkins/grpc_jenkins_slave_32bits/Dockerfile
+++ b/tools/jenkins/grpc_jenkins_slave_32bits/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/run_jenkins.sh b/tools/jenkins/run_jenkins.sh
index 9b6ba719481df4a77f5f161dce34b27772655596..84b4ea51ed4d344a4ebac4dcf7dd7954e13367a9 100755
--- a/tools/jenkins/run_jenkins.sh
+++ b/tools/jenkins/run_jenkins.sh
@@ -1,5 +1,5 @@
 #!/usr/bin/env bash
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -92,4 +92,3 @@ if [ "$TESTS_FAILED" != "" ]
 then
   exit 1
 fi
-
diff --git a/tools/run_tests/build_python.sh b/tools/run_tests/build_python.sh
index 57080ce9348dce69599b1b3372f2e340d6a2261b..e0fcbb602d4bc276e3b7ccb6caa7ed1101634c73 100755
--- a/tools/run_tests/build_python.sh
+++ b/tools/run_tests/build_python.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -34,16 +34,14 @@ set -ex
 cd $(dirname $0)/../..
 
 ROOT=`pwd`
-GRPCIO=$ROOT/src/python/grpcio
 export LD_LIBRARY_PATH=$ROOT/libs/$CONFIG
 export DYLD_LIBRARY_PATH=$ROOT/libs/$CONFIG
 export PATH=$ROOT/bins/$CONFIG:$ROOT/bins/$CONFIG/protobuf:$PATH
-export CFLAGS="-I$ROOT/include -std=c89"
+export CFLAGS="-I$ROOT/include -std=gnu99"
 export LDFLAGS="-L$ROOT/libs/$CONFIG"
 export GRPC_PYTHON_BUILD_WITH_CYTHON=1
 export GRPC_PYTHON_ENABLE_CYTHON_TRACING=1
 
-cd $GRPCIO
 tox --notest
 
-$GRPCIO/.tox/py27/bin/python $GRPCIO/setup.py build
+$ROOT/.tox/py27/bin/python $ROOT/setup.py build
diff --git a/tools/run_tests/jobset.py b/tools/run_tests/jobset.py
index 0b01bc4becdf34d3499aae5b9662a59740dc6591..e33433daf2a9f7b85c3f61e00461d83cf2ed14a5 100755
--- a/tools/run_tests/jobset.py
+++ b/tools/run_tests/jobset.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -450,4 +450,3 @@ def run(cmdlines,
       js.set_remaining(remaining)
   js.finish()
   return js.get_num_failures(), js.resultset
-
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index e69e9877c5c7f272fd1f4e9fd689cfe92b32506f..40bbe3cc3ca0ada2659a126345d49c54fcd74e42 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -298,11 +298,8 @@ class PythonLanguage:
 
   def client_cmd(self, args):
     return [
-        'src/python/grpcio/.tox/py27/bin/python',
-        'src/python/grpcio/setup.py',
-        'run_interop',
-        '--client',
-        '--args=\'{}\''.format(' '.join(args))
+        'tox -einterop_client --',
+        ' '.join(args)
     ]
 
   def cloud_to_prod_env(self):
@@ -310,11 +307,8 @@ class PythonLanguage:
 
   def server_cmd(self, args):
     return [
-        'src/python/grpcio/.tox/py27/bin/python',
-        'src/python/grpcio/setup.py',
-        'run_interop',
-        '--server',
-        '--args=\'{}\''.format(' '.join(args) + ' --use_tls=true')
+        'tox -einterop_server --',
+        ' '.join(args) + ' --use_tls=true'
     ]
 
   def global_env(self):
diff --git a/tools/run_tests/run_python.sh b/tools/run_tests/run_python.sh
index 042b40485df68d0f6e73b3be776d5d1ca20c047a..ffe9c12af1a2beefc6cf9773cd9f46412059fcba 100755
--- a/tools/run_tests/run_python.sh
+++ b/tools/run_tests/run_python.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,6 @@ set -ex
 cd $(dirname $0)/../..
 
 ROOT=`pwd`
-GRPCIO=$ROOT/src/python/grpcio
 export LD_LIBRARY_PATH=$ROOT/libs/$CONFIG
 export DYLD_LIBRARY_PATH=$ROOT/libs/$CONFIG
 export PATH=$ROOT/bins/$CONFIG:$ROOT/bins/$CONFIG/protobuf:$PATH
@@ -43,9 +42,8 @@ export LDFLAGS="-L$ROOT/libs/$CONFIG"
 export GRPC_PYTHON_BUILD_WITH_CYTHON=1
 export GRPC_PYTHON_ENABLE_CYTHON_TRACING=1
 
-cd $GRPCIO
 tox
 
 mkdir -p $ROOT/reports
 rm -rf $ROOT/reports/python-coverage
-(mv -T $GRPCIO/htmlcov $ROOT/reports/python-coverage) || true
+(mv -T $ROOT/htmlcov $ROOT/reports/python-coverage) || true
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000000000000000000000000000000000000..a655935219f9cd537132d4a72781b3dc5ca3c775
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,26 @@
+# GRPC Python tox (test environment) settings
+[tox]
+skipsdist = true
+envlist = py27
+
+[testenv]
+setenv =
+    PYGRPC_ROOT = {toxinidir}/src/python/grpcio/
+commands =
+    {envpython} setup.py build_py
+    {envpython} setup.py test
+    {envbindir}/coverage combine
+# TODO(atash): we currently ignore cygrpc.pyx due to an insufficiency in Cython's coverage plug-in. Discussion is ongoing.
+    {envbindir}/coverage html --include='{env:PYGRPC_ROOT}/grpc/*' --omit='{env:PYGRPC_ROOT}/grpc/framework/alpha/*','{env:PYGRPC_ROOT}/grpc/early_adopter/*','{env:PYGRPC_ROOT}/grpc/framework/base/*','{env:PYGRPC_ROOT}/grpc/framework/face/*','{env:PYGRPC_ROOT}/grpc/_adapter/fore.py','{env:PYGRPC_ROOT}/grpc/_adapter/rear.py','{env:PYGRPC_ROOT}/grpc/_cython/cygrpc.pyx'
+    {envbindir}/coverage report --include='{env:PYGRPC_ROOT}/grpc/*' --omit='{env:PYGRPC_ROOT}/grpc/framework/alpha/*','{env:PYGRPC_ROOT}/grpc/early_adopter/*','{env:PYGRPC_ROOT}/grpc/framework/base/*','{env:PYGRPC_ROOT}/grpc/framework/face/*','{env:PYGRPC_ROOT}/grpc/_adapter/fore.py','{env:PYGRPC_ROOT}/grpc/_adapter/rear.py','{env:PYGRPC_ROOT}/grpc/_cython/cygrpc.pyx'
+deps =
+    -rrequirements.txt
+passenv = *
+
+[testenv:interop_client]
+commands =
+    {envpython} setup.py run_interop --client --args='{posargs}'
+
+[testenv:interop_server]
+commands =
+    {envpython} setup.py run_interop --server --args='{posargs}'