From nobody Fri May 17 00:38:28 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=fail(p=none dis=none) header.from=arm.com Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1706699009877969.1834794615665; Wed, 31 Jan 2024 03:03:29 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.673919.1048509 (Exim 4.92) (envelope-from ) id 1rV8N4-0001qU-Rh; Wed, 31 Jan 2024 11:03:10 +0000 Received: by outflank-mailman (output) from mailman id 673919.1048509; Wed, 31 Jan 2024 11:03:10 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1rV8N4-0001qN-O5; Wed, 31 Jan 2024 11:03:10 +0000 Received: by outflank-mailman (input) for mailman id 673919; Wed, 31 Jan 2024 11:03:08 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1rV8N2-0001NU-KK for xen-devel@lists.xenproject.org; Wed, 31 Jan 2024 11:03:08 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-flk1.inumbo.com (Halon) with ESMTP id 4f869515-c028-11ee-98f5-efadbce2ee36; Wed, 31 Jan 2024 12:03:06 +0100 (CET) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 3894311FB; Wed, 31 Jan 2024 03:03:49 -0800 (PST) Received: from e125770.cambridge.arm.com (e125770.arm.com [10.1.199.1]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 4A2883F762; Wed, 31 Jan 2024 03:03:05 -0800 (PST) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 4f869515-c028-11ee-98f5-efadbce2ee36 From: Luca Fancellu To: xen-devel@lists.xenproject.org Cc: Stefano Stabellini Subject: [PATCH 1/3] xen-analysis.py: Use named group for tag regex Date: Wed, 31 Jan 2024 11:02:39 +0000 Message-Id: <20240131110241.3951995-2-luca.fancellu@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240131110241.3951995-1-luca.fancellu@arm.com> References: <20240131110241.3951995-1-luca.fancellu@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1706699010821100003 Content-Type: text/plain; charset="utf-8" Use named group for the regex matching a tag identifier, this is done to ease retrieving the matching group instead of using an index. Signed-off-by: Luca Fancellu Acked-by: Stefano Stabellini --- xen/scripts/xen_analysis/cppcheck_analysis.py | 4 ++-- xen/scripts/xen_analysis/tag_database.py | 24 +++++++++---------- xen/scripts/xen_analysis/utils.py | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/xen/scripts/xen_analysis/cppcheck_analysis.py b/xen/scripts/xe= n_analysis/cppcheck_analysis.py index e54848aa5339..919eb153ce9c 100644 --- a/xen/scripts/xen_analysis/cppcheck_analysis.py +++ b/xen/scripts/xen_analysis/cppcheck_analysis.py @@ -41,7 +41,7 @@ def __generate_suppression_list(out_file): # The following lambda function will return a file if it contains line= s with # a comment containing "cppcheck-suppress[*]" on a single line. grep_action =3D lambda x: utils.grep(x, - r'^[ \t]*/\* cppcheck-suppress\[(.*)\] \*/$') + r'^[ \t]*/\* cppcheck-suppress\[(?P.*)\] \*/$') # Look for a list of .h files that matches the condition above headers =3D utils.recursive_find_file(settings.xen_dir, r'.*\.h$', grep_action) @@ -97,7 +97,7 @@ def __generate_suppression_list(out_file): if (not comment_section) and comment_line_starts: comment_section =3D True if (len(line.strip()) !=3D 0) and (not comment_sec= tion): - cppcheck_violation_id =3D entry["matches"][lin= e_num][0] + cppcheck_violation_id =3D entry["matches"][lin= e_num]['id'] break if comment_section and comment_line_stops: comment_section =3D False diff --git a/xen/scripts/xen_analysis/tag_database.py b/xen/scripts/xen_ana= lysis/tag_database.py index ca374bbb62dd..abba163aec71 100644 --- a/xen/scripts/xen_analysis/tag_database.py +++ b/xen/scripts/xen_analysis/tag_database.py @@ -18,11 +18,12 @@ tool_syntax =3D { =20 =20 def get_xen_tag_index_type_regex(tool): - return r'^SAF-(\d+)-(safe|false-positive-' + tool + ')$' + return rf'^SAF-(?P\d+)-(?Psafe|false-positive-{tool})$' =20 =20 def get_xen_tag_comment_regex(tool): - return r'^[ \t]*/\* +(SAF-\d+-(?:safe|false-positive-' + tool + ')).*\= */$' + tag=3Drf'(?PSAF-\d+-(?:safe|false-positive-{tool}))' + return rf'^[ \t]*/\* +{tag}.*\*/$' =20 =20 # Returns a data structure containing dictionaries for safe and false-posi= tive-* @@ -60,12 +61,11 @@ def load_tag_database(tool, input_files, data_struct = =3D None, schema =3D "safe"): if proprietary_id !=3D "": comment=3Dtool_syntax[tool].replace("VID",proprietary_id) # Regex to capture the index of the Xen tag and the schema - xen_tag =3D re.compile(get_xen_tag_index_type_regex(tool))\ - .match(entry["id"]) - if xen_tag and xen_tag.group(1) and xen_tag.group(2): + xen_tag =3D re.match(get_xen_tag_index_type_regex(tool), entry= ["id"]) + if xen_tag and xen_tag.group('id') and xen_tag.group('type'): # Save in safe or false-positive-* the key {#id: "comment"} - id_number =3D int(xen_tag.group(1)) - key =3D xen_tag.group(2) + id_number =3D int(xen_tag.group('id')) + key =3D xen_tag.group('type') ret[key][id_number] =3D "/* {} */\n".format(comment) else: raise TagDatabaseError( @@ -95,11 +95,11 @@ def substitute_tags(tool, input_file, grep_struct, subs= _rules): # information access the subs_rules dictionary to see if there= is # a match for line_number in grep_struct["matches"]: - xen_tag =3D grep_struct["matches"][line_number][0] - xen_tag_regex_obj =3D re.compile( - get_xen_tag_index_type_regex(tool)).match(xen_= tag) - id_number =3D int(xen_tag_regex_obj.group(1)) - key =3D xen_tag_regex_obj.group(2) + xen_tag =3D grep_struct["matches"][line_number]['tag'] + xen_tag_regex_obj =3D re.match(get_xen_tag_index_type_rege= x(tool), + xen_tag) + id_number =3D int(xen_tag_regex_obj.group('id')) + key =3D xen_tag_regex_obj.group('type') if id_number in subs_rules[key]: parsed_content[line_number-1] =3D subs_rules[key][id_n= umber] =20 diff --git a/xen/scripts/xen_analysis/utils.py b/xen/scripts/xen_analysis/u= tils.py index 1193e3f4631e..eef48eeb7e87 100644 --- a/xen/scripts/xen_analysis/utils.py +++ b/xen/scripts/xen_analysis/utils.py @@ -12,7 +12,7 @@ def grep(filepath, regex): for line in f: match =3D regObj.match(line) if match: - res["matches"][line_number] =3D match.groups() + res["matches"][line_number] =3D match line_number =3D line_number + 1 except Exception as e: print("WARNING: Can't open {}: {}".format(filepath, e)) --=20 2.34.1 From nobody Fri May 17 00:38:28 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=fail(p=none dis=none) header.from=arm.com Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1706699013798193.19188924497075; Wed, 31 Jan 2024 03:03:33 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.673918.1048494 (Exim 4.92) (envelope-from ) id 1rV8N3-0001R3-Ia; Wed, 31 Jan 2024 11:03:09 +0000 Received: by outflank-mailman (output) from mailman id 673918.1048494; Wed, 31 Jan 2024 11:03:09 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1rV8N3-0001QO-Di; Wed, 31 Jan 2024 11:03:09 +0000 Received: by outflank-mailman (input) for mailman id 673918; Wed, 31 Jan 2024 11:03:08 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1rV8N2-0001NO-BK for xen-devel@lists.xenproject.org; Wed, 31 Jan 2024 11:03:08 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 4ff0d39e-c028-11ee-8a43-1f161083a0e0; Wed, 31 Jan 2024 12:03:07 +0100 (CET) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id D5AE71477; Wed, 31 Jan 2024 03:03:49 -0800 (PST) Received: from e125770.cambridge.arm.com (e125770.arm.com [10.1.199.1]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id E71183F762; Wed, 31 Jan 2024 03:03:05 -0800 (PST) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 4ff0d39e-c028-11ee-8a43-1f161083a0e0 From: Luca Fancellu To: xen-devel@lists.xenproject.org Cc: Stefano Stabellini Subject: [PATCH 2/3] xen-analysis.py: Substitute only the comment instead of the line Date: Wed, 31 Jan 2024 11:02:40 +0000 Message-Id: <20240131110241.3951995-3-luca.fancellu@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240131110241.3951995-1-luca.fancellu@arm.com> References: <20240131110241.3951995-1-luca.fancellu@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1706699014826100007 Content-Type: text/plain; charset="utf-8" Change the code in tag_database.py to substitute only the SAF-* comment instead of replacing the line. Signed-off-by: Luca Fancellu Acked-by: Stefano Stabellini --- xen/scripts/xen_analysis/tag_database.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/xen/scripts/xen_analysis/tag_database.py b/xen/scripts/xen_ana= lysis/tag_database.py index abba163aec71..dc0558a46ed6 100644 --- a/xen/scripts/xen_analysis/tag_database.py +++ b/xen/scripts/xen_analysis/tag_database.py @@ -16,14 +16,18 @@ tool_syntax =3D { "eclair":"-E> hide VID 1 \"\"" } =20 +def get_xen_tag_regex(tool): + return rf'(?PSAF-(?P\d+)-(?Psafe|false-positive-{tool})= )' + =20 def get_xen_tag_index_type_regex(tool): - return rf'^SAF-(?P\d+)-(?Psafe|false-positive-{tool})$' + return rf'^{get_xen_tag_regex(tool)}$' =20 =20 def get_xen_tag_comment_regex(tool): - tag=3Drf'(?PSAF-\d+-(?:safe|false-positive-{tool}))' - return rf'^[ \t]*/\* +{tag}.*\*/$' + before_comment =3D r'(?P[ \t]*)' + comment =3D rf'(?P/\* +{get_xen_tag_regex(tool)}.*\*/)' + return rf'^(?P{before_comment}{comment})$' =20 =20 # Returns a data structure containing dictionaries for safe and false-posi= tive-* @@ -66,7 +70,7 @@ def load_tag_database(tool, input_files, data_struct =3D = None, schema =3D "safe"): # Save in safe or false-positive-* the key {#id: "comment"} id_number =3D int(xen_tag.group('id')) key =3D xen_tag.group('type') - ret[key][id_number] =3D "/* {} */\n".format(comment) + ret[key][id_number] =3D "/* {} */".format(comment) else: raise TagDatabaseError( "Error in database file, entry {} has unexpected " @@ -101,7 +105,11 @@ def substitute_tags(tool, input_file, grep_struct, sub= s_rules): id_number =3D int(xen_tag_regex_obj.group('id')) key =3D xen_tag_regex_obj.group('type') if id_number in subs_rules[key]: - parsed_content[line_number-1] =3D subs_rules[key][id_n= umber] + comment_in =3D grep_struct["matches"][line_number]['co= mment'] + comment_out =3D subs_rules[key][id_number] + parsed_content[line_number-1] =3D re.sub( + re.escape(comment_in), comment_out, + parsed_content[line_number-1]) =20 outfile.writelines(parsed_content) except Exception as e: --=20 2.34.1 From nobody Fri May 17 00:38:28 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=fail(p=none dis=none) header.from=arm.com Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 170669901223991.78325528327412; Wed, 31 Jan 2024 03:03:32 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.673920.1048515 (Exim 4.92) (envelope-from ) id 1rV8N5-0001tp-4d; Wed, 31 Jan 2024 11:03:11 +0000 Received: by outflank-mailman (output) from mailman id 673920.1048515; Wed, 31 Jan 2024 11:03:11 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1rV8N4-0001t9-Vc; Wed, 31 Jan 2024 11:03:10 +0000 Received: by outflank-mailman (input) for mailman id 673920; Wed, 31 Jan 2024 11:03:10 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1rV8N4-0001NU-5G for xen-devel@lists.xenproject.org; Wed, 31 Jan 2024 11:03:10 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-flk1.inumbo.com (Halon) with ESMTP id 50b4dbc4-c028-11ee-98f5-efadbce2ee36; Wed, 31 Jan 2024 12:03:08 +0100 (CET) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 0D7F61480; Wed, 31 Jan 2024 03:03:51 -0800 (PST) Received: from e125770.cambridge.arm.com (e125770.arm.com [10.1.199.1]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 91AFD3F762; Wed, 31 Jan 2024 03:03:06 -0800 (PST) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 50b4dbc4-c028-11ee-98f5-efadbce2ee36 From: Luca Fancellu To: xen-devel@lists.xenproject.org Cc: Andrew Cooper , George Dunlap , Jan Beulich , Julien Grall , Stefano Stabellini , Wei Liu Subject: [PATCH 3/3] xen-analysis.py: Accept deviation comment at the end of the line Date: Wed, 31 Jan 2024 11:02:41 +0000 Message-Id: <20240131110241.3951995-4-luca.fancellu@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240131110241.3951995-1-luca.fancellu@arm.com> References: <20240131110241.3951995-1-luca.fancellu@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1706699012819100005 Content-Type: text/plain; charset="utf-8" Implement the in-code suppression comment at the end of the line. Now it is possible to add a Xen deviaiton comment with the syntax described in the docs at the end of the line affected by the violation, to deviate it. Eclair natively supports it, so the translation for the tool will be straighforward, but the other tool needs to translate an occurrence of the tag into a suppressino comment at the end of the previous line, this will have a corner case where the line number 1 of the file can't be deviated in this way for such tools. Updated documentation. Signed-off-by: Luca Fancellu Acked-by: Stefano Stabellini --- docs/misra/documenting-violations.rst | 10 ++++++++ xen/scripts/xen_analysis/cppcheck_analysis.py | 2 +- xen/scripts/xen_analysis/generic_analysis.py | 14 +++++++---- xen/scripts/xen_analysis/tag_database.py | 25 ++++++++++++++++++- 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/docs/misra/documenting-violations.rst b/docs/misra/documenting= -violations.rst index 0d02a8e6f905..8f1cbd83b859 100644 --- a/docs/misra/documenting-violations.rst +++ b/docs/misra/documenting-violations.rst @@ -210,3 +210,13 @@ will be an entry like the following and the violation = id will be in the column =20 Given the violation id "misra-c2012-20.7", the procedure above can be foll= owed to justify this finding. + +Another way to justify the above violation is to put the in-code comment t= ag +at the end of the affected line:: + +| extern char _start[], _end[], start[]; /* SAF-1-safe [...] */ + +This way of deviating violations needs however to be used only when placin= g the +tag above the line can't be done. This option suffers from some limitation= on +cppcheck and coverity tool that don't support natively the suppression com= ment +at the end of the line. diff --git a/xen/scripts/xen_analysis/cppcheck_analysis.py b/xen/scripts/xe= n_analysis/cppcheck_analysis.py index 919eb153ce9c..850335c998a3 100644 --- a/xen/scripts/xen_analysis/cppcheck_analysis.py +++ b/xen/scripts/xen_analysis/cppcheck_analysis.py @@ -41,7 +41,7 @@ def __generate_suppression_list(out_file): # The following lambda function will return a file if it contains line= s with # a comment containing "cppcheck-suppress[*]" on a single line. grep_action =3D lambda x: utils.grep(x, - r'^[ \t]*/\* cppcheck-suppress\[(?P.*)\] \*/$') + r'^.*/\* cppcheck-suppress\[(?P.*)\] \*/$') # Look for a list of .h files that matches the condition above headers =3D utils.recursive_find_file(settings.xen_dir, r'.*\.h$', grep_action) diff --git a/xen/scripts/xen_analysis/generic_analysis.py b/xen/scripts/xen= _analysis/generic_analysis.py index 94122aebace0..9e0cfc1bbc08 100644 --- a/xen/scripts/xen_analysis/generic_analysis.py +++ b/xen/scripts/xen_analysis/generic_analysis.py @@ -52,11 +52,15 @@ def parse_xen_tags(): os.rename(file, bkp_file) time_bkp_file =3D os.stat(bkp_file) # Create from .safparse but with the Xen tag parsed - tag_database.substitute_tags(settings.analysis_tool, bkp_file, ent= ry, - subs_list) - # Set timestamp for file equal to bkp_file, so that if the file is - # modified during the process by the user, we can catch it - os.utime(file, (time_bkp_file.st_atime, time_bkp_file.st_mtime)) + try: + tag_database.substitute_tags(settings.analysis_tool, bkp_file,= entry, + subs_list) + except Exception as e: + raise ParseTagPhaseError("{}".format(e)) + finally: + # Set timestamp for file equal to bkp_file, so that if the fil= e is + # modified during the process by the user, we can catch it + os.utime(file, (time_bkp_file.st_atime, time_bkp_file.st_mtime= )) =20 =20 def build_xen(): diff --git a/xen/scripts/xen_analysis/tag_database.py b/xen/scripts/xen_ana= lysis/tag_database.py index dc0558a46ed6..57746ca0ddb6 100644 --- a/xen/scripts/xen_analysis/tag_database.py +++ b/xen/scripts/xen_analysis/tag_database.py @@ -25,7 +25,7 @@ def get_xen_tag_index_type_regex(tool): =20 =20 def get_xen_tag_comment_regex(tool): - before_comment =3D r'(?P[ \t]*)' + before_comment =3D r'(?P.*)' comment =3D rf'(?P/\* +{get_xen_tag_regex(tool)}.*\*/)' return rf'^(?P{before_comment}{comment})$' =20 @@ -106,7 +106,30 @@ def substitute_tags(tool, input_file, grep_struct, sub= s_rules): key =3D xen_tag_regex_obj.group('type') if id_number in subs_rules[key]: comment_in =3D grep_struct["matches"][line_number]['co= mment'] + before =3D grep_struct["matches"][line_number]['before= '] comment_out =3D subs_rules[key][id_number] + if before !=3D '' and not re.match(r'^[ \t]+$', before= ): + # The comment is at the end of some line with some= code + if tool =3D=3D "eclair": + # Eclair supports comment at the end of the li= ne, so + # the only thing to do is use the right syntax= in + # the comment, the default version of it is + # deviating the current line and the next one + comment_out =3D re.sub(r'\d+ ""', '0 ""', comm= ent_out) + else: + # Other tool does not support deviating the sa= me + # line of the comment, so we use a trick and w= e use + # the comment at the end of the previous line + if line_number-2 < 0: + raise TagDatabaseError( + "The comment {} using the tool '{}' ca= n't " + "stay at the end of the line 1." + .format(comment_in, tool) + ) + parsed_content[line_number-2] =3D \ + parsed_content[line_number-2].replace("\n", + comment_out + '\n') + comment_out =3D '' parsed_content[line_number-1] =3D re.sub( re.escape(comment_in), comment_out, parsed_content[line_number-1]) --=20 2.34.1