[{"id":22893,"web_url":"https://patchwork.libcamera.org/comment/22893/","msgid":"<YnVMw4qOhtICPeI2@pendragon.ideasonboard.com>","date":"2022-05-06T16:28:51","subject":"Re: [libcamera-devel] [PATCH v8 5/7] py: generate control enums\n\tfrom yaml","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Tomi,\n\nThank you for the patch.\n\nOn Fri, May 06, 2022 at 05:54:12PM +0300, Tomi Valkeinen wrote:\n> Generate enums for controls from control_ids.yaml. The generator script\n> has some heuristics to generate nicer enum names. E.g. instead of having\n> \"LensShadingMapMode.LensShadingMapModeOff\" we get\n> \"LensShadingMapMode.Off\". This heuristics may need to be updated when\n> the yaml file is changed or new controls are added.\n> \n> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>\n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  src/py/libcamera/gen-py-control-enums.py  | 95 +++++++++++++++++++++++\n>  src/py/libcamera/meson.build              | 12 +++\n>  src/py/libcamera/pyenums_generated.cpp.in | 21 +++++\n>  src/py/libcamera/pymain.cpp               |  2 +\n>  4 files changed, 130 insertions(+)\n>  create mode 100755 src/py/libcamera/gen-py-control-enums.py\n>  create mode 100644 src/py/libcamera/pyenums_generated.cpp.in\n> \n> diff --git a/src/py/libcamera/gen-py-control-enums.py b/src/py/libcamera/gen-py-control-enums.py\n> new file mode 100755\n> index 00000000..dcc28b1a\n> --- /dev/null\n> +++ b/src/py/libcamera/gen-py-control-enums.py\n> @@ -0,0 +1,95 @@\n> +#!/usr/bin/env python3\n> +# SPDX-License-Identifier: GPL-2.0-or-later\n> +#\n> +# Generate Python bindings enums for controls from YAML\n> +\n> +import argparse\n> +import string\n> +import sys\n> +import yaml\n> +\n> +\n> +def find_common_prefix(strings):\n> +    prefix = strings[0]\n> +\n> +    for string in strings[1:]:\n> +        while string[:len(prefix)] != prefix and prefix:\n> +            prefix = prefix[:len(prefix) - 1]\n> +        if not prefix:\n> +            break\n> +\n> +    return prefix\n> +\n> +\n> +def generate_py(controls):\n> +    out = ''\n> +\n> +    for ctrl in controls:\n> +        name, ctrl = ctrl.popitem()\n> +\n> +        enum = ctrl.get('enum')\n> +        if not enum:\n> +            continue\n> +\n> +        if ctrl.get('draft'):\n> +            ns = 'libcamera::controls::draft::'\n> +        else:\n> +            ns = 'libcamera::controls::'\n> +\n> +        cpp_enum = name + 'Enum'\n> +\n> +        out += '\\tpy::enum_<{}{}>(m, \\\"{}\\\")\\n'.format(ns, cpp_enum, name)\n> +\n> +        if name == 'LensShadingMapMode':\n> +            prefix = 'LensShadingMapMode'\n> +        else:\n> +            prefix = find_common_prefix([e['name'] for e in enum])\n> +\n> +        for entry in enum:\n> +            cpp_enum = entry['name']\n> +            py_enum = entry['name'][len(prefix):]\n> +\n> +            out += '\\t\\t.value(\\\"{}\\\", {}{})\\n'.format(py_enum, ns, cpp_enum)\n> +\n> +        out += '\\t;\\n'\n> +\n> +    return {'enums': out}\n> +\n> +\n> +def fill_template(template, data):\n> +    template = open(template, 'rb').read()\n> +    template = template.decode('utf-8')\n> +    template = string.Template(template)\n> +    return template.substitute(data)\n> +\n> +\n> +def main(argv):\n> +    # Parse command line arguments\n> +    parser = argparse.ArgumentParser()\n> +    parser.add_argument('-o', dest='output', metavar='file', type=str,\n> +                        help='Output file name. Defaults to standard output if not specified.')\n> +    parser.add_argument('input', type=str,\n> +                        help='Input file name.')\n> +    parser.add_argument('template', type=str,\n> +                        help='Template file name.')\n> +    args = parser.parse_args(argv[1:])\n> +\n> +    data = open(args.input, 'rb').read()\n> +    controls = yaml.safe_load(data)['controls']\n> +\n> +    data = generate_py(controls)\n> +\n> +    data = fill_template(args.template, data)\n> +\n> +    if args.output:\n> +        output = open(args.output, 'wb')\n> +        output.write(data.encode('utf-8'))\n> +        output.close()\n> +    else:\n> +        sys.stdout.write(data)\n> +\n> +    return 0\n> +\n> +\n> +if __name__ == '__main__':\n> +    sys.exit(main(sys.argv))\n> diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build\n> index e4abc34a..f4c7590c 100644\n> --- a/src/py/libcamera/meson.build\n> +++ b/src/py/libcamera/meson.build\n> @@ -17,6 +17,18 @@ pycamera_sources = files([\n>      'pymain.cpp',\n>  ])\n>  \n> +gen_input_files = [\n> +    meson.project_source_root() / 'src' / 'libcamera' / 'control_ids.yaml',\n> +    'pyenums_generated.cpp.in'\n\nYou can add a comma at the end of the line. No need to resend for that,\nit can be fixed when applying.\n\n> +]\n> +\n> +generated_sources = custom_target('py_gen_controls',\n> +                                  input : gen_input_files,\n> +                                  output : ['pyenums_generated.cpp'],\n> +                                  command : ['gen-py-control-enums.py', '-o', '@OUTPUT@', '@INPUT@'])\n> +\n> +pycamera_sources += generated_sources\n> +\n>  pycamera_deps = [\n>      libcamera_public,\n>      py3_dep,\n> diff --git a/src/py/libcamera/pyenums_generated.cpp.in b/src/py/libcamera/pyenums_generated.cpp.in\n> new file mode 100644\n> index 00000000..96daf257\n> --- /dev/null\n> +++ b/src/py/libcamera/pyenums_generated.cpp.in\n> @@ -0,0 +1,21 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2021, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>\n> + *\n> + * Python bindings\n> + *\n> + * This file is auto-generated. Do not edit.\n> + */\n> +\n> +#include <libcamera/libcamera.h>\n> +\n> +#include <pybind11/smart_holder.h>\n> +\n> +namespace py = pybind11;\n> +\n> +using namespace libcamera;\n> +\n> +void init_pyenums_generated(py::module& m)\n> +{\n> +${enums}\n> +}\n> diff --git a/src/py/libcamera/pymain.cpp b/src/py/libcamera/pymain.cpp\n> index 8c3be8f4..aff672aa 100644\n> --- a/src/py/libcamera/pymain.cpp\n> +++ b/src/py/libcamera/pymain.cpp\n> @@ -131,10 +131,12 @@ static void handleRequestCompleted(Request *req)\n>  }\n>  \n>  void init_pyenums(py::module &m);\n> +void init_pyenums_generated(py::module &m);\n>  \n>  PYBIND11_MODULE(_libcamera, m)\n>  {\n>  \tinit_pyenums(m);\n> +\tinit_pyenums_generated(m);\n>  \n>  \t/* Forward declarations */\n>  \n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id B4964C3256\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  6 May 2022 16:28:58 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id ED96665646;\n\tFri,  6 May 2022 18:28:57 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9BDA1604A3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  6 May 2022 18:28:56 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id C4702492;\n\tFri,  6 May 2022 18:28:55 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1651854538;\n\tbh=kWz1bSZNAU7K92jVH6XJOuNUAxh7FbduqudxJodDIhE=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=Ws3p6cC8ql0BCLvx+5ggy81lrQr1ZYmPhMHe+leyQsoY8ywQPT77rcOVUXsADuuvq\n\t/Oc2bp7CLhQSaBbfcs612ZggowWH7aImm6h4XS5oHHQbIAA0yAf3PGEbQMPzRsqL7g\n\tCI4qNUBOqJl1KZRx6CmkByN20FbpMWJsTvv51jrqxhLNOGdLbxMRHBfe8P0IrwsyRj\n\tE6yznTidhNA0z8J71MLfL6/IpP4ENM7pScRsZPjXb6dUmYvm+pycTXFk5hDe9v4Mh/\n\t2kJG0g9Z8S9nbkbSi4Lnul2T1h3WCwDTVyhIiy2i/0XMtVgETCgus4NqcelpHQJCJM\n\tl/Tss+sAdZkig==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1651854536;\n\tbh=kWz1bSZNAU7K92jVH6XJOuNUAxh7FbduqudxJodDIhE=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=QiJecBrG5P6KTHKfKjPAsVjjXEfXCMxD161HL6ejHcRezKy9vWWj3MhnB7qLrLDP/\n\tbf3DCktfY+0MBJSN/gYEqfZRm3FHYikfJQ2QkMXBPNAP5bTUV6RENBJL5npGML3hpI\n\tv+Wazc9+V1KrQAibWT9QUa0ogrSjPRyiX4WqS81g="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"QiJecBrG\"; dkim-atps=neutral","Date":"Fri, 6 May 2022 19:28:51 +0300","To":"Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>","Message-ID":"<YnVMw4qOhtICPeI2@pendragon.ideasonboard.com>","References":"<20220506145414.99039-1-tomi.valkeinen@ideasonboard.com>\n\t<20220506145414.99039-6-tomi.valkeinen@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20220506145414.99039-6-tomi.valkeinen@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v8 5/7] py: generate control enums\n\tfrom yaml","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]