Add a metadata_transformer to the Python stub.
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index d32213f..72149bc 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -354,6 +354,7 @@
         "Service", service->name(),
       });
   out->Print(dict, "def early_adopter_create_$Service$_stub(host, port,"
+             " metadata_transformer=None,"
              " secure=False, root_certificates=None, private_key=None,"
              " certificate_chain=None, server_host_override=None):\n");
   {
@@ -423,7 +424,8 @@
     out->Print(
         "return implementations.stub("
         "\"$PackageQualifiedServiceName$\","
-        " method_invocation_descriptions, host, port, secure=secure,"
+        " method_invocation_descriptions, host, port,"
+        " metadata_transformer=metadata_transformer, secure=secure,"
         " root_certificates=root_certificates, private_key=private_key,"
         " certificate_chain=certificate_chain,"
         " server_host_override=server_host_override)\n",
diff --git a/src/python/src/grpc/_adapter/_links_test.py b/src/python/src/grpc/_adapter/_links_test.py
index cfdcc2c..4987be3 100644
--- a/src/python/src/grpc/_adapter/_links_test.py
+++ b/src/python/src/grpc/_adapter/_links_test.py
@@ -43,6 +43,14 @@
 _TIMEOUT = 2
 
 
+# TODO(nathaniel): End-to-end metadata testing.
+def _transform_metadata(unused_metadata):
+  return (
+      ('one unused key', 'one unused value'),
+      ('another unused key', 'another unused value'),
+)
+
+
 class RoundTripTest(unittest.TestCase):
 
   def setUp(self):
@@ -76,7 +84,8 @@
 
     rear_link = rear.RearLink(
         'localhost', port, self.rear_link_pool, {test_method: None},
-        {test_method: None}, False, None, None, None)
+        {test_method: None}, False, None, None, None,
+        metadata_transformer=_transform_metadata)
     rear_link.join_fore_link(test_fore_link)
     test_fore_link.join_rear_link(rear_link)
     rear_link.start()
diff --git a/src/python/src/grpc/_adapter/rear.py b/src/python/src/grpc/_adapter/rear.py
index f19321c..2b93aa6 100644
--- a/src/python/src/grpc/_adapter/rear.py
+++ b/src/python/src/grpc/_adapter/rear.py
@@ -93,7 +93,7 @@
   def __init__(
       self, host, port, pool, request_serializers, response_deserializers,
       secure, root_certificates, private_key, certificate_chain,
-      server_host_override=None):
+      metadata_transformer=None, server_host_override=None):
     """Constructor.
 
     Args:
@@ -111,6 +111,9 @@
         key should be used.
       certificate_chain: The PEM-encoded certificate chain to use or None if
         no certificate chain should be used.
+      metadata_transformer: A function that given a metadata object produces
+        another metadata to be used in the underlying communication on the
+        wire.
       server_host_override: (For testing only) the target name used for SSL
         host name checking.
     """
@@ -134,6 +137,7 @@
     self._root_certificates = root_certificates
     self._private_key = private_key
     self._certificate_chain = certificate_chain
+    self._metadata_transformer = metadata_transformer
     self._server_host_override = server_host_override
 
   def _on_write_event(self, operation_id, event, rpc_state):
@@ -243,6 +247,10 @@
     """
     request_serializer = self._request_serializers[name]
     call = _low.Call(self._channel, name, self._host, time.time() + timeout)
+    if self._metadata_transformer is not None:
+      metadata = self._metadata_transformer([])
+      for metadata_key, metadata_value in metadata:
+        call.add_metadata(metadata_key, metadata_value)
     call.invoke(self._completion_queue, operation_id, operation_id)
     outstanding = set(_INVOCATION_EVENT_KINDS)
 
diff --git a/src/python/src/grpc/early_adopter/implementations.py b/src/python/src/grpc/early_adopter/implementations.py
index 7d3d29f..35456d3 100644
--- a/src/python/src/grpc/early_adopter/implementations.py
+++ b/src/python/src/grpc/early_adopter/implementations.py
@@ -114,7 +114,7 @@
 
   def __init__(
       self, breakdown, host, port, secure, root_certificates, private_key,
-      certificate_chain, server_host_override=None):
+      certificate_chain, metadata_transformer=None, server_host_override=None):
     self._lock = threading.Lock()
     self._breakdown = breakdown
     self._host = host
@@ -123,6 +123,7 @@
     self._root_certificates = root_certificates
     self._private_key = private_key
     self._certificate_chain = certificate_chain
+    self._metadata_transformer = metadata_transformer
     self._server_host_override = server_host_override
 
     self._pool = None
@@ -141,6 +142,7 @@
             self._breakdown.request_serializers,
             self._breakdown.response_deserializers, self._secure,
             self._root_certificates, self._private_key, self._certificate_chain,
+            metadata_transformer=self._metadata_transformer,
             server_host_override=self._server_host_override)
         self._front.join_rear_link(self._rear_link)
         self._rear_link.join_fore_link(self._front)
@@ -189,8 +191,9 @@
 
 
 def stub(
-    service_name, methods, host, port, secure=False, root_certificates=None,
-    private_key=None, certificate_chain=None, server_host_override=None):
+    service_name, methods, host, port, metadata_transformer=None, secure=False,
+    root_certificates=None, private_key=None, certificate_chain=None,
+    server_host_override=None):
   """Constructs an interfaces.Stub.
 
   Args:
@@ -201,6 +204,9 @@
       not qualified by the service name or decorated in any other way.
     host: The host to which to connect for RPC service.
     port: The port to which to connect for RPC service.
+    metadata_transformer: A callable that given a metadata object produces
+      another metadata object to be used in the underlying communication on the
+      wire.
     secure: Whether or not to construct the stub with a secure connection.
     root_certificates: The PEM-encoded root certificates or None to ask for
       them to be retrieved from a default location.