fix: parsing of YAML config params with "=" signs

Close #405.
This commit is contained in:
Régis Behmo 2021-03-08 12:20:46 +01:00
parent 41bb6fe190
commit 070b75caa4
4 changed files with 31 additions and 20 deletions

View File

@ -4,6 +4,7 @@ Note: Breaking changes between versions are indicated by "💥".
## Unreleased
- [Bugfix] Fix parsing of YAML CLI arguments that include equal "=" signs.
- [Bugfix] Fix minor edge case in `long_to_base64` utility function.
## v11.2.3 (2021-02-20)

View File

@ -1,5 +1,7 @@
import unittest
import click
from tutor import serialize
@ -29,7 +31,11 @@ class SerializeTests(unittest.TestCase):
def test_parse_empty_string(self):
self.assertEqual("", serialize.parse("''"))
# def test_dump_null(self):# # Unfortunately, this fails as the output is "null\n...\n"
# self.assertEqual("null", serialize.dumps(None))
def test_yaml_param_type(self):
param = serialize.YamlParamType()
self.assertEqual(("name", True), param.convert("name=true", "param", {}))
self.assertEqual(("name", "abcd"), param.convert("name=abcd", "param", {}))
self.assertEqual(("name", ""), param.convert("name=", "param", {}))
with self.assertRaises(click.exceptions.BadParameter):
param.convert("name", "param", {})
self.assertEqual(("x", "a=bcd"), param.convert("x=a=bcd", "param", {}))

View File

@ -17,28 +17,13 @@ def config_command():
pass
class YamlParamType(click.ParamType):
name = "yaml"
def convert(self, value, param, ctx):
try:
k, v = value.split("=")
except ValueError:
self.fail("'{}' is not of the form 'key=value'.".format(value), param, ctx)
if not v:
# Empty strings are incorrectly interpreted as null values, which is
# incorrect.
v = "''"
return k, serialize.parse(v)
@click.command(help="Create and save configuration interactively")
@click.option("-i", "--interactive", is_flag=True, help="Run interactively")
@click.option(
"-s",
"--set",
"set_vars",
type=YamlParamType(),
type=serialize.YamlParamType(),
multiple=True,
metavar="KEY=VAL",
help="Set a configuration value (can be used multiple times)",

View File

@ -1,7 +1,10 @@
import re
import yaml
from yaml.parser import ParserError
from yaml.scanner import ScannerError
import click
def load(stream):
return yaml.load(stream, Loader=yaml.SafeLoader)
@ -28,3 +31,19 @@ def parse(v):
except (ParserError, ScannerError):
pass
return v
class YamlParamType(click.ParamType):
name = "yaml"
PARAM_REGEXP = r"(?P<key>[a-zA-Z0-9_-]+)=(?P<value>.*)"
def convert(self, value, param, ctx):
match = re.match(self.PARAM_REGEXP, value)
if not match:
self.fail("'{}' is not of the form 'key=value'.".format(value), param, ctx)
key = match.groupdict()["key"]
value = match.groupdict()["value"]
if not value:
# Empty strings are interpreted as null values, which is incorrect.
value = "''"
return key, parse(value)