diff mbox series

[6/6] patchtest: use black to format libraries

Message ID 20240924115503.1599651-7-tgamblin@baylibre.com
State Under Review
Headers show
Series patchtest: some refactor and simplification | expand

Commit Message

Trevor Gamblin Sept. 24, 2024, 11:55 a.m. UTC
Black makes things easier to read.

Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
---
 meta/lib/patchtest/mbox.py                    |  44 +++---
 meta/lib/patchtest/patchtest_parser.py        | 106 ++++++++-----
 meta/lib/patchtest/patchtest_patterns.py      |  84 ++++++----
 meta/lib/patchtest/repo.py                    |  32 ++--
 meta/lib/patchtest/selftest/selftest          |  92 ++++++++---
 meta/lib/patchtest/tests/base.py              |  86 ++++++-----
 meta/lib/patchtest/tests/test_mbox.py         | 144 +++++++++++++-----
 meta/lib/patchtest/tests/test_metadata.py     |  94 ++++++++----
 meta/lib/patchtest/tests/test_patch.py        |  39 +++--
 .../lib/patchtest/tests/test_python_pylint.py |  45 ++++--
 scripts/patchtest                             | 113 +++++++++-----
 scripts/patchtest-get-branch                  |  54 ++++---
 scripts/patchtest-send-results                |  66 +++++---
 13 files changed, 660 insertions(+), 339 deletions(-)

Comments

Richard Purdie Oct. 1, 2024, 11:45 a.m. UTC | #1
On Tue, 2024-09-24 at 07:55 -0400, Trevor Gamblin via lists.openembedded.org wrote:
> Black makes things easier to read.
> 
> Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
> ---
>  meta/lib/patchtest/mbox.py                    |  44 +++---
>  meta/lib/patchtest/patchtest_parser.py        | 106 ++++++++-----
>  meta/lib/patchtest/patchtest_patterns.py      |  84 ++++++----
>  meta/lib/patchtest/repo.py                    |  32 ++--
>  meta/lib/patchtest/selftest/selftest          |  92 ++++++++---
>  meta/lib/patchtest/tests/base.py              |  86 ++++++-----
>  meta/lib/patchtest/tests/test_mbox.py         | 144 +++++++++++++-----
>  meta/lib/patchtest/tests/test_metadata.py     |  94 ++++++++----
>  meta/lib/patchtest/tests/test_patch.py        |  39 +++--
>  .../lib/patchtest/tests/test_python_pylint.py |  45 ++++--
>  scripts/patchtest                             | 113 +++++++++-----
>  scripts/patchtest-get-branch                  |  54 ++++---
>  scripts/patchtest-send-results                |  66 +++++---
>  13 files changed, 660 insertions(+), 339 deletions(-)

I'm a bit nervous about this change for a few reasons. Firstly, it sets
a precedent where others will want to do this on other areas of the
code and I'm not sure we really want to do that.

black is quite opinionated and I don't agree with everything it is
changing. Some of the code does look more readable before it made
changes compared to the end result, particularly around how it is
choosing to line wrap the code. Some of the changes are also just
rearranging things for little gain such as changing quoting characters.

I'm therefore in two minds of this. I do want to empower people to
maintain code but I don't want to end up forced into taking style
changes I really don't agree with :/.

Cheers,

Richard
Trevor Gamblin Oct. 1, 2024, 12:47 p.m. UTC | #2
On 2024-10-01 07:45, Richard Purdie wrote:
> On Tue, 2024-09-24 at 07:55 -0400, Trevor Gamblin via lists.openembedded.org wrote:
>> Black makes things easier to read.
>>
>> Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
>> ---
>>   meta/lib/patchtest/mbox.py                    |  44 +++---
>>   meta/lib/patchtest/patchtest_parser.py        | 106 ++++++++-----
>>   meta/lib/patchtest/patchtest_patterns.py      |  84 ++++++----
>>   meta/lib/patchtest/repo.py                    |  32 ++--
>>   meta/lib/patchtest/selftest/selftest          |  92 ++++++++---
>>   meta/lib/patchtest/tests/base.py              |  86 ++++++-----
>>   meta/lib/patchtest/tests/test_mbox.py         | 144 +++++++++++++-----
>>   meta/lib/patchtest/tests/test_metadata.py     |  94 ++++++++----
>>   meta/lib/patchtest/tests/test_patch.py        |  39 +++--
>>   .../lib/patchtest/tests/test_python_pylint.py |  45 ++++--
>>   scripts/patchtest                             | 113 +++++++++-----
>>   scripts/patchtest-get-branch                  |  54 ++++---
>>   scripts/patchtest-send-results                |  66 +++++---
>>   13 files changed, 660 insertions(+), 339 deletions(-)
> I'm a bit nervous about this change for a few reasons. Firstly, it sets
> a precedent where others will want to do this on other areas of the
> code and I'm not sure we really want to do that.
>
> black is quite opinionated and I don't agree with everything it is
> changing. Some of the code does look more readable before it made
> changes compared to the end result, particularly around how it is
> choosing to line wrap the code. Some of the changes are also just
> rearranging things for little gain such as changing quoting characters.
>
> I'm therefore in two minds of this. I do want to empower people to
> maintain code but I don't want to end up forced into taking style
> changes I really don't agree with :/.

I agree that it may lead to a rush of reformatting efforts that aren't 
desired. We certainly don't have to take this patch now if you don't 
want to, although the more minor changes (e.g. the quotations) were 
actually a bigger part of the draw for me when I ran it.

