[PATCH] tbot_contrib/utils.py: convert a string into a dictionary via a pattern

Harald Seiler hws at denx.de
Tue May 5 17:02:40 CEST 2020


Hello Heiko,

On Mon, 2020-04-20 at 15:51 +0200, Heiko Schocher wrote:
> introduce function string_to_dict(), which converts
> a string into dictionary via a pattern.

Can you quickly explain where this helper is useful to you?  IMO the name
string_to_dict() doesn't really hint at what it does.  If I can see this
correctly, this is kind of a reverse string formatting.  So maybe
match_format(), parse_format(), or unformat() would be more appropriate?

> Signed-off-by: Heiko Schocher <hs at denx.de>
> ---
> 
>  tbot_contrib/utils.py | 25 +++++++++++++++++++++++++
>  1 file changed, 25 insertions(+)
> 
> diff --git a/tbot_contrib/utils.py b/tbot_contrib/utils.py
> index 8073f89..1afb65b 100644
> --- a/tbot_contrib/utils.py
> +++ b/tbot_contrib/utils.py
> @@ -15,6 +15,7 @@
>  # along with this program.  If not, see <https://www.gnu.org/licenses/>;;;.
>  
>  from tbot.machine import linux
> +import re
>  
>  
>  def check_systemd_services_running(lnx: linux.LinuxShell, services: list) -> None:
> @@ -29,3 +30,27 @@ def check_systemd_services_running(lnx: linux.LinuxShell, services: list) -> Non
>          ret = lnx.exec("systemctl", "status", s, "--no-pager")
>          if ret[0] != 0:
>              lnx.test("sudo", "systemctl", "start", s)
> +
> +
> +def string_to_dict(string: str, pattern: str) -> dict:

Annotation for the return type needs to be typing.Dict[str, str].

Also, to keep consistent with the rest of Python (e.g. the `re` module),
the arguments should be switched so that pattern comes first.

> +    """
> +    convert a string into a dictionary via a pattern
> +
> +    example pattern:
> +    'hello, my name is {name} and I am a {age} year old {what}'
> +
> +    string:
> +    'hello, my name is dan and I am a 33 year old developer'
> +
> +    returned dict:
> +    {'age': '33', 'name': 'dan', 'what': 'developer'}
> +    from:
> +    https://stackoverflow.com/questions/11844986/convert-or-unformat-a-string-to-variables-like-format-but-in-reverse-in-p
> +    """
> +    regex = re.sub(r"{(.+?)}", r"(?P<_\1>.+)", pattern)

The match-pattern used here, `(?P<_group>.+)` matches greedy.  This means
for your above example that the following string

    hello, my name is dan and I am a 33 year old developer and I am a 33 year old developer

will yield

    {'name': 'dan and I am a 33 year old developer', 'age': '33',
     'what': 'developer'}

Not sure if this is a problem though.  It could be changed by using
`(?P<_group>.+?)` instead if non-greedy behavior is more desirable.

> +    match = re.search(regex, string)
> +    assert match is not None, f"The pattern {regex!r} was not found!"
> +    values = list(match.groups())
> +    keys = re.findall(r"{(.+?)}", pattern)
> +    _dict = dict(zip(keys, values))
> +    return _dict
-- 
Harald



More information about the tbot mailing list