qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v2 01/38] [DO-NOT-MERGE] qapi: add debugging tools


From: Cleber Rosa
Subject: Re: [PATCH v2 01/38] [DO-NOT-MERGE] qapi: add debugging tools
Date: Tue, 22 Sep 2020 19:43:13 -0400

On Tue, Sep 22, 2020 at 05:00:24PM -0400, John Snow wrote:
> This adds some really childishly simple debugging tools. Maybe they're
> interesting for someone else, too?
> 
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>  scripts/qapi/debug.py | 78 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 78 insertions(+)
>  create mode 100644 scripts/qapi/debug.py
> 
> diff --git a/scripts/qapi/debug.py b/scripts/qapi/debug.py
> new file mode 100644
> index 0000000000..bacf5ee180
> --- /dev/null
> +++ b/scripts/qapi/debug.py
> @@ -0,0 +1,78 @@
> +"""
> +Small debugging facilities for mypy static analysis work.
> +(C) 2020 John Snow, for Red Hat, Inc.
> +"""
> +
> +import inspect
> +import json
> +from typing import Dict, List, Any
> +from types import FrameType
> +
> +
> +OBSERVED_TYPES: Dict[str, List[str]] = {}
> +
> +
> +# You have no idea how long it took to find this return type...
> +def caller_frame() -> FrameType:
> +    """
> +    Returns the stack frame of the caller's caller.
> +    e.g. foo() -> caller() -> caller_frame() return's foo's stack frame.
> +    """
> +    stack = inspect.stack()
> +    caller = stack[2].frame
> +    if caller is None:
> +        msg = "Python interpreter does not support stack frame inspection"
> +        raise RuntimeError(msg)
> +    return caller
> +
> +
> +def _add_type_record(name: str, typestr: str) -> None:
> +    seen = OBSERVED_TYPES.setdefault(name, [])
> +    if typestr not in seen:
> +        seen.append(typestr)
> +
> +
> +def record_type(name: str, value: Any, dict_names: bool = False) -> None:
> +    """
> +    Record the type of a variable.
> +
> +    :param name: The name of the variable
> +    :param value: The value of the variable
> +    """
> +    _add_type_record(name, str(type(value)))
> +
> +    try:
> +        for key, subvalue in value.items():
> +            subname = f"{name}.{key}" if dict_names else 
> f"{name}.[dict_value]"
> +            _add_type_record(subname, str(type(subvalue)))
> +        return
> +    except AttributeError:
> +        # (Wasn't a dict or anything resembling one.)
> +        pass
> +
> +    # str is iterable, but not in the way we want!
> +    if isinstance(value, str):
> +        return
> +
> +    try:
> +        for elem in value:
> +            _add_type_record(f"{name}.[list_elem]", str(type(elem)))
> +    except TypeError:
> +        # (Wasn't a list or anything else iterable.)
> +        pass
> +
> +
> +def show_types() -> None:
> +    """
> +    Print all of the currently known variable types to stdout.
> +    """
> +    print(json.dumps(OBSERVED_TYPES, indent=2))
> +

Maybe the following will be cheaper (no json conversion):

   pprint.pprint(OBSERVED_TYPES, indent=2)

Other than that, I'd vote for including this if there's a bit more
documentation on how to use it, or an example script.  Maybe there
already is, and I did not get to it yet.

- Cleber.

> +
> +def record_locals(show: bool = False, dict_names: bool = False) -> None:
> +    caller = caller_frame()
> +    name = caller.f_code.co_name
> +    for key, value in caller.f_locals.items():
> +        record_type(f"{name}.{key}", value, dict_names=dict_names)
> +    if show:
> +        show_types()
> -- 
> 2.26.2
> 

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]