diff --git a/packages/google-api-core/google/api_core/path_template.py b/packages/google-api-core/google/api_core/path_template.py index 069112ae6e6b..128a923ae76b 100644 --- a/packages/google-api-core/google/api_core/path_template.py +++ b/packages/google-api-core/google/api_core/path_template.py @@ -123,7 +123,7 @@ def _expand_variable_match(positional_vars, named_vars, match): try: val = str(named_vars[name]) _extract_and_validate_wildcards(val, template, name) - return urllib.parse.quote(val, safe="/") + return urllib.parse.quote(val, safe="/():") except KeyError: raise ValueError( "Named variable '{}' not specified and needed by template " @@ -133,7 +133,7 @@ def _expand_variable_match(positional_vars, named_vars, match): try: val = str(positional_vars.pop(0)) _extract_and_validate_wildcards(val, positional, "positional variable") - return urllib.parse.quote(val, safe="/") + return urllib.parse.quote(val, safe="/():") except IndexError: raise ValueError( "Positional variable not specified and needed by template " diff --git a/packages/google-api-core/tests/unit/test_path_template.py b/packages/google-api-core/tests/unit/test_path_template.py index e8dead5edc6d..05edaa117205 100644 --- a/packages/google-api-core/tests/unit/test_path_template.py +++ b/packages/google-api-core/tests/unit/test_path_template.py @@ -64,6 +64,39 @@ {"name": "parent/child/object"}, "/v1/a/parent/child/object", ], + # See https://github.com/googleapis/google-cloud-python/issues/18213 + # Test parentheses in resource paths + [ + "projects/{project}/databases/{database}", + [], + {"project": "my-project", "database": "(default)"}, + "projects/my-project/databases/(default)", + ], + [ + "projects/{project}/databases/{database}/**", + ["documents/user_1"], + {"project": "my-project", "database": "(default)"}, + "projects/my-project/databases/(default)/documents/user_1", + ], + [ + "/v1/{name=projects/*/databases/*}", + [], + {"name": "projects/my-project/databases/(default)"}, + "/v1/projects/my-project/databases/(default)", + ], + # Test colon in resource paths + [ + "/v1/{name}", + [], + {"name": "my-instance:cluster-1"}, + "/v1/my-instance:cluster-1", + ], + [ + "/v1/{name=**}", + [], + {"name": "instances/my-instance:cluster-1"}, + "/v1/instances/my-instance:cluster-1", + ], # Encoding / Metacharacters in positional and named params ["/v1/*", ["..?$httpMethod=DELETE#"], {}, "/v1/..%3F%24httpMethod%3DDELETE%23"], ["/v1/**", ["path/sub/with/?and#"], {}, "/v1/path/sub/with/%3Fand%23"],