Skip to content

Commit

Permalink
Add support for stringArray and operationContextParams (boto#3301)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexgromero authored and hswong3i committed Dec 10, 2024
1 parent b36ec84 commit 6e433bd
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 2 deletions.
3 changes: 2 additions & 1 deletion botocore/endpoint_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,7 @@ class ParameterType(Enum):

string = str
boolean = bool
stringarray = tuple


class ParameterDefinition:
Expand All @@ -600,7 +601,7 @@ def __init__(
except AttributeError:
raise EndpointResolutionError(
msg=f"Unknown parameter type: {parameter_type}. "
"A parameter must be of type string or boolean."
"A parameter must be of type string, boolean, or stringarray."
)
self.documentation = documentation
self.builtin = builtIn
Expand Down
4 changes: 4 additions & 0 deletions botocore/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,10 @@ def context_parameters(self):
and 'name' in shape.metadata['contextParam']
]

@CachedProperty
def operation_context_parameters(self):
return self._operation_model.get('operationContextParams', [])

@CachedProperty
def request_compression(self):
return self._operation_model.get('requestcompression')
Expand Down
17 changes: 17 additions & 0 deletions botocore/regions.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import re
from enum import Enum

import jmespath

from botocore import UNSIGNED, xform_name
from botocore.auth import AUTH_TYPE_MAPS, HAS_CRT
from botocore.crt import CRT_SUPPORTED_AUTH_TYPES
Expand Down Expand Up @@ -578,6 +580,13 @@ def _resolve_param_from_context(
)
if dynamic is not None:
return dynamic
operation_context_params = (
self._resolve_param_as_operation_context_param(
param_name, operation_model, call_args
)
)
if operation_context_params is not None:
return operation_context_params
return self._resolve_param_as_client_context_param(param_name)

def _resolve_param_as_static_context_param(
Expand All @@ -600,6 +609,14 @@ def _resolve_param_as_client_context_param(self, param_name):
client_ctx_varname = client_ctx_params[param_name]
return self._client_context.get(client_ctx_varname)

def _resolve_param_as_operation_context_param(
self, param_name, operation_model, call_args
):
operation_ctx_params = operation_model.operation_context_parameters
if param_name in operation_ctx_params:
path = operation_ctx_params[param_name]['path']
return jmespath.search(path, call_args)

def _resolve_param_as_builtin(self, builtin_name, builtins):
if builtin_name not in EndpointResolverBuiltins.__members__.values():
raise UnknownEndpointResolutionBuiltInName(name=builtin_name)
Expand Down
5 changes: 4 additions & 1 deletion botocore/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1479,7 +1479,7 @@ def lru_cache_weakref(*cache_args, **cache_kwargs):
functools implementation which offers ``max_size`` and ``typed`` properties.
lru_cache is a global cache even when used on a method. The cache's
reference to ``self`` will prevent garbace collection of the object. This
reference to ``self`` will prevent garbage collection of the object. This
wrapper around functools.lru_cache replaces the reference to ``self`` with
a weak reference to not interfere with garbage collection.
"""
Expand All @@ -1491,6 +1491,9 @@ def func_with_weakref(weakref_to_self, *args, **kwargs):

@functools.wraps(func)
def inner(self, *args, **kwargs):
for kwarg_key, kwarg_value in kwargs.items():
if isinstance(kwarg_value, list):
kwargs[kwarg_key] = tuple(kwarg_value)
return func_with_weakref(weakref.ref(self), *args, **kwargs)

inner.cache_info = func_with_weakref.cache_info
Expand Down
37 changes: 37 additions & 0 deletions tests/unit/data/endpoints/test-cases/array-index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"version": "1.0",
"testCases": [
{
"documentation": "Access an array index at index 0",
"params": {
"ResourceList": ["resource"]
},
"expect": {
"endpoint": {
"url": "https://www.resource.example.com"
}
}
},
{
"documentation": "Resolved value when array is explictly set to empty",
"params": {
"ResourceList": []
},
"expect": {
"endpoint": {
"url": "https://www.example.com"
}
}
},
{
"documentation": "Resolved value to default if array is unset",
"params": {
},
"expect": {
"endpoint": {
"url": "https://www.default1.example.com"
}
}
}
]
}
47 changes: 47 additions & 0 deletions tests/unit/data/endpoints/valid-rules/array-index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"version": "1.3",
"parameters": {
"ResourceList": {
"required": true,
"default": ["default1", "default2"],
"type": "stringArray"
}
},
"rules": [
{
"documentation": "Array is set, retrieve index 0",
"conditions": [
{
"fn": "isSet",
"argv": [
{
"ref": "ResourceList"
}
]
},
{
"fn": "getAttr",
"argv": [
{
"ref": "ResourceList"
},
"[0]"
],
"assign": "resourceid"
}
],
"endpoint": {
"url": "https://www.{resourceid}.example.com"
},
"type": "endpoint"
},
{
"documentation": "Fallback when array is unset",
"conditions": [],
"endpoint": {
"url": "https://www.example.com"
},
"type": "endpoint"
}
]
}
1 change: 1 addition & 0 deletions tests/unit/test_endpoint_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ def endpoint_rule():

def ruleset_testcases():
filenames = [
"array-index",
"aws-region",
"default-values",
"eventbridge",
Expand Down

0 comments on commit 6e433bd

Please sign in to comment.