Created
February 10, 2025 22:56
-
-
Save wrouesnel/84d2b3c2e122fc261ff7d99fc00172ac to your computer and use it in GitHub Desktop.
Extended click parameter types
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import csv | |
import typing | |
import typing as t | |
import click | |
from furl import furl | |
from timelength.timelength import TimeLength | |
class TimelengthType(click.ParamType): | |
name = "timelength" | |
def convert( | |
self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] | |
) -> t.Any: | |
return TimeLength(value) | |
class URLParamType(click.ParamType): | |
name = "url" | |
def convert( | |
self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] | |
) -> t.Any: | |
return furl(value) | |
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, | |
) | |
class ListParamType(click.ParamType): | |
""" | |
Represents the list type of a CLI parameter. | |
Validates and converts values from the command line string or Python into | |
a Python list. | |
- All values must be separated by one colon. | |
Usage | |
----- | |
@click.option("--param", default=None, type=ListParamType()) | |
def command(param): | |
... | |
CLI: command --param='value1,value2,value3' | |
Example | |
------- | |
>>> param_value = 'value1,value2,value3' | |
>>> ListParamType().convert(param_value, None, None) | |
['value1', 'value2', 'value3'] | |
>>> param_value = 'value1,"value,"' | |
>>> ListParamType().convert(param_value, None, None) | |
['value1', 'value,'] | |
""" | |
name = "list" | |
def convert(self, cli_value, param, ctx): | |
"""Converts CLI value to the list 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: | |
list: The validated and converted list. | |
Raises: | |
click.BadParameter: If the validation is failed. | |
""" | |
if isinstance(cli_value, typing.Sequence) and not isinstance( | |
cli_value, (str, bytes) | |
): | |
return cli_value | |
# Use the CSV reader to parse - this gives us handling for commented values. | |
row = next(csv.reader([cli_value])) | |
return row |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment