Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/139239/?format=api
http://patches.dpdk.org/api/patches/139239/?format=api", "web_url": "http://patches.dpdk.org/project/dpdk/patch/20240412111136.3470304-4-luca.vizzarro@arm.com/", "project": { "id": 1, "url": "http://patches.dpdk.org/api/projects/1/?format=api", "name": "DPDK", "link_name": "dpdk", "list_id": "dev.dpdk.org", "list_email": "dev@dpdk.org", "web_url": "http://core.dpdk.org", "scm_url": "git://dpdk.org/dpdk", "webscm_url": "http://git.dpdk.org/dpdk", "list_archive_url": "https://inbox.dpdk.org/dev", "list_archive_url_format": "https://inbox.dpdk.org/dev/{}", "commit_url_format": "" }, "msgid": "<20240412111136.3470304-4-luca.vizzarro@arm.com>", "list_archive_url": "https://inbox.dpdk.org/dev/20240412111136.3470304-4-luca.vizzarro@arm.com", "date": "2024-04-12T11:11:34", "name": "[3/5] dts: add parsing utility module", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "9b9a0a4d86d81ccb85131674122133356c4033ff", "submitter": { "id": 3197, "url": "http://patches.dpdk.org/api/people/3197/?format=api", "name": "Luca Vizzarro", "email": "luca.vizzarro@arm.com" }, "delegate": { "id": 1, "url": "http://patches.dpdk.org/api/users/1/?format=api", "username": "tmonjalo", "first_name": "Thomas", "last_name": "Monjalon", "email": "thomas@monjalon.net" }, "mbox": "http://patches.dpdk.org/project/dpdk/patch/20240412111136.3470304-4-luca.vizzarro@arm.com/mbox/", "series": [ { "id": 31729, "url": "http://patches.dpdk.org/api/series/31729/?format=api", "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=31729", "date": "2024-04-12T11:11:31", "name": "dts: testpmd show port info/stats", "version": 1, "mbox": "http://patches.dpdk.org/series/31729/mbox/" } ], "comments": "http://patches.dpdk.org/api/patches/139239/comments/", "check": "success", "checks": "http://patches.dpdk.org/api/patches/139239/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<dev-bounces@dpdk.org>", "X-Original-To": "patchwork@inbox.dpdk.org", "Delivered-To": "patchwork@inbox.dpdk.org", "Received": [ "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 0468F43E51;\n\tFri, 12 Apr 2024 13:12:10 +0200 (CEST)", "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id EEE8B40A72;\n\tFri, 12 Apr 2024 13:11:57 +0200 (CEST)", "from foss.arm.com (foss.arm.com [217.140.110.172])\n by mails.dpdk.org (Postfix) with ESMTP id 6623A40A4B\n for <dev@dpdk.org>; Fri, 12 Apr 2024 13:11:56 +0200 (CEST)", "from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14])\n by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 34C5B339;\n Fri, 12 Apr 2024 04:12:25 -0700 (PDT)", "from localhost.localdomain (unknown [10.57.19.212])\n by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id CEC4E3F766;\n Fri, 12 Apr 2024 04:11:54 -0700 (PDT)" ], "From": "Luca Vizzarro <luca.vizzarro@arm.com>", "To": "dev@dpdk.org", "Cc": "=?utf-8?q?Juraj_Linke=C5=A1?= <juraj.linkes@pantheon.tech>,\n Jeremy Spewock <jspewock@iol.unh.edu>, Luca Vizzarro <luca.vizzarro@arm.com>,\n Paul Szczepanek <paul.szczepanek@arm.com>", "Subject": "[PATCH 3/5] dts: add parsing utility module", "Date": "Fri, 12 Apr 2024 12:11:34 +0100", "Message-Id": "<20240412111136.3470304-4-luca.vizzarro@arm.com>", "X-Mailer": "git-send-email 2.34.1", "In-Reply-To": "<20240412111136.3470304-1-luca.vizzarro@arm.com>", "References": "<20240412111136.3470304-1-luca.vizzarro@arm.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "X-BeenThere": "dev@dpdk.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "DPDK patches and discussions <dev.dpdk.org>", "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>", "List-Archive": "<http://mails.dpdk.org/archives/dev/>", "List-Post": "<mailto:dev@dpdk.org>", "List-Help": "<mailto:dev-request@dpdk.org?subject=help>", "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>", "Errors-To": "dev-bounces@dpdk.org" }, "content": "Adds parsing text into a custom data structure. It provides a new\n`TextParser` dataclass to be inherited. This implements the `parse`\nmethod, which combined with the parser functions, it can automatically\nparse the value for each field.\n\nSigned-off-by: Luca Vizzarro <luca.vizzarro@arm.com>\nReviewed-by: Paul Szczepanek <paul.szczepanek@arm.com>\n---\n dts/framework/parser.py | 147 ++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 147 insertions(+)\n create mode 100644 dts/framework/parser.py", "diff": "diff --git a/dts/framework/parser.py b/dts/framework/parser.py\nnew file mode 100644\nindex 0000000000..5a2ba0c93a\n--- /dev/null\n+++ b/dts/framework/parser.py\n@@ -0,0 +1,147 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2024 Arm Limited\n+\n+\"\"\"Parsing utility module.\n+\n+This module provides :class:`~TextParser` which can be used to model any data structure\n+that can parse a block of text.\n+\"\"\"\n+\n+from dataclasses import dataclass, fields, MISSING\n+import re\n+from typing import TypeVar\n+from typing_extensions import Self\n+\n+T = TypeVar(\"T\")\n+\n+\n+META_PARSERS = \"parsers\"\n+\n+\n+def chain(parser, metadata):\n+ \"\"\"Chain a parser function.\n+\n+ The parser function can take and return a single argument of any type. It is\n+ up to the user to ensure that the chained functions have compatible types.\n+\n+ Args:\n+ parser: the parser function pointer\n+ metadata: pre-existing metadata to chain if any\n+ \"\"\"\n+ parsers = metadata.get(META_PARSERS) or []\n+ parsers.append(parser)\n+ return {**metadata, META_PARSERS: parsers}\n+\n+\n+def to_int(metadata={}, base=0):\n+ \"\"\"Converts a string to an integer.\n+\n+ Args:\n+ metadata: pre-existing metadata to chain if any\n+ base: argument passed to the constructor of ``int``\n+ \"\"\"\n+ return chain(lambda v: int(v, base), metadata)\n+\n+\n+def eq(v2, metadata={}):\n+ \"\"\"Compares two values and returns a boolean.\n+\n+ Args:\n+ v2: value to compare with the incoming value\n+ metadata: pre-existing metadata to chain if any\n+ \"\"\"\n+ return chain(lambda v1: v1 == v2, metadata)\n+\n+\n+def to_bool(metadata={}):\n+ \"\"\"Evaluates a string into a boolean.\n+\n+ The following case-insensitive words yield ``True``: on, yes, enabled, true.\n+\n+ Args:\n+ metadata: pre-existing metadata to chain if any\n+ \"\"\"\n+ return chain(lambda s: s.lower() in [\"on\", \"yes\", \"enabled\", \"true\"], metadata)\n+\n+\n+def regex(\n+ pattern: str | re.Pattern[str],\n+ flags: re.RegexFlag = re.RegexFlag(0),\n+ named: bool = False,\n+ metadata={},\n+):\n+ \"\"\"Searches for a regular expression in a text.\n+\n+ If there is only one capture group, its value is returned, otherwise a tuple containing all the\n+ capture groups values is returned instead.\n+\n+ Args:\n+ pattern: the regular expression pattern\n+ flags: the regular expression flags\n+ named: if set to True only the named capture groups will be returned as a dictionary\n+ metadata: pre-existing metadata to chain if any\n+ \"\"\"\n+ pattern = re.compile(pattern, flags)\n+\n+ def regex_parser(text: str):\n+ m = pattern.search(text)\n+ if m is None:\n+ return m\n+\n+ if named:\n+ return m.groupdict()\n+\n+ matches = m.groups()\n+ if len(matches) == 1:\n+ return matches[0]\n+\n+ return matches\n+\n+ return chain(regex_parser, metadata)\n+\n+\n+@dataclass\n+class TextParser:\n+ \"\"\"Helper abstract dataclass that parses a text according to the fields' rules.\n+\n+ This class is accompanied by a selection of parser functions and a generic chaining function,\n+ that are to be set to the fields' metadata, to enable parsing. If a field metadata is not set with\n+ any parser function, this is skipped.\n+ \"\"\"\n+\n+ @classmethod\n+ def parse(cls, text: str) -> Self:\n+ \"\"\"The parsing class method.\n+\n+ This function loops through every field that has any parser function associated with it and runs\n+ each parser chain to the supplied text. If a parser function returns None, it expects that parsing\n+ has failed and continues to the next field.\n+\n+ Args:\n+ text: the text to parse\n+ Raises:\n+ RuntimeError: if the parser did not find a match and the field does not have a default value\n+ or default factory.\n+ \"\"\"\n+ fields_values = {}\n+ for field in fields(cls):\n+ parsers = field.metadata.get(META_PARSERS)\n+ if parsers is None:\n+ continue\n+\n+ field_value = text\n+ for parser_fn in parsers:\n+ field_value = parser_fn(field_value)\n+ if field_value is None:\n+ # nothing was actually parsed, move on\n+ break\n+\n+ if field_value is None:\n+ if field.default is MISSING and field.default_factory is MISSING:\n+ raise RuntimeError(\n+ f\"parsers for field {field.name} returned None, but the field has no default\"\n+ )\n+ else:\n+ fields_values[field.name] = field_value\n+\n+ return cls(**fields_values)\n", "prefixes": [ "3/5" ] }{ "id": 139239, "url": "