Skip to content

Instantly share code, notes, and snippets.

@welel
Created June 10, 2023 10:38
Show Gist options
  • Save welel/9cf860dd3f4d3e09f9b4305878b3a04e to your computer and use it in GitHub Desktop.
Save welel/9cf860dd3f4d3e09f9b4305878b3a04e to your computer and use it in GitHub Desktop.
Custom dict type for the Python library click.
import click
class DictParamType(click.ParamType):
"""Represents the dictionary type of a CLI parameter.
Validates and converts values from the command line string or Python into
a Python dict.
- All key-value pairs must be separated by one semicolon.
- Key and value must be separated by one equal sign.
- Converts sequences separeted by dots into a list: list value items
must be separated by commas.
- Converts numbers to int.
Usage:
>>> @click.option("--param", default=None, type=DictParamType())
... def command(param):
... ...
CLI: command --param='page=1; name=Items; rules=1, 2, three; extra=A,;'
Example:
>>> param_value = 'page=1; name=Items; rules=1, 2, three; extra=A,;'
>>> DictParamType().convert(param_value, None, None)
{'page': 1, 'name': 'Items', 'rules': [1, 2, 'three'], 'extra': ['A']}`
"""
name = "dictionary"
def convert(self, cli_value, param, ctx):
"""Converts CLI value to the dictionary structure.
Args:
cli_value (Any): The value to convert.
param (click.Parameter | None): The parameter that is using this
type to convert its value.
ctx (click.Context | None): The current context that arrived
at this value.
Returns:
dict: The validated and converted dictionary.
Raises:
click.BadParameter: If the validation is failed.
"""
if isinstance(cli_value, dict):
return cli_value
try:
keyvalue_pairs = cli_value.rstrip(";").split(";")
result_dict = {}
for pair in keyvalue_pairs:
key, values = [item.strip() for item in pair.split("=")]
converted_values = []
for value in values.split(","):
value = value.strip()
if value.isdigit():
value = int(value)
converted_values.append(value)
if len(converted_values) == 1:
result_dict[key] = converted_values[0]
elif len(converted_values) > 1 and converted_values[-1] == "":
result_dict[key] = converted_values[:-1]
else:
result_dict[key] = converted_values
return result_dict
except ValueError:
self.fail(
"All key-value pairs must be separated by one semicolon. "
"Key and value must be separated by one equal sign. "
"List value items must be separated by one comma. "
f"Key-value: {pair}.",
param,
ctx
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment