5858FALSE_STRINGS = frozenset (['false' , 'False' , 'f' , 'no' , 'n' , '0' , 'off' ])
5959WSGI_CONTENT_HEADERS = frozenset (['CONTENT_TYPE' , 'CONTENT_LENGTH' ])
6060
61+ _PARAM_VALUE_DELIMITERS = {
62+ ',' : ',' ,
63+ '|' : '|' ,
64+ ' ' : ' ' ,
65+ 'pipeDelimited' : '|' ,
66+ 'spaceDelimited' : ' ' ,
67+ }
68+
6169# PERF(kgriffs): Avoid an extra namespace lookup when using these functions
6270strptime = datetime .strptime
6371now = datetime .now
@@ -1944,6 +1952,7 @@ def get_param_as_list(
19441952 required : Literal [True ],
19451953 store : StoreArg = ...,
19461954 default : list [str ] | None = ...,
1955+ delimiter : str | None = None ,
19471956 ) -> list [str ]: ...
19481957
19491958 @overload
@@ -1954,6 +1963,7 @@ def get_param_as_list(
19541963 required : Literal [True ],
19551964 store : StoreArg = ...,
19561965 default : list [_T ] | None = ...,
1966+ delimiter : str | None = None ,
19571967 ) -> list [_T ]: ...
19581968
19591969 @overload
@@ -1965,6 +1975,7 @@ def get_param_as_list(
19651975 store : StoreArg = ...,
19661976 * ,
19671977 default : list [str ],
1978+ delimiter : str | None = None ,
19681979 ) -> list [str ]: ...
19691980
19701981 @overload
@@ -1976,6 +1987,7 @@ def get_param_as_list(
19761987 store : StoreArg = ...,
19771988 * ,
19781989 default : list [_T ],
1990+ delimiter : str | None = None ,
19791991 ) -> list [_T ]: ...
19801992
19811993 @overload
@@ -1986,6 +1998,7 @@ def get_param_as_list(
19861998 required : bool = ...,
19871999 store : StoreArg = ...,
19882000 default : list [str ] | None = ...,
2001+ delimiter : str | None = None ,
19892002 ) -> list [str ] | None : ...
19902003
19912004 @overload
@@ -1996,6 +2009,7 @@ def get_param_as_list(
19962009 required : bool = ...,
19972010 store : StoreArg = ...,
19982011 default : list [_T ] | None = ...,
2012+ delimiter : str | None = None ,
19992013 ) -> list [_T ] | None : ...
20002014
20012015 def get_param_as_list (
@@ -2005,6 +2019,7 @@ def get_param_as_list(
20052019 required : bool = False ,
20062020 store : StoreArg = None ,
20072021 default : list [_T ] | None = None ,
2022+ delimiter : str | None = None ,
20082023 ) -> list [_T ] | list [str ] | None :
20092024 """Return the value of a query string parameter as a list.
20102025
@@ -2033,7 +2048,33 @@ def get_param_as_list(
20332048 the value of the param, but only if the param is found (default
20342049 ``None``).
20352050 default (any): If the param is not found returns the
2036- given value instead of ``None``
2051+ given value instead of ``None``.
2052+ delimiter(str): An optional character for splitting a parameter
2053+ value into a list. In addition to the ``','``, ``' '``, and
2054+ ``'|'`` characters, the ``'spaceDelimited'`` and
2055+ ``'pipeDelimited'`` symbolic constants from the
2056+ `OpenAPI v3 parameter specification
2057+ <https://spec.openapis.org/oas/v3.2.0.html#style-values>`__
2058+ are also supported.
2059+
2060+ Note:
2061+ If the parameter was already passed as an array, e.g., as
2062+ multiple instances (the OAS ``'explode'`` style), the
2063+ `delimiter` argument has no effect.
2064+
2065+ Note:
2066+ In contrast to the automatic splitting of comma-separated
2067+ values via the
2068+ :attr:`~falcon.RequestOptions.auto_parse_qs_csv` option,
2069+ values are split by `delimiter` **after** percent-decoding
2070+ the query string.
2071+
2072+ The :attr:`~falcon.RequestOptions.keep_blank_qs_values`
2073+ option has no effect on the secondary splitting by
2074+ `delimiter` either.
2075+
2076+ .. versionadded:: 4.3
2077+ The `delimiter` keyword argument.
20372078
20382079 Returns:
20392080 list: The value of the param if it is found. Otherwise, returns
@@ -2053,6 +2094,15 @@ def get_param_as_list(
20532094 :attr:`~falcon.RequestOptions.auto_parse_qs_csv` option must be
20542095 set to ``True``.
20552096
2097+ Even if the :attr:`~falcon.RequestOptions.auto_parse_qs_csv` option
2098+ is set (by default) to ``False``, a value can also be split into
2099+ list elements by using an OpenAPI spec-compatible delimiter, e.g.:
2100+
2101+ >>> req
2102+ <Request: GET 'http://falconframework.org/?colors=blue%7Cblack%7Cbrown'>
2103+ >>> req.get_param_as_list('colors', delimiter='pipeDelimited')
2104+ ['blue', 'black', 'brown']
2105+
20562106 Raises:
20572107 HTTPBadRequest: A required param is missing from the request, or
20582108 a transform function raised an instance of ``ValueError``.
@@ -2066,6 +2116,16 @@ def get_param_as_list(
20662116 if name in params :
20672117 items = params [name ]
20682118
2119+ # NOTE(bricklayer25): If a delimiter is specified AND the param is
2120+ # a single string, split it.
2121+ if delimiter is not None and isinstance (items , str ):
2122+ if delimiter not in _PARAM_VALUE_DELIMITERS :
2123+ raise ValueError (
2124+ f'Unsupported delimiter value: { delimiter !r} ;'
2125+ f' supported: { tuple (_PARAM_VALUE_DELIMITERS )} '
2126+ )
2127+ items = items .split (_PARAM_VALUE_DELIMITERS [delimiter ])
2128+
20692129 # NOTE(warsaw): When a key appears multiple times in the request
20702130 # query, it will already be represented internally as a list.
20712131 # NOTE(kgriffs): Likewise for comma-delimited values.
0 commit comments