Add `user_agent` property to `ClientInfo` (#7799)

* Add `user_agent` property to `ClientInfo`

This provides a way for partners to define a prefix identifying their
tool or application, as required by many cloud partnership agreements.

* Workaround for pytype pyi error with nested class.
diff --git a/google/api_core/gapic_v1/client_info.py b/google/api_core/gapic_v1/client_info.py
index 66a4e4c..069e019 100644
--- a/google/api_core/gapic_v1/client_info.py
+++ b/google/api_core/gapic_v1/client_info.py
@@ -51,6 +51,9 @@
             library, generally used if the client library was not generated
             by gapic or if additional functionality was built on top of
             a gapic client library.
+        user_agent (Optional[str]): Prefix to the user agent header. This is
+            used to supply information such as application name or partner tool.
+            Recommended format: ``application-or-tool-ID/major.minor.version``.
     """
 
     def __init__(
@@ -60,18 +63,26 @@
         api_core_version=_API_CORE_VERSION,
         gapic_version=None,
         client_library_version=None,
+        user_agent=None,
     ):
         self.python_version = python_version
         self.grpc_version = grpc_version
         self.api_core_version = api_core_version
         self.gapic_version = gapic_version
         self.client_library_version = client_library_version
+        self.user_agent = user_agent
 
     def to_user_agent(self):
         """Returns the user-agent string for this client info."""
+
         # Note: the order here is important as the internal metrics system
         # expects these items to be in specific locations.
-        ua = "gl-python/{python_version} "
+        ua = ""
+
+        if self.user_agent is not None:
+            ua += "{user_agent} "
+
+        ua += "gl-python/{python_version} "
 
         if self.grpc_version is not None:
             ua += "grpc/{grpc_version} "
diff --git a/setup.cfg b/setup.cfg
index 581d862..5c32e16 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -8,3 +8,5 @@
 exclude =
     tests/
 output = pytype_output/
+# Workaround for https://github.com/google/pytype/issues/150
+disable = pyi-error
diff --git a/tests/unit/gapic/test_client_info.py b/tests/unit/gapic/test_client_info.py
index dbab267..0cca479 100644
--- a/tests/unit/gapic/test_client_info.py
+++ b/tests/unit/gapic/test_client_info.py
@@ -33,6 +33,7 @@
         api_core_version="3",
         gapic_version="4",
         client_library_version="5",
+        user_agent="6"
     )
 
     assert info.python_version == "1"
@@ -40,6 +41,7 @@
     assert info.api_core_version == "3"
     assert info.gapic_version == "4"
     assert info.client_library_version == "5"
+    assert info.user_agent == "6"
 
 
 def test_to_user_agent_minimal():
@@ -59,11 +61,12 @@
         api_core_version="3",
         gapic_version="4",
         client_library_version="5",
+        user_agent="app-name/1.0",
     )
 
     user_agent = info.to_user_agent()
 
-    assert user_agent == "gl-python/1 grpc/2 gax/3 gapic/4 gccl/5"
+    assert user_agent == "app-name/1.0 gl-python/1 grpc/2 gax/3 gapic/4 gccl/5"
 
 
 def test_to_grpc_metadata():