Repository: googleapis/gapic-generator-python

Issue:
Allow package name to be customized via a generator option
https://github.com/googleapis/gapic-generator-python/blob/f86a47b6431e374ae1797061511b49fe6bf22daf/gapic/schema/naming.py#L186-L193
Occasionally we want to deviate from the generated provided `api.naming.warehouse_package_name`.

* The published package includes two GAPICs (firestore admin and firestore) and we want the library to be consistently named `google-cloud-firestore`.
* The API has a long name and we want to rename the package to make it easier to spell.
`google-cloud-assuredworkloads` -> `google-cloud-assured-workloads`.

The name is used to identify the library in request headers so it is somewhat important.

https://github.com/googleapis/gapic-generator-python/blob/af17501d258c7c37fc1081fcad5fe18f7629f4c3/gapic/templates/%25namespace/%25name_%25version/%25sub/services/%25service/transports/base.py.j2#L29-L33

CC @crwilcox 

Comments:

Patch:
diff --git a/gapic/schema/naming.py b/gapic/schema/naming.py
index c591ad59..3f49a18a 100644
--- a/gapic/schema/naming.py
+++ b/gapic/schema/naming.py
@@ -42,6 +42,7 @@ class Naming(abc.ABC):
     version: str = ''
     product_name: str = ''
     proto_package: str = ''
+    _warehouse_package_name: str = ''
 
     def __post_init__(self):
         if not self.product_name:
@@ -141,6 +142,10 @@ class Naming(abc.ABC):
                 # with ('x.y',) will become a two-tuple: ('x', 'y')
                 i.capitalize() for i in '.'.join(opts.namespace).split('.')
             ))
+        if opts.warehouse_package_name:
+            package_info = dataclasses.replace(package_info,
+                _warehouse_package_name=opts.warehouse_package_name
+                                               )
 
         # Done; return the naming information.
         return package_info
@@ -186,9 +191,11 @@ class Naming(abc.ABC):
     @property
     def warehouse_package_name(self) -> str:
         """Return the appropriate Python package name for Warehouse."""
-
-        # Piece the name and namespace together to come up with the
-        # proper package name.
+        # If a custom name has been set, use it
+        if self._warehouse_package_name:
+            return self._warehouse_package_name
+        # Otherwise piece the name and namespace together to come
+        # up with the proper package name.
         answer = list(self.namespace) + self.name.split(' ')
         return '-'.join(answer).lower()
 
diff --git a/gapic/utils/options.py b/gapic/utils/options.py
index d99e34c6..b8e79a06 100644
--- a/gapic/utils/options.py
+++ b/gapic/utils/options.py
@@ -34,6 +34,7 @@ class Options:
     """
     name: str = ''
     namespace: Tuple[str, ...] = dataclasses.field(default=())
+    warehouse_package_name: str = ''
     retry: Optional[Dict[str, Any]] = None
     sample_configs: Tuple[str, ...] = dataclasses.field(default=())
     templates: Tuple[str, ...] = dataclasses.field(default=('DEFAULT',))
@@ -53,6 +54,7 @@ class Options:
         'add-iam-methods',      # microgenerator implementation for `reroute_to_grpc_interface`
         # transport type(s) delineated by '+' (i.e. grpc, rest, custom.[something], etc?)
         'transport',
+        'warehouse-package-name'  # change the package name on PyPI
     ))
 
     @classmethod
@@ -129,6 +131,8 @@ class Options:
         answer = Options(
             name=opts.pop('name', ['']).pop(),
             namespace=tuple(opts.pop('namespace', [])),
+            warehouse_package_name=opts.pop(
+                'warehouse-package-name', ['']).pop(),
             retry=retry_cfg,
             sample_configs=tuple(
                 cfg_path


Test patch:
diff --git a/tests/unit/generator/test_options.py b/tests/unit/generator/test_options.py
index 5235c2e4..60d365a8 100644
--- a/tests/unit/generator/test_options.py
+++ b/tests/unit/generator/test_options.py
@@ -152,3 +152,8 @@ def test_options_old_naming():
 def test_options_add_iam_methods():
     opts = Options.build('add-iam-methods')
     assert opts.add_iam_methods
+
+
+def test_options_warehouse_package_name():
+    opts = Options.build('warehouse-package-name')
+    assert opts.warehouse_package_name
diff --git a/tests/unit/schema/test_naming.py b/tests/unit/schema/test_naming.py
index ec1e0dad..c0487b7d 100644
--- a/tests/unit/schema/test_naming.py
+++ b/tests/unit/schema/test_naming.py
@@ -218,6 +218,16 @@ def test_cli_override_name_and_namespace_versionless():
     assert not n.version
 
 
+def test_cli_override_warehouse_package_name():
+    FileDesc = descriptor_pb2.FileDescriptorProto
+    proto1 = FileDesc(package='google.translation')
+    n = naming.Naming.build(
+        proto1,
+        opts=Options(warehouse_package_name='google-cloud-foo'),
+    )
+    assert n.warehouse_package_name == "google-cloud-foo"
+
+
 def test_build_factory():
     proto = descriptor_pb2.FileDescriptorProto(
         package='google.mollusc.v1alpha1'