On the other hand, some experience with using checkpatch.pl in the 
kernel has me wondering if we should be considering standardizing our 
formats for Python scripts and modules (over time) anyway. I have no 
strong preference on which formatter would be best (to be honest, I 
haven't even tried the others like YAPF or Ruff). Black, however, seems 
to be the one recommended most, and though it's opinionated it helps 
keep things consistent (the example above where the string quoting was 
sometimes single and sometimes double drove me nuts every time I looked 
at it).

Is this a reasonable goal for some distant release? I've CC'd Ross and 
Tim since they're also doing some Python work. I might bring it up at 
the weekly today.

- Trevor

>
> Cheers,
>
> Richard
>
>
>
>
>
>
Alexander Kanavin Oct. 1, 2024, 12:56 p.m. UTC | #3
On Tue, 1 Oct 2024 at 14:47, Trevor Gamblin via lists.openembedded.org
<tgamblin=baylibre.com@lists.openembedded.org> wrote:
> Is this a reasonable goal for some distant release? I've CC'd Ross and
> Tim since they're also doing some Python work. I might bring it up at
> the weekly today.

Can I raise a strong objection? I've been writing python for over 20
years, and I haven't once been in a situation where formatting would
affect my ability to form a mental picture of what the code is doing.
It's by far the most overrated item in various coding guidelines. As
long as people stay roughly consistent with what is already there, and
remember to wrap or split long lines, I utterly don't care about
anything else, and feel it's a waste of time to enforce a particular
style.

Alex
Richard Purdie Oct. 1, 2024, 12:56 p.m. UTC | #4
On Tue, 2024-10-01 at 08:47 -0400, Trevor Gamblin wrote:
> 
> On 2024-10-01 07:45, Richard Purdie wrote:
> > On Tue, 2024-09-24 at 07:55 -0400, Trevor Gamblin via lists.openembedded.org wrote:
> > > Black makes things easier to read.
> > > 
> > > Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
> > > ---
> > >   meta/lib/patchtest/mbox.py                    |  44 +++---
> > >   meta/lib/patchtest/patchtest_parser.py        | 106 ++++++++-----
> > >   meta/lib/patchtest/patchtest_patterns.py      |  84 ++++++----
> > >   meta/lib/patchtest/repo.py                    |  32 ++--
> > >   meta/lib/patchtest/selftest/selftest          |  92 ++++++++---
> > >   meta/lib/patchtest/tests/base.py              |  86 ++++++-----
> > >   meta/lib/patchtest/tests/test_mbox.py         | 144 +++++++++++++-----
> > >   meta/lib/patchtest/tests/test_metadata.py     |  94 ++++++++----
> > >   meta/lib/patchtest/tests/test_patch.py        |  39 +++--
> > >   .../lib/patchtest/tests/test_python_pylint.py |  45 ++++--
> > >   scripts/patchtest                             | 113 +++++++++-----
> > >   scripts/patchtest-get-branch                  |  54 ++++---
> > >   scripts/patchtest-send-results                |  66 +++++---
> > >   13 files changed, 660 insertions(+), 339 deletions(-)
> > I'm a bit nervous about this change for a few reasons. Firstly, it sets
> > a precedent where others will want to do this on other areas of the
> > code and I'm not sure we really want to do that.
> > 
> > black is quite opinionated and I don't agree with everything it is
> > changing. Some of the code does look more readable before it made
> > changes compared to the end result, particularly around how it is
> > choosing to line wrap the code. Some of the changes are also just
> > rearranging things for little gain such as changing quoting characters.
> > 
> > I'm therefore in two minds of this. I do want to empower people to
> > maintain code but I don't want to end up forced into taking style
> > changes I really don't agree with :/.
> 
> I agree that it may lead to a rush of reformatting efforts that aren't 
> desired. We certainly don't have to take this patch now if you don't 
> want to, although the more minor changes (e.g. the quotations) were 
> actually a bigger part of the draw for me when I ran it.
> 
> On the other hand, some experience with using checkpatch.pl in the 
> kernel has me wondering if we should be considering standardizing our
> formats for Python scripts and modules (over time) anyway. I have no 
> strong preference on which formatter would be best (to be honest, I 
> haven't even tried the others like YAPF or Ruff). Black, however, seems 
> to be the one recommended most, and though it's opinionated it helps 
> keep things consistent (the example above where the string quoting was 
> sometimes single and sometimes double drove me nuts every time I looked 
> at it).
> 
> Is this a reasonable goal for some distant release? I've CC'd Ross and 
> Tim since they're also doing some Python work. I might bring it up at
> the weekly today.

Seemingly simple formatting changes have been some of the more
contentious issues in the past. The churn such patches introduce make
history difficult to read and make LTS maintanenace hard as patches
become hard to backport. I've "lived" through the discussion multiple
times in one format or another and I'm still not convinced that
adopting hard "rules" around format X or Y is a great idea.

We have been adopting a rough standardisation of things slowly over
time as code gets updated but it doesn't extend to the quotes or line
wrapping as there were other bigger problems. I'm not against doing
that as we update code but I'm not sure I'm convinced about block
formatting changes like this patch.

If there was a specific issue like the quoting, I'd in many ways prefer
to fix that in a specific patch rather than have multiple formatting
changes all mixed together. Our metadata quoting really doesn't help
things there :/. Different people are triggered by different issues, I
know personally quoting bothers much much less that function parameter
white spacing.

I worry this is a topic where there is no right answer too :/

Cheers,

Richard
Trevor Gamblin Oct. 1, 2024, 1:04 p.m. UTC | #5
On 2024-10-01 08:56, Richard Purdie wrote:
> On Tue, 2024-10-01 at 08:47 -0400, Trevor Gamblin wrote:
>> On 2024-10-01 07:45, Richard Purdie wrote:
>>> On Tue, 2024-09-24 at 07:55 -0400, Trevor Gamblin via lists.openembedded.org wrote:
>>>> Black makes things easier to read.
>>>>
>>>> Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
>>>> ---
>>>>    meta/lib/patchtest/mbox.py                    |  44 +++---
>>>>    meta/lib/patchtest/patchtest_parser.py        | 106 ++++++++-----
>>>>    meta/lib/patchtest/patchtest_patterns.py      |  84 ++++++----
>>>>    meta/lib/patchtest/repo.py                    |  32 ++--
>>>>    meta/lib/patchtest/selftest/selftest          |  92 ++++++++---
>>>>    meta/lib/patchtest/tests/base.py              |  86 ++++++-----
>>>>    meta/lib/patchtest/tests/test_mbox.py         | 144 +++++++++++++-----
>>>>    meta/lib/patchtest/tests/test_metadata.py     |  94 ++++++++----
>>>>    meta/lib/patchtest/tests/test_patch.py        |  39 +++--
>>>>    .../lib/patchtest/tests/test_python_pylint.py |  45 ++++--
>>>>    scripts/patchtest                             | 113 +++++++++-----
>>>>    scripts/patchtest-get-branch                  |  54 ++++---
>>>>    scripts/patchtest-send-results                |  66 +++++---
>>>>    13 files changed, 660 insertions(+), 339 deletions(-)
>>> I'm a bit nervous about this change for a few reasons. Firstly, it sets
>>> a precedent where others will want to do this on other areas of the
>>> code and I'm not sure we really want to do that.
>>>
>>> black is quite opinionated and I don't agree with everything it is
>>> changing. Some of the code does look more readable before it made
>>> changes compared to the end result, particularly around how it is
>>> choosing to line wrap the code. Some of the changes are also just
>>> rearranging things for little gain such as changing quoting characters.
>>>
>>> I'm therefore in two minds of this. I do want to empower people to
>>> maintain code but I don't want to end up forced into taking style
>>> changes I really don't agree with :/.
>> I agree that it may lead to a rush of reformatting efforts that aren't
>> desired. We certainly don't have to take this patch now if you don't
>> want to, although the more minor changes (e.g. the quotations) were
>> actually a bigger part of the draw for me when I ran it.
>>
>> On the other hand, some experience with using checkpatch.pl in the
>> kernel has me wondering if we should be considering standardizing our
>> formats for Python scripts and modules (over time) anyway. I have no
>> strong preference on which formatter would be best (to be honest, I
>> haven't even tried the others like YAPF or Ruff). Black, however, seems
>> to be the one recommended most, and though it's opinionated it helps
>> keep things consistent (the example above where the string quoting was
>> sometimes single and sometimes double drove me nuts every time I looked
>> at it).
>>
>> Is this a reasonable goal for some distant release? I've CC'd Ross and
>> Tim since they're also doing some Python work. I might bring it up at
>> the weekly today.
> Seemingly simple formatting changes have been some of the more
> contentious issues in the past. The churn such patches introduce make
> history difficult to read and make LTS maintanenace hard as patches
> become hard to backport. I've "lived" through the discussion multiple
> times in one format or another and I'm still not convinced that
> adopting hard "rules" around format X or Y is a great idea.
>
> We have been adopting a rough standardisation of things slowly over
> time as code gets updated but it doesn't extend to the quotes or line
> wrapping as there were other bigger problems. I'm not against doing
> that as we update code but I'm not sure I'm convinced about block
> formatting changes like this patch.
>
> If there was a specific issue like the quoting, I'd in many ways prefer
> to fix that in a specific patch rather than have multiple formatting
> changes all mixed together. Our metadata quoting really doesn't help
> things there :/. Different people are triggered by different issues, I
> know personally quoting bothers much much less that function parameter
> white spacing.
>
> I worry this is a topic where there is no right answer too :/

Let's just drop it then, since Alex has raised an objection too. I'll 
submit another one to fix the quoting at some point soon.

- Trevor

>
> Cheers,
>
> Richard
>
>
>
>
>
>
>
>
>
>
diff mbox series

Patch

diff --git a/meta/lib/patchtest/mbox.py b/meta/lib/patchtest/mbox.py
index 1d95819b7ae..aad07356f1f 100644
--- a/meta/lib/patchtest/mbox.py
+++ b/meta/lib/patchtest/mbox.py
@@ -13,11 +13,12 @@ 
 import email
 import re
 
+
 # From: https://stackoverflow.com/questions/59681461/read-a-big-mbox-file-with-python
 class MboxReader:
     def __init__(self, filepath):
-        self.handle = open(filepath, 'rb')
-        assert self.handle.readline().startswith(b'From ')
+        self.handle = open(filepath, "rb")
+        assert self.handle.readline().startswith(b"From ")
 
     def __enter__(self):
         return self
@@ -32,24 +33,26 @@  class MboxReader:
         lines = []
         while True:
             line = self.handle.readline()
-            if line == b'' or line.startswith(b'From '):
-                yield email.message_from_bytes(b''.join(lines))
-                if line == b'':
+            if line == b"" or line.startswith(b"From "):
+                yield email.message_from_bytes(b"".join(lines))
+                if line == b"":
                     break
                 lines = []
                 continue
             lines.append(line)
 
+
 class Patch:
     def __init__(self, data):
-        self.author = data['From']
-        self.to = data['To']
-        self.cc = data['Cc']
-        self.subject = data['Subject']
-        self.split_body = re.split('---', data.get_payload(), maxsplit=1)
+        self.author = data["From"]
+        self.to = data["To"]
+        self.cc = data["Cc"]
+        self.subject = data["Subject"]
+        self.split_body = re.split("---", data.get_payload(), maxsplit=1)
         self.commit_message = self.split_body[0]
         self.diff = self.split_body[1]
 
+
 class PatchSeries:
     def __init__(self, filepath):
         with MboxReader(filepath) as mbox:
@@ -78,8 +81,8 @@  class PatchSeries:
         branch, branches, valid_branches = None, [], []
 
         if fullprefix:
-            prefix = fullprefix.strip('[]')
-            branches = [ b.strip() for b in prefix.split(',')]
+            prefix = fullprefix.strip("[]")
+            branches = [b.strip() for b in prefix.split(",")]
             valid_branches = [b for b in branches if PatchSeries.valid_branch(b)]
 
         if len(valid_branches):
@@ -89,20 +92,21 @@  class PatchSeries:
         # found, then assume there was no branch tag in the subject line
         # and that the patch targets master
         if branch is not None:
-            return branch.split(']')[0]
+            return branch.split("]")[0]
         else:
             return "master"
 
     @staticmethod
     def valid_branch(branch):
-        """ Check if branch is valid name """
+        """Check if branch is valid name"""
         lbranch = branch.lower()
 
-        invalid  = lbranch.startswith('patch') or \
-                   lbranch.startswith('rfc') or \
-                   lbranch.startswith('resend') or \
-                   re.search(r'^v\d+', lbranch) or \
-                   re.search(r'^\d+/\d+', lbranch)
+        invalid = (
+            lbranch.startswith("patch")
+            or lbranch.startswith("rfc")
+            or lbranch.startswith("resend")
+            or re.search(r"^v\d+", lbranch)
+            or re.search(r"^\d+/\d+", lbranch)
+        )
 
         return not invalid
-
diff --git a/meta/lib/patchtest/patchtest_parser.py b/meta/lib/patchtest/patchtest_parser.py
index 2a11cb76c23..f1fef143245 100644
--- a/meta/lib/patchtest/patchtest_parser.py
+++ b/meta/lib/patchtest/patchtest_parser.py
@@ -19,6 +19,7 @@  import argparse
 default_testdir = os.path.abspath(os.path.dirname(__file__) + "/tests")
 default_repodir = os.path.abspath(os.path.dirname(__file__) + "/../../..")
 
+
 class PatchtestParser(object):
     """Abstract the patchtest argument parser"""
 
@@ -33,46 +34,69 @@  class PatchtestParser(object):
 
         target_patch_group = parser.add_mutually_exclusive_group(required=True)
 
-        target_patch_group.add_argument('--patch', metavar='PATCH', dest='patch_path',
-                            help='The patch to be tested')
-
-        target_patch_group.add_argument('--directory', metavar='DIRECTORY', dest='patch_path',
-                            help='The directory containing patches to be tested')
-
-        parser.add_argument('--repodir', metavar='REPO',
-                            default=default_repodir,
-                            help="Name of the repository where patch is merged")
-
-        parser.add_argument('--testdir', metavar='TESTDIR',
-                            default=default_testdir,
-                            help="Directory where test cases are located")
-
-        parser.add_argument('--top-level-directory', '-t',
-                            dest='topdir',
-                            default=None,
-                            help="Top level directory of project (defaults to start directory)")
-
-        parser.add_argument('--pattern', '-p',
-                            dest='pattern',
-                            default='test*.py',
-                            help="Pattern to match test files")
-
-        parser.add_argument('--base-branch', '-b',
-                            dest='basebranch',
-                            help="Branch name used by patchtest to branch from. By default, it uses the current one.")
-
-        parser.add_argument('--base-commit', '-c',
-                            dest='basecommit',
-                            help="Commit ID used by patchtest to branch from. By default, it uses HEAD.")
-
-        parser.add_argument('--debug', '-d',
-                            action='store_true',
-                            help='Enable debug output')
-
-        parser.add_argument('--log-results', 
-                            action='store_true', 
-                            help='Enable logging to a file matching the target patch name with ".testresult" appended')
-
+        target_patch_group.add_argument(
+            "--patch", metavar="PATCH", dest="patch_path", help="The patch to be tested"
+        )
+
+        target_patch_group.add_argument(
+            "--directory",
+            metavar="DIRECTORY",
+            dest="patch_path",
+            help="The directory containing patches to be tested",
+        )
+
+        parser.add_argument(
+            "--repodir",
+            metavar="REPO",
+            default=default_repodir,
+            help="Name of the repository where patch is merged",
+        )
+
+        parser.add_argument(
+            "--testdir",
+            metavar="TESTDIR",
+            default=default_testdir,
+            help="Directory where test cases are located",
+        )
+
+        parser.add_argument(
+            "--top-level-directory",
+            "-t",
+            dest="topdir",
+            default=None,
+            help="Top level directory of project (defaults to start directory)",
+        )
+
+        parser.add_argument(
+            "--pattern",
+            "-p",
+            dest="pattern",
+            default="test*.py",
+            help="Pattern to match test files",
+        )
+
+        parser.add_argument(
+            "--base-branch",
+            "-b",
+            dest="basebranch",
+            help="Branch name used by patchtest to branch from. By default, it uses the current one.",
+        )
+
+        parser.add_argument(
+            "--base-commit",
+            "-c",
+            dest="basecommit",
+            help="Commit ID used by patchtest to branch from. By default, it uses HEAD.",
+        )
+
+        parser.add_argument(
+            "--debug", "-d", action="store_true", help="Enable debug output"
+        )
+
+        parser.add_argument(
+            "--log-results",
+            action="store_true",
+            help='Enable logging to a file matching the target patch name with ".testresult" appended',
+        )
 
         return parser
-
diff --git a/meta/lib/patchtest/patchtest_patterns.py b/meta/lib/patchtest/patchtest_patterns.py
index 8c2e192fc9f..f332a070e5d 100644
--- a/meta/lib/patchtest/patchtest_patterns.py
+++ b/meta/lib/patchtest/patchtest_patterns.py
@@ -17,23 +17,23 @@  inappropriate = pyparsing.CaselessLiteral("Inappropriate")
 submitted = pyparsing.CaselessLiteral("Submitted")
 
 # word related
-nestexpr = pyparsing.nestedExpr(opener='[', closer=']')
+nestexpr = pyparsing.nestedExpr(opener="[", closer="]")
 inappropriateinfo = pyparsing.Literal("Inappropriate") + nestexpr
 submittedinfo = pyparsing.Literal("Submitted") + nestexpr
 word = pyparsing.Word(pyparsing.alphas)
-worddot = pyparsing.Word(pyparsing.alphas+".")
+worddot = pyparsing.Word(pyparsing.alphas + ".")
 
 # metadata
 
-metadata_lic = 'LICENSE'
-invalid_license = 'PATCHTESTINVALID'
-metadata_chksum = 'LIC_FILES_CHKSUM'
-license_var  = 'LICENSE'
-closed   = 'CLOSED'
-lictag_re  = pyparsing.AtLineStart("License-Update:")
+metadata_lic = "LICENSE"
+invalid_license = "PATCHTESTINVALID"
+metadata_chksum = "LIC_FILES_CHKSUM"
+license_var = "LICENSE"
+closed = "CLOSED"
+lictag_re = pyparsing.AtLineStart("License-Update:")
 lic_chksum_added = pyparsing.AtLineStart("+" + metadata_chksum)
 lic_chksum_removed = pyparsing.AtLineStart("-" + metadata_chksum)
-add_mark = pyparsing.Regex('\\+ ')
+add_mark = pyparsing.Regex("\\+ ")
 patch_max_line_length = 200
 metadata_src_uri = "SRC_URI"
 metadata_summary = "SUMMARY"
@@ -42,20 +42,20 @@  cve_status_var = "CVE_STATUS"
 endcommit_messages_regex = re.compile(
     r"\(From \w+-\w+ rev:|(?<!\S)Signed-off-by|(?<!\S)---\n"
 )
-patchmetadata_regex = re.compile(
-    r"-{3} \S+|\+{3} \S+|@{2} -\d+,\d+ \+\d+,\d+ @{2} \S+"
-)
+patchmetadata_regex = re.compile(r"-{3} \S+|\+{3} \S+|@{2} -\d+,\d+ \+\d+,\d+ @{2} \S+")
 
 # mbox
-auh_email = 'auh@yoctoproject.org'
+auh_email = "auh@yoctoproject.org"
 
-invalid_submitters = [pyparsing.Regex("^Upgrade Helper.+"),
-            pyparsing.Regex(auh_email),
-            pyparsing.Regex("uh@not\.set"),
-            pyparsing.Regex("\S+@example\.com")]
+invalid_submitters = [
+    pyparsing.Regex("^Upgrade Helper.+"),
+    pyparsing.Regex(auh_email),
+    pyparsing.Regex("uh@not\.set"),
+    pyparsing.Regex("\S+@example\.com"),
+]
 
-mbox_bugzilla = pyparsing.Regex('\[\s?YOCTO.*\]')
-mbox_bugzilla_validation = pyparsing.Regex('\[(\s?YOCTO\s?#\s?(\d+)\s?,?)+\]')
+mbox_bugzilla = pyparsing.Regex("\[\s?YOCTO.*\]")
+mbox_bugzilla_validation = pyparsing.Regex("\[(\s?YOCTO\s?#\s?(\d+)\s?,?)+\]")
 mbox_revert_shortlog_regex = pyparsing.Regex('Revert\s+".*"')
 mbox_shortlog_maxlength = 90
 
@@ -67,30 +67,56 @@  upstream_status_regex = pyparsing.AtLineStart("+" + "Upstream-Status")
 
 # shortlog
 
-shortlog_target = pyparsing.OneOrMore(pyparsing.Word(pyparsing.printables.replace(':','')))
+shortlog_target = pyparsing.OneOrMore(
+    pyparsing.Word(pyparsing.printables.replace(":", ""))
+)
 shortlog_summary = pyparsing.OneOrMore(pyparsing.Word(pyparsing.printables))
 shortlog = line_start + shortlog_target + colon + shortlog_summary + line_end
 
 # signed-off-bys
 
-email_pattern = pyparsing.Regex(r"(?P<user>[A-Za-z0-9._%+-]+)@(?P<hostname>[A-Za-z0-9.-]+)\.(?P<domain>[A-Za-z]{2,})")
+email_pattern = pyparsing.Regex(
+    r"(?P<user>[A-Za-z0-9._%+-]+)@(?P<hostname>[A-Za-z0-9.-]+)\.(?P<domain>[A-Za-z]{2,})"
+)
 
 signed_off_by_prefix = pyparsing.Literal("Signed-off-by:")
-signed_off_by_name = pyparsing.Regex('\S+.*(?= <)')
+signed_off_by_name = pyparsing.Regex("\S+.*(?= <)")
 signed_off_by_email = lessthan + email_pattern + greaterthan
-signed_off_by = pyparsing.AtLineStart(signed_off_by_prefix + signed_off_by_name + signed_off_by_email)
-patch_signed_off_by = pyparsing.AtLineStart("+" + signed_off_by_prefix + signed_off_by_name + signed_off_by_email)
+signed_off_by = pyparsing.AtLineStart(
+    signed_off_by_prefix + signed_off_by_name + signed_off_by_email
+)
+patch_signed_off_by = pyparsing.AtLineStart(
+    "+" + signed_off_by_prefix + signed_off_by_name + signed_off_by_email
+)
 
 # upstream-status
 
-upstream_status_literal_valid_status = ["Pending", "Backport", "Denied", "Inappropriate", "Submitted"]
-upstream_status_nonliteral_valid_status = ["Pending", "Backport", "Denied", "Inappropriate [reason]", "Submitted [where]"]
+upstream_status_literal_valid_status = [
+    "Pending",
+    "Backport",
+    "Denied",
+    "Inappropriate",
+    "Submitted",
+]
+upstream_status_nonliteral_valid_status = [
+    "Pending",
+    "Backport",
+    "Denied",
+    "Inappropriate [reason]",
+    "Submitted [where]",
+]
 
 upstream_status_valid_status = pyparsing.Or(
     [pyparsing.Literal(status) for status in upstream_status_literal_valid_status]
 )
 
 upstream_status_prefix = pyparsing.Literal("Upstream-Status")
-upstream_status = line_start + upstream_status_prefix + colon + upstream_status_valid_status
-upstream_status_inappropriate_info = line_start + upstream_status_prefix + colon + inappropriateinfo
-upstream_status_submitted_info = line_start + upstream_status_prefix + colon + submittedinfo
+upstream_status = (
+    line_start + upstream_status_prefix + colon + upstream_status_valid_status
+)
+upstream_status_inappropriate_info = (
+    line_start + upstream_status_prefix + colon + inappropriateinfo
+)
+upstream_status_submitted_info = (
+    line_start + upstream_status_prefix + colon + submittedinfo
+)
diff --git a/meta/lib/patchtest/repo.py b/meta/lib/patchtest/repo.py
index 8ec8f68a0bc..89ef2c2a5a4 100644
--- a/meta/lib/patchtest/repo.py
+++ b/meta/lib/patchtest/repo.py
@@ -12,10 +12,11 @@  import git
 import os
 import mbox
 
+
 class PatchTestRepo(object):
 
     # prefixes used for temporal branches/stashes
-    prefix = 'patchtest'
+    prefix = "patchtest"
 
     def __init__(self, patch, repodir, commit=None, branch=None):
         self.repodir = repodir
@@ -28,23 +29,27 @@  class PatchTestRepo(object):
         valid_patch_branch = None
         if self.patch.branch in self.repo.branches:
             valid_patch_branch = self.patch.branch
-            
+
         # Target Commit
         # Priority (top has highest priority):
         #    1. commit given at cmd line
         #    2. branch given at cmd line
         #    3. branch given at the patch
         #    3. current HEAD
-        self._commit = self._get_commitid(commit) or \
-          self._get_commitid(branch) or \
-          self._get_commitid(valid_patch_branch) or \
-          self._get_commitid('HEAD')
+        self._commit = (
+            self._get_commitid(commit)
+            or self._get_commitid(branch)
+            or self._get_commitid(valid_patch_branch)
+            or self._get_commitid("HEAD")
+        )
 
         self._workingbranch = "%s_%s" % (PatchTestRepo.prefix, os.getpid())
 
         # create working branch. Use the '-B' flag so that we just
         # check out the existing one if it's there
-        self.repo.git.execute(['git', 'checkout', '-B', self._workingbranch, self._commit])
+        self.repo.git.execute(
+            ["git", "checkout", "-B", self._workingbranch, self._commit]
+        )
 
         self._patchmerged = False
 
@@ -52,7 +57,10 @@  class PatchTestRepo(object):
         self._patchcanbemerged = True
         try:
             # Make sure to get the absolute path of the file
-            self.repo.git.execute(['git', 'apply', '--check', os.path.abspath(self.patch.path)], with_exceptions=True)
+            self.repo.git.execute(
+                ["git", "apply", "--check", os.path.abspath(self.patch.path)],
+                with_exceptions=True,
+            )
         except git.exc.GitCommandError as ce:
             self._patchcanbemerged = False
 
@@ -76,10 +84,12 @@  class PatchTestRepo(object):
 
     def merge(self):
         if self._patchcanbemerged:
-            self.repo.git.execute(['git', 'am', '--keep-cr', os.path.abspath(self.patch.path)])
+            self.repo.git.execute(
+                ["git", "am", "--keep-cr", os.path.abspath(self.patch.path)]
+            )
             self._patchmerged = True
 
     def clean(self):
-        self.repo.git.execute(['git', 'checkout', self.current_branch])
-        self.repo.git.execute(['git', 'branch', '-D', self._workingbranch])
+        self.repo.git.execute(["git", "checkout", self.current_branch])
+        self.repo.git.execute(["git", "branch", "-D", self._workingbranch])
         self._patchmerged = False
diff --git a/meta/lib/patchtest/selftest/selftest b/meta/lib/patchtest/selftest/selftest
index 6fad50ce616..9df6ecf7c68 100755
--- a/meta/lib/patchtest/selftest/selftest
+++ b/meta/lib/patchtest/selftest/selftest
@@ -11,18 +11,33 @@  import subprocess
 import sys
 
 currentdir = os.path.dirname(os.path.abspath(__file__))
-patchesdir = os.path.join(currentdir, 'files')
-topdir     = os.path.dirname(currentdir)
-parentdir  = os.path.dirname(topdir)
+patchesdir = os.path.join(currentdir, "files")
+topdir = os.path.dirname(currentdir)
+parentdir = os.path.dirname(topdir)
 
 # path to the repo root
 repodir = os.path.dirname(os.path.dirname(parentdir))
 
-def print_results(passcount, failcount, skipcount, xpasscount, xfailcount, xskipcount, errorcount):
-    total = passcount + skipcount + failcount + xpasscount + xfailcount + xskipcount + errorcount
-    print("============================================================================")
+
+def print_results(
+    passcount, failcount, skipcount, xpasscount, xfailcount, xskipcount, errorcount
+):
+    total = (
+        passcount
+        + skipcount
+        + failcount
+        + xpasscount
+        + xfailcount
+        + xskipcount
+        + errorcount
+    )
+    print(
+        "============================================================================"
+    )
     print("Testsuite summary for %s" % os.path.basename(topdir))
-    print("============================================================================")
+    print(
+        "============================================================================"
+    )
     print("# TOTAL: %s" % str(total))
     print("# XPASS: %s" % str(xpasscount))
     print("# XFAIL: %s" % str(xfailcount))
@@ -31,19 +46,29 @@  def print_results(passcount, failcount, skipcount, xpasscount, xfailcount, xskip
     print("# FAIL: %s" % str(failcount))
     print("# SKIP: %s" % str(skipcount))
     print("# ERROR: %s" % str(errorcount))
-    print("============================================================================")
+    print(
+        "============================================================================"
+    )
+
 
 # Once the tests are in oe-core, we can remove the testdir param and use os.path.dirname to get relative paths
 def test(root, patch):
     res = True
     patchpath = os.path.abspath(os.path.join(root, patch))
-    
-    cmd     = 'patchtest --repodir %s --testdir %s/tests --patch %s' % (repodir, topdir, patchpath)
-    results = subprocess.check_output(cmd, stderr=subprocess.STDOUT, universal_newlines=True, shell=True)
+
+    cmd = "patchtest --repodir %s --testdir %s/tests --patch %s" % (
+        repodir,
+        topdir,
+        patchpath,
+    )
+    results = subprocess.check_output(
+        cmd, stderr=subprocess.STDOUT, universal_newlines=True, shell=True
+    )
 
     return results
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     passcount = 0
     failcount = 0
     skipcount = 0
@@ -53,31 +78,47 @@  if __name__ == '__main__':
     errorcount = 0
 
     results = None
-        
+
     for root, dirs, patches in os.walk(patchesdir):
         for patch in patches:
             results = test(root, patch)
 
-            a = patch.split('.')
+            a = patch.split(".")
             klass, testname = a[0], a[1]
             expected_result = a[-1]
-            testid          = ".%s.%s" % (klass,testname)
+            testid = ".%s.%s" % (klass, testname)
 
             for resultline in results.splitlines():
                 if testid in resultline:
-                    result, _ = resultline.split(':', 1)
+                    result, _ = resultline.split(":", 1)
 
                     if expected_result.upper() == "FAIL" and result.upper() == "FAIL":
                         xfailcount = xfailcount + 1
-                        print("XFAIL: %s (file: %s)" % (testid.strip("."), os.path.basename(patch)))
+                        print(
+                            "XFAIL: %s (file: %s)"
+                            % (testid.strip("."), os.path.basename(patch))
+                        )
                     elif expected_result.upper() == "PASS" and result.upper() == "PASS":
                         xpasscount = xpasscount + 1
-                        print("XPASS: %s (file: %s)" % (testid.strip("."), os.path.basename(patch)))
+                        print(
+                            "XPASS: %s (file: %s)"
+                            % (testid.strip("."), os.path.basename(patch))
+                        )
                     elif expected_result.upper() == "SKIP" and result.upper() == "SKIP":
                         xskipcount = xskipcount + 1
-                        print("XSKIP: %s (file: %s)" % (testid.strip("."), os.path.basename(patch)))
+                        print(
+                            "XSKIP: %s (file: %s)"
+                            % (testid.strip("."), os.path.basename(patch))
+                        )
                     else:
-                        print("%s: %s (%s)" % (result.upper(), testid.strip("."), os.path.basename(patch)))
+                        print(
+                            "%s: %s (%s)"
+                            % (
+                                result.upper(),
+                                testid.strip("."),
+                                os.path.basename(patch),
+                            )
+                        )
                         if result.upper() == "PASS":
                             passcount = passcount + 1
                         elif result.upper() == "FAIL":
@@ -85,10 +126,15 @@  if __name__ == '__main__':
                         elif result.upper() == "SKIP":
                             skipcount = skipcount + 1
                         else:
-                            print("Bad result on test %s against %s" % (testid.strip("."), os.path.basename(patch)))
+                            print(
+                                "Bad result on test %s against %s"
+                                % (testid.strip("."), os.path.basename(patch))
+                            )
                             errorcount = errorcount + 1
                     break
             else:
-                print ("No test for=%s" % patch)
+                print("No test for=%s" % patch)
 
-    print_results(passcount, failcount, skipcount, xpasscount, xfailcount, xskipcount, errorcount)
+    print_results(
+        passcount, failcount, skipcount, xpasscount, xfailcount, xskipcount, errorcount
+    )
diff --git a/meta/lib/patchtest/tests/base.py b/meta/lib/patchtest/tests/base.py
index 919ca136bb4..a0e29e7f53c 100644
--- a/meta/lib/patchtest/tests/base.py
+++ b/meta/lib/patchtest/tests/base.py
@@ -26,40 +26,43 @@  Commit = collections.namedtuple(
     "Commit", ["author", "subject", "commit_message", "shortlog", "payload"]
 )
 
-Commit = collections.namedtuple('Commit', ['author', 'subject', 'commit_message', 'shortlog', 'payload'])
 
 class PatchtestOEError(Exception):
     """Exception for handling patchtest-oe errors"""
+
     def __init__(self, message, exitcode=1):
         super().__init__(message)
         self.exitcode = exitcode
 
+
 class Base(unittest.TestCase):
     # if unit test fails, fail message will throw at least the following JSON: {"id": <testid>}
 
     @staticmethod
     def msg_to_commit(msg):
         payload = msg.get_payload()
-        return Commit(subject=msg['subject'].replace('\n', ' ').replace('  ', ' '),
-                      author=msg.get('From'),
-                      shortlog=Base.shortlog(msg['subject']),
-                      commit_message=Base.commit_message(payload),
-                      payload=payload)
+        return Commit(
+            subject=msg["subject"].replace("\n", " ").replace("  ", " "),
+            author=msg.get("From"),
+            shortlog=Base.shortlog(msg["subject"]),
+            commit_message=Base.commit_message(payload),
+            payload=payload,
+        )
 
     @staticmethod
     def commit_message(payload):
         commit_message = payload.__str__()
         match = patchtest_patterns.endcommit_messages_regex.search(payload)
         if match:
-            commit_message = payload[:match.start()]
+            commit_message = payload[: match.start()]
         return commit_message
 
     @staticmethod
     def shortlog(shlog):
         # remove possible prefix (between brackets) before colon
-        start = shlog.find(']', 0, shlog.find(':'))
+        start = shlog.find("]", 0, shlog.find(":"))
         # remove also newlines and spaces at both sides
-        return shlog[start + 1:].replace('\n', '').strip()
+        return shlog[start + 1 :].replace("\n", "").strip()
 
     @classmethod
     def setUpClass(cls):
@@ -68,7 +71,7 @@  class Base(unittest.TestCase):
         cls.mbox = mailbox.mbox(PatchtestParser.repo.patch.path)
 
         # Patch may be malformed, so try parsing it
-        cls.unidiff_parse_error = ''
+        cls.unidiff_parse_error = ""
         cls.patchset = None
         try:
             cls.patchset = unidiff.PatchSet.from_filename(
@@ -81,7 +84,7 @@  class Base(unittest.TestCase):
         # Easy to iterate list of commits
         cls.commits = []
         for msg in cls.mbox:
-            if msg['subject'] and msg.get_payload():
+            if msg["subject"] and msg.get_payload():
                 cls.commits.append(Base.msg_to_commit(msg))
 
         cls.setUpClassLocal()
@@ -99,38 +102,36 @@  class Base(unittest.TestCase):
         pass
 
     def fail(self, issue, fix=None, commit=None, data=None):
-        """ Convert to a JSON string failure data"""
-        value = {'id': self.id(),
-                 'issue': issue}
+        """Convert to a JSON string failure data"""
+        value = {"id": self.id(), "issue": issue}
 
         if fix:
-            value['fix'] = fix
+            value["fix"] = fix
         if commit:
-            value['commit'] = {'subject': commit.subject,
-                               'shortlog': commit.shortlog}
+            value["commit"] = {"subject": commit.subject, "shortlog": commit.shortlog}
 
         # extend return value with other useful info
         if data:
-            value['data'] = data
+            value["data"] = data
 
         return super(Base, self).fail(json.dumps(value))
 
     def skip(self, issue, data=None):
-        """ Convert the skip string to JSON"""
-        value = {'id': self.id(),
-                 'issue': issue}
+        """Convert the skip string to JSON"""
+        value = {"id": self.id(), "issue": issue}
 
         # extend return value with other useful info
         if data:
-            value['data'] = data
+            value["data"] = data
 
         return super(Base, self).skipTest(json.dumps(value))
 
     def shortid(self):
-        return self.id().split('.')[-1]
+        return self.id().split(".")[-1]
 
     def __str__(self):
-        return json.dumps({'id': self.id()})
+        return json.dumps({"id": self.id()})
+
 
 class Metadata(Base):
     @classmethod
@@ -154,19 +155,20 @@  class Metadata(Base):
             if scripts_path not in sys.path:
                 sys.path.insert(0, scripts_path)
             import scriptpath
+
             scriptpath.add_bitbake_lib_path()
             import bb.tinfoil
         except ImportError:
-            raise PatchtestOEError('Could not import tinfoil module')
+            raise PatchtestOEError("Could not import tinfoil module")
 
         orig_cwd = os.path.abspath(os.curdir)
 
         # Load tinfoil
         tinfoil = None
         try:
-            builddir = os.environ.get('BUILDDIR')
+            builddir = os.environ.get("BUILDDIR")
             if not builddir:
-                logger.warn('Bitbake environment not loaded?')
+                logger.warn("Bitbake environment not loaded?")
                 return tinfoil
             os.chdir(builddir)
             tinfoil = bb.tinfoil.Tinfoil()
@@ -174,7 +176,9 @@  class Metadata(Base):
         except bb.tinfoil.TinfoilUIException as te:
             if tinfoil:
                 tinfoil.shutdown()
-            raise PatchtestOEError('Could not prepare properly tinfoil (TinfoilUIException)')
+            raise PatchtestOEError(
+                "Could not prepare properly tinfoil (TinfoilUIException)"
+            )
         except Exception as e:
             if tinfoil:
                 tinfoil.shutdown()
@@ -194,7 +198,7 @@  class Metadata(Base):
             pn_native = None
             for _path, _pn in data:
                 if path in _path:
-                    if 'native' in _pn:
+                    if "native" in _pn:
                         # store the native PN but look for the non-native one first
                         pn_native = _pn
                     else:
@@ -208,9 +212,9 @@  class Metadata(Base):
                 # on renames (usually upgrades), we need to check (FILE) base names
                 # because the unidiff library does not provided the new filename, just the modified one
                 # and tinfoil datastore, once the patch is merged, will contain the new filename
-                path_basename = path.split('_')[0]
+                path_basename = path.split("_")[0]
                 for _path, _pn in data:
-                    _path_basename = _path.split('_')[0]
+                    _path_basename = _path.split("_")[0]
                     if path_basename == _path_basename:
                         pn = _pn
             return pn
@@ -223,7 +227,11 @@  class Metadata(Base):
 
         # get metadata filename additions, modification and removals
         for patch in patchset:
-            if patch.path.endswith('.bb') or patch.path.endswith('.bbappend') or patch.path.endswith('.inc'):
+            if (
+                patch.path.endswith(".bb")
+                or patch.path.endswith(".bbappend")
+                or patch.path.endswith(".inc")
+            ):
                 if patch.is_added_file:
                     added_paths.append(
                         os.path.join(
@@ -243,10 +251,14 @@  class Metadata(Base):
                         )
                     )
 
-        data = cls.tinfoil.cooker.recipecaches[''].pkg_fn.items()
+        data = cls.tinfoil.cooker.recipecaches[""].pkg_fn.items()
 
-        added = [find_pn(data,path) for path in added_paths]
-        modified = [find_pn(data,path) for path in modified_paths]
-        removed = [find_pn(data,path) for path in removed_paths]
+        added = [find_pn(data, path) for path in added_paths]
+        modified = [find_pn(data, path) for path in modified_paths]
+        removed = [find_pn(data, path) for path in removed_paths]
 
-        return [a for a in added if a], [m for m in modified if m], [r for r in removed if r]
+        return (
+            [a for a in added if a],
+            [m for m in modified if m],
+            [r for r in removed if r],
+        )
diff --git a/meta/lib/patchtest/tests/test_mbox.py b/meta/lib/patchtest/tests/test_mbox.py
index c0f9970686a..22e4001613f 100644
--- a/meta/lib/patchtest/tests/test_mbox.py
+++ b/meta/lib/patchtest/tests/test_mbox.py
@@ -12,40 +12,73 @@  import re
 import subprocess
 from patchtest_parser import PatchtestParser
 
+
 def headlog():
     output = subprocess.check_output(
         "cd %s; git log --pretty='%%h#%%aN#%%cD:#%%s' -1" % PatchtestParser.repodir,
         universal_newlines=True,
-        shell=True
-        )
-    return output.split('#')
+        shell=True,
+    )
+    return output.split("#")
+
 
 class TestMbox(base.Base):
 
     # base paths of main yocto project sub-projects
     paths = {
-        'oe-core': ['meta-selftest', 'meta-skeleton', 'meta', 'scripts'],
-        'bitbake': ['bitbake'],
-        'documentation': ['documentation'],
-        'poky': ['meta-poky','meta-yocto-bsp'],
-        'oe': ['meta-gpe', 'meta-gnome', 'meta-efl', 'meta-networking', 'meta-multimedia','meta-initramfs', 'meta-ruby', 'contrib', 'meta-xfce', 'meta-filesystems', 'meta-perl', 'meta-webserver', 'meta-systemd', 'meta-oe', 'meta-python']
-        }
-
-    # scripts folder is a mix of oe-core and poky, most is oe-core code except:
-    poky_scripts = ['scripts/yocto-bsp', 'scripts/yocto-kernel', 'scripts/yocto-layer', 'scripts/lib/bsp']
-
-    Project = collections.namedtuple('Project', ['name', 'listemail', 'gitrepo', 'paths'])
-
-    bitbake = Project(name='Bitbake', listemail='bitbake-devel@lists.openembedded.org', gitrepo='http://git.openembedded.org/bitbake/', paths=paths['bitbake'])
-    doc     = Project(name='Documentantion', listemail='yocto@yoctoproject.org', gitrepo='http://git.yoctoproject.org/cgit/cgit.cgi/yocto-docs/', paths=paths['documentation'])
-    poky    = Project(name='Poky', listemail='poky@yoctoproject.org', gitrepo='http://git.yoctoproject.org/cgit/cgit.cgi/poky/', paths=paths['poky'])
-    oe      = Project(name='oe', listemail='openembedded-devel@lists.openembedded.org', gitrepo='http://git.openembedded.org/meta-openembedded/', paths=paths['oe'])
-
+        "oe-core": ["meta-selftest", "meta-skeleton", "meta", "scripts"],
+        "bitbake": ["bitbake"],
+        "documentation": ["documentation"],
+        "poky": ["meta-poky", "meta-yocto-bsp"],
+        "oe": [
+            "meta-filesystems",
+            "meta-gnome",
+            "meta-initramfs",
+            "meta-multimedia",
+            "meta-networking",
+            "meta-oe",
+            "meta-perl",
+            "meta-python",
+            "meta-webserver",
+            "meta-xfce",
+        ],
+    }
+
+    Project = collections.namedtuple(
+        "Project", ["name", "listemail", "gitrepo", "paths"]
+    )
+
+    bitbake = Project(
+        name="Bitbake",
+        listemail="bitbake-devel@lists.openembedded.org",
+        gitrepo="http://git.openembedded.org/bitbake/",
+        paths=paths["bitbake"],
+    )
+    doc = Project(
+        name="Documentantion",
+        listemail="yocto@yoctoproject.org",
+        gitrepo="http://git.yoctoproject.org/cgit/cgit.cgi/yocto-docs/",
+        paths=paths["documentation"],
+    )
+    poky = Project(
+        name="Poky",
+        listemail="poky@yoctoproject.org",
+        gitrepo="http://git.yoctoproject.org/cgit/cgit.cgi/poky/",
+        paths=paths["poky"],
+    )
+    oe = Project(
+        name="oe",
+        listemail="openembedded-devel@lists.openembedded.org",
+        gitrepo="http://git.openembedded.org/meta-openembedded/",
+        paths=paths["oe"],
+    )
 
     def test_signed_off_by_presence(self):
         for commit in self.commits:
             # skip those patches that revert older commits, these do not required the tag presence
-            if patchtest_patterns.mbox_revert_shortlog_regex.search_string(commit.shortlog):
+            if patchtest_patterns.mbox_revert_shortlog_regex.search_string(
+                commit.shortlog
+            ):
                 continue
             if not patchtest_patterns.signed_off_by.search_string(commit.payload):
                 self.fail(
@@ -57,7 +90,7 @@  class TestMbox(base.Base):
         for commit in self.commits:
             shortlog = commit.shortlog
             if not shortlog.strip():
-                self.skip('Empty shortlog, no reason to execute shortlog format test')
+                self.skip("Empty shortlog, no reason to execute shortlog format test")
             else:
                 # no reason to re-check on revert shortlogs
                 if shortlog.startswith('Revert "'):
@@ -65,13 +98,15 @@  class TestMbox(base.Base):
                 try:
                     patchtest_patterns.shortlog.parseString(shortlog)
                 except pyparsing.ParseException as pe:
-                    self.fail('Commit shortlog (first line of commit message) should follow the format "<target>: <summary>"',
-                              commit=commit)
+                    self.fail(
+                        'Commit shortlog (first line of commit message) should follow the format "<target>: <summary>"',
+                        commit=commit,
+                    )
 
     def test_shortlog_length(self):
         for commit in self.commits:
             # no reason to re-check on revert shortlogs
-            shortlog = re.sub('^(\[.*?\])+ ', '', commit.shortlog)
+            shortlog = re.sub("^(\[.*?\])+ ", "", commit.shortlog)
             if shortlog.startswith('Revert "'):
                 continue
             l = len(shortlog)
@@ -113,38 +148,63 @@  class TestMbox(base.Base):
         for commit in self.commits:
             match = project_regex.search_string(commit.subject)
             if match:
-                self.fail('Series sent to the wrong mailing list or some patches from the series correspond to different mailing lists',
-                          commit=commit)
+                self.fail(
+                    "Series sent to the wrong mailing list or some patches from the series correspond to different mailing lists",
+                    commit=commit,
+                )
 
         for patch in self.patchset:
-            folders = patch.path.split('/')
+            folders = patch.path.split("/")
             base_path = folders[0]
             for project in [self.bitbake, self.doc, self.oe, self.poky]:
-                if base_path in  project.paths:
-                    self.fail('Series sent to the wrong mailing list or some patches from the series correspond to different mailing lists',
-                              data=[('Suggested ML', '%s [%s]' % (project.listemail, project.gitrepo)),
-                                    ('Patch\'s path:', patch.path)])
+                if base_path in project.paths:
+                    self.fail(
+                        "Series sent to the wrong mailing list or some patches from the series correspond to different mailing lists",
+                        data=[
+                            (
+                                "Suggested ML",
+                                "%s [%s]" % (project.listemail, project.gitrepo),
+                            ),
+                            ("Patch's path:", patch.path),
+                        ],
+                    )
 
             # check for poky's scripts code
-            if base_path.startswith('scripts'):
+            if base_path.startswith("scripts"):
                 for poky_file in self.poky_scripts:
                     if patch.path.startswith(poky_file):
-                        self.fail('Series sent to the wrong mailing list or some patches from the series correspond to different mailing lists',
-                                  data=[('Suggested ML', '%s [%s]' % (self.poky.listemail, self.poky.gitrepo)),('Patch\'s path:', patch.path)])
+                        self.fail(
+                            "Series sent to the wrong mailing list or some patches from the series correspond to different mailing lists",
+                            data=[
+                                (
+                                    "Suggested ML",
+                                    "%s [%s]"
+                                    % (self.poky.listemail, self.poky.gitrepo),
+                                ),
+                                ("Patch's path:", patch.path),
+                            ],
+                        )
 
     def test_mbox_format(self):
         if self.unidiff_parse_error:
-            self.fail('Series has malformed diff lines. Create the series again using git-format-patch and ensure it applies using git am',
-                      data=[('Diff line',self.unidiff_parse_error)])
+            self.fail(
+                "Series has malformed diff lines. Create the series again using git-format-patch and ensure it applies using git am",
+                data=[("Diff line", self.unidiff_parse_error)],
+            )
 
     def test_commit_message_presence(self):
         for commit in self.commits:
             if not commit.commit_message.strip():
-                self.fail('Please include a commit message on your patch explaining the change', commit=commit)
+                self.fail(
+                    "Please include a commit message on your patch explaining the change",
+                    commit=commit,
+                )
 
     def test_bugzilla_entry_format(self):
         for commit in self.commits:
-            if not patchtest_patterns.mbox_bugzilla.search_string(commit.commit_message):
+            if not patchtest_patterns.mbox_bugzilla.search_string(
+                commit.commit_message
+            ):
                 self.skip("No bug ID found")
             elif not patchtest_patterns.mbox_bugzilla_validation.search_string(
                 commit.commit_message
@@ -158,7 +218,11 @@  class TestMbox(base.Base):
         for commit in self.commits:
             for invalid in patchtest_patterns.invalid_submitters:
                 if invalid.search_string(commit.author):
-                    self.fail('Invalid author %s. Resend the series with a valid patch author' % commit.author, commit=commit)
+                    self.fail(
+                        "Invalid author %s. Resend the series with a valid patch author"
+                        % commit.author,
+                        commit=commit,
+                    )
 
     def test_non_auh_upgrade(self):
         for commit in self.commits:
diff --git a/meta/lib/patchtest/tests/test_metadata.py b/meta/lib/patchtest/tests/test_metadata.py
index 2dee80b0023..b6b62a65884 100644
--- a/meta/lib/patchtest/tests/test_metadata.py
+++ b/meta/lib/patchtest/tests/test_metadata.py
@@ -14,19 +14,20 @@  from patchtest_parser import PatchtestParser
 # Data store commonly used to share values between pre and post-merge tests
 PatchTestDataStore = collections.defaultdict(str)
 
+
 class TestMetadata(base.Metadata):
 
     def test_license_presence(self):
         if not self.added:
-            self.skip('No added recipes, skipping test')
+            self.skip("No added recipes, skipping test")
 
         # TODO: this is a workaround so we can parse the recipe not
         # containing the LICENSE var: add some default license instead
         # of INVALID into auto.conf, then remove this line at the end
-        auto_conf = os.path.join(os.environ.get('BUILDDIR'), 'conf', 'auto.conf')
-        open_flag = 'w'
+        auto_conf = os.path.join(os.environ.get("BUILDDIR"), "conf", "auto.conf")
+        open_flag = "w"
         if os.path.exists(auto_conf):
-            open_flag = 'a'
+            open_flag = "a"
         with open(auto_conf, open_flag) as fd:
             for pn in self.added:
                 fd.write('LICENSE ??= "%s"\n' % patchtest_patterns.invalid_license)
@@ -40,43 +41,44 @@  class TestMetadata(base.Metadata):
                 break
 
         # remove auto.conf line or the file itself
-        if open_flag == 'w':
+        if open_flag == "w":
             os.remove(auto_conf)
         else:
-            fd = open(auto_conf, 'r')
+            fd = open(auto_conf, "r")
             lines = fd.readlines()
             fd.close()
-            with open(auto_conf, 'w') as fd:
-                fd.write(''.join(lines[:-1]))
+            with open(auto_conf, "w") as fd:
+                fd.write("".join(lines[:-1]))
 
         if no_license:
-            self.fail('Recipe does not have the LICENSE field set.')
+            self.fail("Recipe does not have the LICENSE field set.")
 
     def test_lic_files_chksum_presence(self):
         if not self.added:
-            self.skip('No added recipes, skipping test')
+            self.skip("No added recipes, skipping test")
 
         for pn in self.added:
             rd = self.tinfoil.parse_recipe(pn)
-            pathname = rd.getVar('FILE')
+            pathname = rd.getVar("FILE")
             # we are not interested in images
-            if '/images/' in pathname:
+            if "/images/" in pathname:
                 continue
             lic_files_chksum = rd.getVar(patchtest_patterns.metadata_chksum)
             if rd.getVar(patchtest_patterns.license_var) == patchtest_patterns.closed:
                 continue
             if not lic_files_chksum:
                 self.fail(
-                    "%s is missing in newly added recipe" % patchtest_patterns.metadata_chksum
+                    "%s is missing in newly added recipe"
+                    % patchtest_patterns.metadata_chksum
                 )
 
     def test_lic_files_chksum_modified_not_mentioned(self):
         if not self.modified:
-            self.skip('No modified recipes, skipping test')
+            self.skip("No modified recipes, skipping test")
 
         for patch in self.patchset:
             # for the moment, we are just interested in metadata
-            if patch.path.endswith('.patch'):
+            if patch.path.endswith(".patch"):
                 continue
             payload = str(patch)
             if patchtest_patterns.lic_chksum_added.search_string(
@@ -84,15 +86,19 @@  class TestMetadata(base.Metadata):
             ) or patchtest_patterns.lic_chksum_removed.search_string(payload):
                 # if any patch on the series contain reference on the metadata, fail
                 for commit in self.commits:
-                    if patchtest_patterns.lictag_re.search_string(commit.commit_message):
+                    if patchtest_patterns.lictag_re.search_string(
+                        commit.commit_message
+                    ):
                         break
                 else:
-                    self.fail('LIC_FILES_CHKSUM changed without "License-Update:" tag and description in commit message')
+                    self.fail(
+                        'LIC_FILES_CHKSUM changed without "License-Update:" tag and description in commit message'
+                    )
 
     def test_max_line_length(self):
         for patch in self.patchset:
             # for the moment, we are just interested in metadata
-            if patch.path.endswith('.patch'):
+            if patch.path.endswith(".patch"):
                 continue
             payload = str(patch)
             for line in payload.splitlines():
@@ -101,7 +107,10 @@  class TestMetadata(base.Metadata):
                     if current_line_length > patchtest_patterns.patch_max_line_length:
                         self.fail(
                             "Patch line too long (current length %s, maximum is %s)"
-                            % (current_line_length, patchtest_patterns.patch_max_line_length),
+                            % (
+                                current_line_length,
+                                patchtest_patterns.patch_max_line_length,
+                            ),
                             data=[
                                 ("Patch", patch.path),
                                 ("Line", "%s ..." % line[0:80]),
@@ -113,12 +122,12 @@  class TestMetadata(base.Metadata):
         if not PatchtestParser.repo.canbemerged:
             self.skip("Patch cannot be merged")
         if not self.modified:
-            self.skip('No modified recipes, skipping pretest')
+            self.skip("No modified recipes, skipping pretest")
 
         # get the proper metadata values
         for pn in self.modified:
             # we are not interested in images
-            if 'core-image' in pn:
+            if "core-image" in pn:
                 continue
             rd = self.tinfoil.parse_recipe(pn)
             PatchTestDataStore[
@@ -130,12 +139,12 @@  class TestMetadata(base.Metadata):
         if not PatchtestParser.repo.canbemerged:
             self.skip("Patch cannot be merged")
         if not self.modified:
-            self.skip('No modified recipes, skipping pretest')
+            self.skip("No modified recipes, skipping pretest")
 
         # get the proper metadata values
         for pn in self.modified:
             # we are not interested in images
-            if 'core-image' in pn:
+            if "core-image" in pn:
                 continue
             rd = self.tinfoil.parse_recipe(pn)
             PatchTestDataStore[
@@ -144,14 +153,27 @@  class TestMetadata(base.Metadata):
 
         for pn in self.modified:
             pretest_src_uri = PatchTestDataStore[
-                "pre%s-%s-%s" % (self.shortid(), patchtest_patterns.metadata_src_uri, pn)
+                "pre%s-%s-%s"
+                % (self.shortid(), patchtest_patterns.metadata_src_uri, pn)
             ].split()
             test_src_uri = PatchTestDataStore[
                 "%s-%s-%s" % (self.shortid(), patchtest_patterns.metadata_src_uri, pn)
             ].split()
 
-            pretest_files = set([os.path.basename(patch) for patch in pretest_src_uri if patch.startswith('file://')])
-            test_files    = set([os.path.basename(patch) for patch in test_src_uri    if patch.startswith('file://')])
+            pretest_files = set(
+                [
+                    os.path.basename(patch)
+                    for patch in pretest_src_uri
+                    if patch.startswith("file://")
+                ]
+            )
+            test_files = set(
+                [
+                    os.path.basename(patch)
+                    for patch in test_src_uri
+                    if patch.startswith("file://")
+                ]
+            )
 
             # check if files were removed
             if len(test_files) < len(pretest_files):
@@ -169,16 +191,18 @@  class TestMetadata(base.Metadata):
                 # TODO: we are not taking into account  renames, so test may raise false positives
                 not_removed = filesremoved_from_usr_uri - filesremoved_from_patchset
                 if not_removed:
-                    self.fail('Patches not removed from tree. Remove them and amend the submitted mbox',
-                              data=[('Patch', f) for f in not_removed])
+                    self.fail(
+                        "Patches not removed from tree. Remove them and amend the submitted mbox",
+                        data=[("Patch", f) for f in not_removed],
+                    )
 
     def test_summary_presence(self):
         if not self.added:
-            self.skip('No added recipes, skipping test')
+            self.skip("No added recipes, skipping test")
 
         for pn in self.added:
             # we are not interested in images
-            if 'core-image' in pn:
+            if "core-image" in pn:
                 continue
             rd = self.tinfoil.parse_recipe(pn)
             summary = rd.getVar(patchtest_patterns.metadata_summary)
@@ -186,7 +210,8 @@  class TestMetadata(base.Metadata):
             # "${PN} version ${PN}-${PR}" is the default, so fail if default
             if summary.startswith("%s version" % pn):
                 self.fail(
-                    "%s is missing in newly added recipe" % patchtest_patterns.metadata_summary
+                    "%s is missing in newly added recipe"
+                    % patchtest_patterns.metadata_summary
                 )
 
     def test_cve_check_ignore(self):
@@ -200,7 +225,7 @@  class TestMetadata(base.Metadata):
             self.skip("No modified recipes or older target branch, skipping test")
         for pn in self.modified:
             # we are not interested in images
-            if 'core-image' in pn:
+            if "core-image" in pn:
                 continue
             rd = self.tinfoil.parse_recipe(pn)
             cve_check_ignore = rd.getVar(patchtest_patterns.cve_check_ignore_var)
@@ -208,5 +233,8 @@  class TestMetadata(base.Metadata):
             if cve_check_ignore is not None:
                 self.fail(
                     "%s is deprecated and should be replaced by %s"
-                    % (patchtest_patterns.cve_check_ignore_var, patchtest_patterns.cve_status_var)
+                    % (
+                        patchtest_patterns.cve_check_ignore_var,
+                        patchtest_patterns.cve_status_var,
+                    )
                 )
diff --git a/meta/lib/patchtest/tests/test_patch.py b/meta/lib/patchtest/tests/test_patch.py
index d08b8a50192..6f4799e3ead 100644
--- a/meta/lib/patchtest/tests/test_patch.py
+++ b/meta/lib/patchtest/tests/test_patch.py
@@ -10,6 +10,7 @@  import os
 import patchtest_patterns
 import pyparsing
 
+
 class TestPatch(base.Base):
 
     @classmethod
@@ -17,7 +18,7 @@  class TestPatch(base.Base):
         cls.newpatches = []
         # get just those relevant patches: new software patches
         for patch in cls.patchset:
-            if patch.path.endswith('.patch') and patch.is_added_file:
+            if patch.path.endswith(".patch") and patch.is_added_file:
                 cls.newpatches.append(patch)
 
         cls.mark = str(patchtest_patterns.signed_off_by_prefix).strip('"')
@@ -27,21 +28,27 @@  class TestPatch(base.Base):
 
     def setUp(self):
         if self.unidiff_parse_error:
-            self.skip('Parse error %s' % self.unidiff_parse_error)
+            self.skip("Parse error %s" % self.unidiff_parse_error)
 
-        self.valid_status = ", ".join(patchtest_patterns.upstream_status_nonliteral_valid_status)
+        self.valid_status = ", ".join(
+            patchtest_patterns.upstream_status_nonliteral_valid_status
+        )
         self.standard_format = "Upstream-Status: <Valid status>"
 
         # we are just interested in series that introduce CVE patches, thus discard other
         # possibilities: modification to current CVEs, patch directly introduced into the
         # recipe, upgrades already including the CVE, etc.
-        new_cves = [p for p in self.patchset if p.path.endswith('.patch') and p.is_added_file]
+        new_cves = [
+            p for p in self.patchset if p.path.endswith(".patch") and p.is_added_file
+        ]
         if not new_cves:
-            self.skip('No new CVE patches introduced')
+            self.skip("No new CVE patches introduced")
 
     def test_upstream_status_presence_format(self):
         if not TestPatch.newpatches:
-            self.skip("There are no new software patches, no reason to test Upstream-Status presence/format")
+            self.skip(
+                "There are no new software patches, no reason to test Upstream-Status presence/format"
+            )
 
         for newpatch in TestPatch.newpatches:
             payload = newpatch.__str__()
@@ -91,7 +98,9 @@  class TestPatch(base.Base):
                             )
                     else:
                         try:
-                            patchtest_patterns.upstream_status.parseString(line.lstrip("+"))
+                            patchtest_patterns.upstream_status.parseString(
+                                line.lstrip("+")
+                            )
                         except pyparsing.ParseException as pe:
                             self.fail(
                                 "Upstream-Status is in incorrect format",
@@ -104,7 +113,10 @@  class TestPatch(base.Base):
 
     def test_signed_off_by_presence(self):
         if not TestPatch.newpatches:
-            self.skip("There are no new software patches, no reason to test %s presence" % PatchSignedOffBy.mark)
+            self.skip(
+                "There are no new software patches, no reason to test %s presence"
+                % PatchSignedOffBy.mark
+            )
 
         for newpatch in TestPatch.newpatches:
             payload = newpatch.__str__()
@@ -114,7 +126,10 @@  class TestPatch(base.Base):
                 if TestPatch.prog.search_string(payload):
                     break
             else:
-                self.fail('A patch file has been added without a Signed-off-by tag: \'%s\'' % os.path.basename(newpatch.path))
+                self.fail(
+                    "A patch file has been added without a Signed-off-by tag: '%s'"
+                    % os.path.basename(newpatch.path)
+                )
 
     def test_cve_tag_format(self):
         for commit in TestPatch.commits:
@@ -127,5 +142,7 @@  class TestPatch(base.Base):
                         tag_found = True
                         break
                 if not tag_found:
-                    self.fail('Missing or incorrectly formatted CVE tag in patch file. Correct or include the CVE tag in the patch with format: "CVE: CVE-YYYY-XXXX"',
-                              commit=commit)
+                    self.fail(
+                        'Missing or incorrectly formatted CVE tag in patch file. Correct or include the CVE tag in the patch with format: "CVE: CVE-YYYY-XXXX"',
+                        commit=commit,
+                    )
diff --git a/meta/lib/patchtest/tests/test_python_pylint.py b/meta/lib/patchtest/tests/test_python_pylint.py
index ec9129bc796..11b5c84fa03 100644
--- a/meta/lib/patchtest/tests/test_python_pylint.py
+++ b/meta/lib/patchtest/tests/test_python_pylint.py
@@ -12,9 +12,9 @@  import pylint.lint as lint
 
 
 class PyLint(base.Base):
-    pythonpatches  = []
+    pythonpatches = []
     pylint_pretest = {}
-    pylint_test    = {}
+    pylint_test = {}
     pylint_options = " -E --disable='E0611, E1101, F0401, E0602' --msg-template='L:{line} F:{module} I:{msg}'"
 
     @classmethod
@@ -22,26 +22,32 @@  class PyLint(base.Base):
         # get just those patches touching python files
         cls.pythonpatches = []
         for patch in cls.patchset:
-            if patch.path.endswith('.py'):
+            if patch.path.endswith(".py"):
                 if not patch.is_removed_file:
                     cls.pythonpatches.append(patch)
 
     def setUp(self):
         if self.unidiff_parse_error:
-            self.skip('Python-unidiff parse error')
+            self.skip("Python-unidiff parse error")
         if not PyLint.pythonpatches:
-            self.skip('No python related patches, skipping test')
+            self.skip("No python related patches, skipping test")
 
     def pretest_pylint(self):
         for pythonpatch in self.pythonpatches:
             if pythonpatch.is_modified_file:
                 pylint_output = StringIO()
                 reporter = TextReporter(pylint_output)
-                lint.Run([self.pylint_options, pythonpatch.path], reporter=reporter, exit=False)
+                lint.Run(
+                    [self.pylint_options, pythonpatch.path],
+                    reporter=reporter,
+                    exit=False,
+                )
                 for line in pylint_output.readlines():
-                    if not '*' in line:
+                    if not "*" in line:
                         if line.strip():
-                            self.pylint_pretest[line.strip().split(' ',1)[0]] = line.strip().split(' ',1)[1]
+                            self.pylint_pretest[line.strip().split(" ", 1)[0]] = (
+                                line.strip().split(" ", 1)[1]
+                            )
 
     def test_pylint(self):
         for pythonpatch in self.pythonpatches:
@@ -53,13 +59,22 @@  class PyLint(base.Base):
                 path = pythonpatch.path
             pylint_output = StringIO()
             reporter = TextReporter(pylint_output)
-            lint.Run([self.pylint_options, pythonpatch.path], reporter=reporter, exit=False)
+            lint.Run(
+                [self.pylint_options, pythonpatch.path], reporter=reporter, exit=False
+            )
             for line in pylint_output.readlines():
-                    if not '*' in line:
-                        if line.strip():
-                            self.pylint_test[line.strip().split(' ',1)[0]] = line.strip().split(' ',1)[1]
+                if not "*" in line:
+                    if line.strip():
+                        self.pylint_test[line.strip().split(" ", 1)[0]] = (
+                            line.strip().split(" ", 1)[1]
+                        )
 
         for issue in self.pylint_test:
-             if self.pylint_test[issue] not in self.pylint_pretest.values():
-                 self.fail('Errors in your Python code were encountered. Please check your code with a linter and resubmit',
-                           data=[('Output', 'Please, fix the listed issues:'), ('', issue + ' ' + self.pylint_test[issue])])
+            if self.pylint_test[issue] not in self.pylint_pretest.values():
+                self.fail(
+                    "Errors in your Python code were encountered. Please check your code with a linter and resubmit",
+                    data=[
+                        ("Output", "Please, fix the listed issues:"),
+                        ("", issue + " " + self.pylint_test[issue]),
+                    ],
+                )
diff --git a/scripts/patchtest b/scripts/patchtest
index 9218db232a7..99ce2f79131 100755
--- a/scripts/patchtest
+++ b/scripts/patchtest
@@ -20,7 +20,10 @@  import unittest
 sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
 
 # Include patchtest library
-sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), '../meta/lib/patchtest'))
+sys.path.insert(
+    0,
+    os.path.join(os.path.dirname(os.path.realpath(__file__)), "../meta/lib/patchtest"),
+)
 
 from patchtest_parser import PatchtestParser
 from repo import PatchTestRepo
@@ -33,16 +36,18 @@  logger.setLevel(logging.INFO)
 info = logger.info
 error = logger.error
 
+
 def getResult(patch, mergepatch, logfile=None):
 
     class PatchTestResult(unittest.TextTestResult):
-        """ Patchtest TextTestResult """
-        shouldStop  = True
+        """Patchtest TextTestResult"""
+
+        shouldStop = True
         longMessage = False
 
-        success     = 'PASS'
-        fail        = 'FAIL'
-        skip        = 'SKIP'
+        success = "PASS"
+        fail = "FAIL"
+        skip = "SKIP"
 
         def startTestRun(self):
             # let's create the repo already, it can be used later on
@@ -53,9 +58,9 @@  def getResult(patch, mergepatch, logfile=None):
                 "patch": patch,
             }
 
-            self.repo_error    = False
-            self.test_error    = False
-            self.test_failure  = False
+            self.repo_error = False
+            self.test_error = False
+            self.test_failure = False
 
             try:
                 self.repo = PatchtestParser.repo = PatchTestRepo(**repoargs)
@@ -74,39 +79,58 @@  def getResult(patch, mergepatch, logfile=None):
             logger.error(traceback.print_exc())
 
         def addFailure(self, test, err):
-            test_description = test.id().split('.')[-1].replace('_', ' ').replace("cve", "CVE").replace("signed off by",
-            "Signed-off-by").replace("upstream status",
-            "Upstream-Status").replace("non auh",
-            "non-AUH").replace("presence format", "presence")
+            test_description = (
+                test.id()
+                .split(".")[-1]
+                .replace("_", " ")
+                .replace("cve", "CVE")
+                .replace("signed off by", "Signed-off-by")
+                .replace("upstream status", "Upstream-Status")
+                .replace("non auh", "non-AUH")
+                .replace("presence format", "presence")
+            )
             self.test_failure = True
-            fail_str = '{}: {}: {} ({})'.format(self.fail,
-            test_description, json.loads(str(err[1]))["issue"],
-            test.id())
+            fail_str = "{}: {}: {} ({})".format(
+                self.fail, test_description, json.loads(str(err[1]))["issue"], test.id()
+            )
             print(fail_str)
             if logfile:
                 with open(logfile, "a") as f:
                     f.write(fail_str + "\n")
 
         def addSuccess(self, test):
-            test_description = test.id().split('.')[-1].replace('_', ' ').replace("cve", "CVE").replace("signed off by",
-            "Signed-off-by").replace("upstream status",
-            "Upstream-Status").replace("non auh",
-            "non-AUH").replace("presence format", "presence")
-            success_str = '{}: {} ({})'.format(self.success,
-            test_description, test.id())
+            test_description = (
+                test.id()
+                .split(".")[-1]
+                .replace("_", " ")
+                .replace("cve", "CVE")
+                .replace("signed off by", "Signed-off-by")
+                .replace("upstream status", "Upstream-Status")
+                .replace("non auh", "non-AUH")
+                .replace("presence format", "presence")
+            )
+            success_str = "{}: {} ({})".format(
+                self.success, test_description, test.id()
+            )
             print(success_str)
             if logfile:
                 with open(logfile, "a") as f:
                     f.write(success_str + "\n")
 
         def addSkip(self, test, reason):
-            test_description = test.id().split('.')[-1].replace('_', ' ').replace("cve", "CVE").replace("signed off by",
-            "Signed-off-by").replace("upstream status",
-            "Upstream-Status").replace("non auh",
-            "non-AUH").replace("presence format", "presence")
-            skip_str = '{}: {}: {} ({})'.format(self.skip,
-            test_description, json.loads(str(reason))["issue"],
-            test.id())
+            test_description = (
+                test.id()
+                .split(".")[-1]
+                .replace("_", " ")
+                .replace("cve", "CVE")
+                .replace("signed off by", "Signed-off-by")
+                .replace("upstream status", "Upstream-Status")
+                .replace("non auh", "non-AUH")
+                .replace("presence format", "presence")
+            )
+            skip_str = "{}: {}: {} ({})".format(
+                self.skip, test_description, json.loads(str(reason))["issue"], test.id()
+            )
             print(skip_str)
             if logfile:
                 with open(logfile, "a") as f:
@@ -122,6 +146,7 @@  def getResult(patch, mergepatch, logfile=None):
 
     return PatchTestResult
 
+
 def _runner(resultklass, prefix=None):
     # load test with the corresponding prefix
     loader = unittest.TestLoader()
@@ -145,29 +170,31 @@  def _runner(resultklass, prefix=None):
         result = runner.run(suite)
     except:
         logger.error(traceback.print_exc())
-        logger.error('patchtest: something went wrong')
+        logger.error("patchtest: something went wrong")
         return 1
     if result.test_failure or result.test_error:
-        return 1 
+        return 1
 
     return 0
 
+
 def run(patch, logfile=None):
-    """ Load, setup and run pre and post-merge tests """
+    """Load, setup and run pre and post-merge tests"""
     # Get the result class and install the control-c handler
     unittest.installHandler()
 
     # run pre-merge tests, meaning those methods with 'pretest' as prefix
     premerge_resultklass = getResult(patch, False, logfile)
-    premerge_result = _runner(premerge_resultklass, 'pretest')
+    premerge_result = _runner(premerge_resultklass, "pretest")
 
     # run post-merge tests, meaning those methods with 'test' as prefix
     postmerge_resultklass = getResult(patch, True, logfile)
-    postmerge_result = _runner(postmerge_resultklass, 'test')
+    postmerge_result = _runner(postmerge_resultklass, "test")
 
     print_result_message(premerge_result, postmerge_result)
     return premerge_result or postmerge_result
 
+
 def print_result_message(preresult, postresult):
     print("----------------------------------------------------------------------\n")
     if preresult == 2 and postresult == 2:
@@ -182,6 +209,7 @@  def print_result_message(preresult, postresult):
         logger.info("OK: patchtest: All patchtests passed")
     print("----------------------------------------------------------------------\n")
 
+
 def main():
     tmp_patch = False
     patch_path = PatchtestParser.patch_path
@@ -192,20 +220,25 @@  def main():
     git_status = os.popen("(cd %s && git status)" % PatchtestParser.repodir).read()
     status_matches = ["Changes not staged for commit", "Changes to be committed"]
     if any([match in git_status for match in status_matches]):
-        logger.error("patchtest: there are uncommitted changes in the target repo that would be overwritten. Please commit or restore them before running patchtest")
+        logger.error(
+            "patchtest: there are uncommitted changes in the target repo that would be overwritten. Please commit or restore them before running patchtest"
+        )
         return 1
 
     if os.path.isdir(patch_path):
-        patch_list = [os.path.join(patch_path, filename) for filename in sorted(os.listdir(patch_path))]
+        patch_list = [
+            os.path.join(patch_path, filename)
+            for filename in sorted(os.listdir(patch_path))
+        ]
     else:
         patch_list = [patch_path]
 
     for patch in patch_list:
         if os.path.getsize(patch) == 0:
-            logger.error('patchtest: patch is empty')
+            logger.error("patchtest: patch is empty")
             return 1
 
-        logger.info('Testing patch %s' % patch)
+        logger.info("Testing patch %s" % patch)
 
         if log_results:
             log_path = patch + ".testresult"
@@ -221,7 +254,8 @@  def main():
             if tmp_patch:
                 os.remove(patch)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     ret = 1
 
     # Parse the command line arguments and store it on the PatchtestParser namespace
@@ -239,6 +273,7 @@  if __name__ == '__main__':
         ret = main()
     except Exception:
         import traceback
+
         traceback.print_exc(5)
 
     sys.exit(ret)
diff --git a/scripts/patchtest-get-branch b/scripts/patchtest-get-branch
index c6e242f8b68..7ddb79cbb5a 100755
--- a/scripts/patchtest-get-branch
+++ b/scripts/patchtest-get-branch
@@ -18,16 +18,17 @@  import git
 
 re_prefix = re.compile(r"(\[.*\])", re.DOTALL)
 
+
 def get_branch(filepath_repo, filepath_mbox, default_branch):
     branch = None
 
     # get all remotes branches
-    gitbranches = git.Git(filepath_repo).branch('-a').splitlines()
+    gitbranches = git.Git(filepath_repo).branch("-a").splitlines()
 
     # from gitbranches, just get the names
-    branches = [b.split('/')[-1] for b in gitbranches]
+    branches = [b.split("/")[-1] for b in gitbranches]
 
-    subject = ' '.join(mailbox.mbox(filepath_mbox)[0]['subject'].splitlines())
+    subject = " ".join(mailbox.mbox(filepath_mbox)[0]["subject"].splitlines())
 
     # we expect that patches will have somewhere between one and three
     # consecutive sets of square brackets with tokens inside, e.g.:
@@ -42,23 +43,23 @@  def get_branch(filepath_repo, filepath_mbox, default_branch):
     # Or they may contain both:
     # [PATCH v2 3/4]
     # In any case, we want mprefix to contain all of these tokens so
-    # that we can search for branch names within them. 
-    mprefix = re.findall(r'\[.*?\]', subject)
+    # that we can search for branch names within them.
+    mprefix = re.findall(r"\[.*?\]", subject)
     found_branch = None
     if mprefix:
         # Iterate over the tokens and compare against the branch list to
         # figure out which one the patch is targeting
         for token in mprefix:
-             stripped = token.lower().strip('[]')
-             if default_branch in stripped:
-                 found_branch = default_branch
-                 break
-             else:
-                 for branch in branches:
-                     # ignore branches named "core"
-                     if branch != "core" and stripped.rfind(branch) != -1:
-                         found_branch = token.split(' ')[0].strip('[]')
-                         break
+            stripped = token.lower().strip("[]")
+            if default_branch in stripped:
+                found_branch = default_branch
+                break
+            else:
+                for branch in branches:
+                    # ignore branches named "core"
+                    if branch != "core" and stripped.rfind(branch) != -1:
+                        found_branch = token.split(" ")[0].strip("[]")
+                        break
 
     # if there's no mprefix content or no known branches were found in
     # the tokens, assume the target is master
@@ -67,15 +68,26 @@  def get_branch(filepath_repo, filepath_mbox, default_branch):
 
     return (subject, found_branch)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
 
     parser = argparse.ArgumentParser()
-    parser.add_argument('repo', metavar='REPO', help='Main repository')
-    parser.add_argument('mbox', metavar='MBOX', help='mbox filename')
-    parser.add_argument('--default-branch', metavar='DEFAULT_BRANCH', default='master', help='Use this branch if no one is found')
-    parser.add_argument('--separator', '-s', metavar='SEPARATOR', default=' ', help='Char separator for output data')
+    parser.add_argument("repo", metavar="REPO", help="Main repository")
+    parser.add_argument("mbox", metavar="MBOX", help="mbox filename")
+    parser.add_argument(
+        "--default-branch",
+        metavar="DEFAULT_BRANCH",
+        default="master",
+        help="Use this branch if no one is found",
+    )
+    parser.add_argument(
+        "--separator",
+        "-s",
+        metavar="SEPARATOR",
+        default=" ",
+        help="Char separator for output data",
+    )
     args = parser.parse_args()
 
     subject, branch = get_branch(args.repo, args.mbox, args.default_branch)
     print("branch: %s" % branch)
-
diff --git a/scripts/patchtest-send-results b/scripts/patchtest-send-results
index 8a3dadbd111..875388bf842 100755
--- a/scripts/patchtest-send-results
+++ b/scripts/patchtest-send-results
@@ -10,7 +10,7 @@ 
 # Copyright (C) 2023 BayLibre Inc.
 #
 # SPDX-License-Identifier: GPL-2.0-only
-# 
+#
 
 import argparse
 import boto3
@@ -33,19 +33,36 @@  under 'Yocto Project Subprojects'). For more information on specific
 failures, see: https://wiki.yoctoproject.org/wiki/Patchtest. Thank
 you!"""
 
-def has_a_failed_test(raw_results):
-    return any(raw_result.split(':')[0] == "FAIL" for raw_result in raw_results.splitlines())
 
-parser = argparse.ArgumentParser(description="Send patchtest results to a submitter for a given patch")
-parser.add_argument("-p", "--patch", dest="patch", required=True, help="The patch file to summarize")
-parser.add_argument("-d", "--debug", dest="debug", required=False, action='store_true', help="Print raw email headers and content, but don't actually send it")
+def has_a_failed_test(raw_results):
+    return any(
+        raw_result.split(":")[0] == "FAIL" for raw_result in raw_results.splitlines()
+    )
+
+
+parser = argparse.ArgumentParser(
+    description="Send patchtest results to a submitter for a given patch"
+)
+parser.add_argument(
+    "-p", "--patch", dest="patch", required=True, help="The patch file to summarize"
+)
+parser.add_argument(
+    "-d",
+    "--debug",
+    dest="debug",
+    required=False,
+    action="store_true",
+    help="Print raw email headers and content, but don't actually send it",
+)
 args = parser.parse_args()
 
 if not os.path.exists(args.patch):
     print(f"Patch '{args.patch}' not found - did you provide the right path?")
     sys.exit(1)
 elif not os.path.exists(args.patch + ".testresult"):
-    print(f"Found patch '{args.patch}' but '{args.patch}.testresult' was not present. Have you run patchtest on the patch?")
+    print(
+        f"Found patch '{args.patch}' but '{args.patch}.testresult' was not present. Have you run patchtest on the patch?"
+    )
     sys.exit(1)
 
 result_file = args.patch + ".testresult"
@@ -57,17 +74,17 @@  with open(result_file, "r") as f:
 # we know these patch files will only contain a single patch, so only
 # worry about the first element for getting the subject
 mbox = mailbox.mbox(args.patch)
-mbox_subject = mbox[0]['subject']
+mbox_subject = mbox[0]["subject"]
 subject_line = f"Patchtest results for {mbox_subject}"
 
 # extract the submitter email address and use it as the reply address
 # for the results
-reply_address = mbox[0]['from']
+reply_address = mbox[0]["from"]
 
 # extract the message ID and use that as the in-reply-to address
 # TODO: This will need to change again when patchtest can handle a whole
 # series at once
-in_reply_to = mbox[0]['Message-ID']
+in_reply_to = mbox[0]["Message-ID"]
 
 # the address the results email is sent from
 from_address = "patchtest@automation.yoctoproject.org"
@@ -77,24 +94,35 @@  cc_address = "openembedded-core@lists.openembedded.org"
 
 if has_a_failed_test(testresult):
     reply_contents = None
-    if len(max(open(result_file, 'r'), key=len)) > 220:
+    if len(max(open(result_file, "r"), key=len)) > 220:
         warning = "Tests failed for the patch, but the results log could not be processed due to excessive result line length."
         reply_contents = greeting + warning + suggestions
     else:
         reply_contents = greeting + testresult + suggestions
 
-    ses_client = boto3.client('ses', region_name='us-west-2')
+    ses_client = boto3.client("ses", region_name="us-west-2")
 
     # Construct the headers for the email. We only want to reply
     # directly to the tested patch, so make In-Reply-To and References
     # the same value.
-    raw_data = 'From: ' + from_address + '\nTo: ' + reply_address + \
-        '\nCC: ' + cc_address + '\nSubject:' + subject_line + \
-        '\nIn-Reply-To:' + in_reply_to + \
-        '\nReferences:' + in_reply_to + \
-        '\nMIME-Version: 1.0" + \
-        "\nContent-type: Multipart/Mixed;boundary="NextPart"\n\n--NextPart\nContent-Type: text/plain\n\n' + \
-        reply_contents + '\n\n--NextPart'
+    raw_data = (
+        "From: "
+        + from_address
+        + "\nTo: "
+        + reply_address
+        + "\nCC: "
+        + cc_address
+        + "\nSubject:"
+        + subject_line
+        + "\nIn-Reply-To:"
+        + in_reply_to
+        + "\nReferences:"
+        + in_reply_to
+        + '\nMIME-Version: 1.0" + \
+        "\nContent-type: Multipart/Mixed;boundary="NextPart"\n\n--NextPart\nContent-Type: text/plain\n\n'
+        + reply_contents
+        + "\n\n--NextPart"
+    )
 
     if args.debug:
         print(f"RawMessage: \n\n{raw_data}")