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

Bug#989077: unblock: ionit/0.3.8-1



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock package ionit

it fixes the YAMLLoadWarning from PyYAML 5.1+ and fixes the support for
ruamel.yaml.

[ Reason ]
1) python3-yaml 5.3.1-4 shows a YAMLLoadWarning.
2) When user have the alternative dependency python3-ruamel.yaml
installed instead of python3-yaml, ionit will fail.

[ Impact ]
Users will see the YAMLLoadWarning in the log output when using YAML
files. ionit will fail if users don't have python3-yaml installed (i.e.
they already have python3-ruamel.yaml installed).

[ Tests ]
ionit has 100% test coverage. The tests are run during package build
time and as autopkgtest against the installed system. There are upstream
tests to test having only python3-ruamel.yaml installed:
https://github.com/bdrung/ionit/actions/runs/863074972

[ Risks ]
The code change is trivial (5 lines in the ionit file). The package is
nearly a leaf package (only lsb build-depends on ionit).

[ Checklist ]
  [x] all changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in testing

[ Other info ]
I attach the full debdiff and the reduced debdiff. The reduce debdiff
has following stuff removed (since that is not relevant/trivial IMO):

* copyright year and email address update
* README.md update
* Added GitHub CI config file
* Changes to the unittests in the tests directory

unblock ionit/0.3.8-1

-- 
Benjamin Drung

Senior DevOps Engineer and Debian & Ubuntu Developer
Compute Platform Operations

1&1 IONOS SE | Greifswalder Str. 207 | 10405 Berlin | Deutschland
E-Mail: benjamin.drung@ionos.com | Web: www.ionos.de

Hauptsitz Montabaur, Amtsgericht Montabaur, HRB 24498

Vorstand: Hüseyin Dogan, Dr. Martin Endreß, Claudia Frese, Henning
Kettler, Arthur Mai, Matthias Steinberg, Achim Weiß
Aufsichtsratsvorsitzender: Markus Kadelke


Member of United Internet
diff -Nru ionit-0.3.6/debian/changelog ionit-0.3.8/debian/changelog
--- ionit-0.3.6/debian/changelog	2020-12-15 12:48:40.000000000 +0100
+++ ionit-0.3.8/debian/changelog	2021-05-21 09:27:45.000000000 +0200
@@ -1,3 +1,26 @@
+ionit (0.3.8-1) unstable; urgency=medium
+
+  * New upstream bug-fix release:
+    - tests: Mark ionit_plugin as first party module
+  * Let autopkgtest depend on black and ionit as well
+
+ -- Benjamin Drung <benjamin.drung@ionos.com>  Fri, 21 May 2021 09:27:45 +0200
+
+ionit (0.3.7-1) unstable; urgency=medium
+
+  * New upstream bug-fix release:
+    - Check import definition order with isort
+    - Add test case for black code formatter
+    - Fix YAMLLoadWarning with PyYAML 5.1+
+    - Fix support for ruamel.yaml
+    - setup.py: Add PyYAML as dependency
+  * Build-depend on black and isort
+  * Use py3dist-overrides for alternative yaml dependencies
+  * Update my email to the new ionos.com domain
+  * Update year in debian/copyright
+
+ -- Benjamin Drung <benjamin.drung@ionos.com>  Thu, 20 May 2021 20:30:09 +0200
+
 ionit (0.3.6-2) unstable; urgency=medium
 
   * Create/Remove empty /etc/ionit at install/purge (Closes: #977016)
diff -Nru ionit-0.3.6/debian/control ionit-0.3.8/debian/control
--- ionit-0.3.6/debian/control	2020-12-15 12:47:26.000000000 +0100
+++ ionit-0.3.8/debian/control	2021-05-21 09:27:45.000000000 +0200
@@ -1,9 +1,11 @@
 Source: ionit
 Section: utils
 Priority: optional
-Maintainer: Benjamin Drung <benjamin.drung@cloud.ionos.com>
-Build-Depends: debhelper-compat (= 13),
+Maintainer: Benjamin Drung <benjamin.drung@ionos.com>
+Build-Depends: black,
+               debhelper-compat (= 13),
                dh-python,
+               isort,
                pandoc,
                pylint (>= 2.2.2-2~) | pylint3,
                python3,
@@ -19,9 +21,7 @@
 
 Package: ionit
 Architecture: all
-Depends: python3-yaml | python3-ruamel.yaml,
-         ${misc:Depends},
-         ${python3:Depends}
+Depends: ${misc:Depends}, ${python3:Depends}
 Description: Render configuration files from Jinja templates
  ionit is a simple and small configuration templating tool. It collects a
  context and renders Jinja templates in a given directory. The context can be
diff -Nru ionit-0.3.6/debian/copyright ionit-0.3.8/debian/copyright
--- ionit-0.3.6/debian/copyright	2020-09-28 12:12:50.000000000 +0200
+++ ionit-0.3.8/debian/copyright	2021-05-21 09:27:45.000000000 +0200
@@ -1,7 +1,7 @@
 Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 
 Files: *
-Copyright: 2018-2019 Benjamin Drung <benjamin.drung@cloud.ionos.com>
+Copyright: 2018-2021 Benjamin Drung <benjamin.drung@ionos.com>
 License: ISC
  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
@@ -17,7 +17,7 @@
 
 Files: tests/mock_open.py tests/test_mock_open.py
 Copyright: 2013 Ionuț Arțăriși <ionut@artarisi.eu>
-           2018 Benjamin Drung <benjamin.drung@cloud.ionos.com>
+           2018 Benjamin Drung <benjamin.drung@ionos.com>
 License: MIT
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
diff -Nru ionit-0.3.6/debian/py3dist-overrides ionit-0.3.8/debian/py3dist-overrides
--- ionit-0.3.6/debian/py3dist-overrides	1970-01-01 01:00:00.000000000 +0100
+++ ionit-0.3.8/debian/py3dist-overrides	2021-05-21 09:27:45.000000000 +0200
@@ -0,0 +1 @@
+PyYAML python3-yaml | python3-ruamel.yaml
diff -Nru ionit-0.3.6/debian/tests/control ionit-0.3.8/debian/tests/control
--- ionit-0.3.6/debian/tests/control	2020-09-28 12:12:50.000000000 +0200
+++ ionit-0.3.8/debian/tests/control	2021-05-21 09:27:45.000000000 +0200
@@ -1,3 +1,3 @@
 Tests: unittest
 Restrictions: allow-stderr
-Depends: ionit, pylint (>= 2.2.2-2~) | pylint3, python3-flake8
+Depends: black, ionit, isort, pylint (>= 2.2.2-2~) | pylint3, python3-flake8
diff -Nru ionit-0.3.6/.github/workflows/ci.yaml ionit-0.3.8/.github/workflows/ci.yaml
--- ionit-0.3.6/.github/workflows/ci.yaml	1970-01-01 01:00:00.000000000 +0100
+++ ionit-0.3.8/.github/workflows/ci.yaml	2021-05-21 09:17:01.000000000 +0200
@@ -0,0 +1,65 @@
+name: CI
+
+on:
+  - push
+  - pull_request
+
+jobs:
+  unittest:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        container:
+          - debian:bullseye
+          - debian:testing
+          - debian:unstable
+          - ubuntu:focal
+          - ubuntu:groovy
+          - ubuntu:hirsute
+          - ubuntu:latest
+          - ubuntu:rolling
+          - ubuntu:devel
+        yaml_package:
+          - python3-ruamel.yaml
+          - python3-yaml
+    container:
+      image: ${{ matrix.container }}
+    steps:
+    - uses: actions/checkout@v2
+    - name: Install dependencies
+      run: |
+        apt-get update
+        apt-get install --yes black isort pylint python3 python3-coverage python3-flake8 python3-jinja2 ${{ matrix.yaml_package }}
+    - name: Run unit tests
+      run: |
+        python3 -m coverage run -m unittest discover -v
+        python3 -m coverage xml
+    - name: Install dependencies for Codecov
+      run: apt-get install --yes curl git
+    - name: Upload coverage to Codecov
+      uses: codecov/codecov-action@v1
+      with:
+        fail_ci_if_error: true
+        functionalities: gcov
+
+  # Debian buster needs pylint3 instead of pylint
+  unittest-debian-buster:
+    name: unittest debian:buster
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        yaml_package:
+          - python3-ruamel.yaml
+          - python3-yaml
+    container:
+      image: debian:buster
+    steps:
+    - uses: actions/checkout@v2
+    - name: Install dependencies
+      run: |
+        apt-get update
+        apt-get install --yes black isort pylint3 python3 python3-flake8 python3-jinja2 ${{ matrix.yaml_package }}
+    - name: Run unit tests
+      run: python3 -m unittest discover -v
diff -Nru ionit-0.3.6/ionit ionit-0.3.8/ionit
--- ionit-0.3.6/ionit	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/ionit	2021-05-21 09:17:01.000000000 +0200
@@ -1,6 +1,6 @@
 #!/usr/bin/python3
 
-# Copyright (C) 2018-2019, Benjamin Drung <benjamin.drung@cloud.ionos.com>
+# Copyright (C) 2018-2021, Benjamin Drung <benjamin.drung@ionos.com>
 #
 # Permission to use, copy, modify, and/or distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -24,10 +24,15 @@
 import sys
 
 import jinja2
-import yaml
 
 import ionit_plugin
 
+try:
+    import yaml
+except ImportError:
+    import ruamel.yaml as yaml
+
+
 DEFAULT_CONFIG = "/etc/ionit"
 LOG_FORMAT = "%(asctime)s %(name)s %(levelname)s: %(message)s"
 SCRIPT_NAME = "ionit"
@@ -128,7 +133,7 @@
             elif extension == ".yaml":
                 logger.info("Reading configuration file '%s'...", file)
                 with open(file) as config_file:
-                    file_context = yaml.load(config_file)
+                    file_context = yaml.load(config_file, Loader=yaml.SafeLoader)
             else:
                 logger.info(
                     "Skipping configuration file '%s', "
diff -Nru ionit-0.3.6/ionit.1.md ionit-0.3.8/ionit.1.md
--- ionit-0.3.6/ionit.1.md	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/ionit.1.md	2021-05-21 09:17:01.000000000 +0200
@@ -90,4 +90,4 @@
 
 # AUTHOR
 
-Benjamin Drung <benjamin.drung@cloud.ionos.com>
+Benjamin Drung <benjamin.drung@ionos.com>
diff -Nru ionit-0.3.6/ionit_plugin.py ionit-0.3.8/ionit_plugin.py
--- ionit-0.3.6/ionit_plugin.py	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/ionit_plugin.py	2021-05-21 09:17:01.000000000 +0200
@@ -1,4 +1,4 @@
-# Copyright (C) 2018-2019, Benjamin Drung <benjamin.drung@cloud.ionos.com>
+# Copyright (C) 2018-2021, Benjamin Drung <benjamin.drung@ionos.com>
 #
 # Permission to use, copy, modify, and/or distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
diff -Nru ionit-0.3.6/LICENSE ionit-0.3.8/LICENSE
--- ionit-0.3.6/LICENSE	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/LICENSE	2021-05-21 09:17:01.000000000 +0200
@@ -1,6 +1,6 @@
 ionit is licensed under ISC:
 
-Copyright (C) 2018-2019, Benjamin Drung <benjamin.drung@cloud.ionos.com>
+Copyright (C) 2018-2021, Benjamin Drung <benjamin.drung@ionos.com>
 
 Permission to use, copy, modify, and/or distribute this software for any
 purpose with or without fee is hereby granted, provided that the above
diff -Nru ionit-0.3.6/NEWS ionit-0.3.8/NEWS
--- ionit-0.3.6/NEWS	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/NEWS	2021-05-21 09:17:01.000000000 +0200
@@ -1,3 +1,16 @@
+ionit 0.3.7 (2021-05-21)
+
+* tests: Mark ionit_plugin as first party module
+
+ionit 0.3.7 (2021-05-20)
+
+* Check import definition order with isort
+* Fix code format for older black versions
+* Add test case for black code formatter
+* Fix YAMLLoadWarning with PyYAML 5.1+
+* Add support for ruamel.yaml
+* setup.py: Add PyYAML as dependency
+
 ionit 0.3.6 (2020-09-28)
 
 * Address issues found by pylint 2.6.0 (fixes Debian bug #971138)
diff -Nru ionit-0.3.6/README.md ionit-0.3.8/README.md
--- ionit-0.3.6/README.md	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/README.md	2021-05-21 09:17:01.000000000 +0200
@@ -1,3 +1,11 @@
+[![CI](https://img.shields.io/github/workflow/status/bdrung/ionit/CI)](https://github.com/bdrung/ionit/actions/workflows/ci.yaml)
+[![Codecov](https://img.shields.io/codecov/c/github/bdrung/ionit)](https://codecov.io/gh/bdrung/ionit)
+[![Code Style: black](https://img.shields.io/badge/code%20style-black-black)](https://github.com/psf/black)
+[![License: ISC](https://img.shields.io/badge/license-ISC-blue)](LICENSE)
+[![Debian package](https://img.shields.io/debian/v/ionit/unstable)](https://tracker.debian.org/pkg/ionit)
+[![PyPI project](https://img.shields.io/pypi/v/ionit)](https://pypi.org/project/ionit/)
+[![Ubuntu package](https://img.shields.io/ubuntu/v/ionit)](https://launchpad.net/ubuntu/+source/ionit)
+
 ionit
 =====
 
@@ -60,12 +68,14 @@
 * Python >= 3.4
 * Python modules:
   * jinja2
-  * yaml or ruamel.yaml
+  * PyYAML or ruamel.yaml
 * pandoc (to generate `ionit.1` man page from `ionit.1.md`)
 
 The test cases have additional requirements:
 
+* black
 * flake8
+* isort
 * pylint
 
 Examples
@@ -133,10 +143,12 @@
 Creating releases
 =================
 
-To create a release, increase the version in `setup.py`, document the
-noteworthy changes in `NEWS`, and commit the change. Tag the release:
+This project uses [semantic versioning](https://semver.org/). To create a
+release, increase the version in `setup.py` and document the noteworthy changes
+in `NEWS`. Then commit the changes and tag the release:
 
 ```
+git commit -sm "Release ionit $(./setup.py --version)" NEWS setup.py
 git tag v$(./setup.py --version)
 ```
 
@@ -146,3 +158,10 @@
 git archive --prefix="$name/" HEAD | xz -c9 > "../$name.tar.xz"
 gpg --output "../$name.tar.xz.asc" --armor --detach-sign "../$name.tar.xz"
 ```
+
+The package for PyPI can be built and uploaded by running:
+
+```
+pyproject-build --no-isolation
+twine upload --repository pypi dist/*
+```
diff -Nru ionit-0.3.6/setup.py ionit-0.3.8/setup.py
--- ionit-0.3.6/setup.py	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/setup.py	2021-05-21 09:17:01.000000000 +0200
@@ -1,6 +1,6 @@
 #!/usr/bin/python3
 
-# Copyright (C) 2018-2019, Benjamin Drung <benjamin.drung@cloud.ionos.com>
+# Copyright (C) 2018-2021, Benjamin Drung <benjamin.drung@ionos.com>
 #
 # Permission to use, copy, modify, and/or distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -32,22 +32,37 @@
 
 
 if __name__ == "__main__":
+    with open("README.md", "r", encoding="utf-8") as fh:
+        LONG_DESCRIPTION = fh.read()
+
     setup(
         name="ionit",
-        version="0.3.6",
+        version="0.3.8",
         description="Render configuration files from Jinja templates",
-        long_description=(
-            "ionit is a simple and small configuration templating tool. It collects a context and "
-            "renders Jinja templates in a given directory. The context can be either static JSON "
-            "or YAML files or dynamic Python files. Python files can also define functions passed "
-            "through to the rendering."
-        ),
+        long_description=LONG_DESCRIPTION,
+        long_description_content_type="text/markdown",
         author="Benjamin Drung",
-        author_email="benjamin.drung@cloud.ionos.com",
+        author_email="benjamin.drung@ionos.com",
         url="https://github.com/bdrung/ionit";,
+        project_urls={"Bug Tracker": "https://github.com/bdrung/ionit/issues"},
         license="ISC",
-        install_requires=["jinja2"],
+        classifiers=[
+            "Development Status :: 5 - Production/Stable",
+            "Environment :: Console",
+            "License :: OSI Approved :: ISC License (ISCL)",
+            "Operating System :: POSIX",
+            "Programming Language :: Python :: 3",
+            "Programming Language :: Python :: 3 :: Only",
+            "Programming Language :: Python :: 3.4",
+            "Programming Language :: Python :: 3.5",
+            "Programming Language :: Python :: 3.6",
+            "Programming Language :: Python :: 3.7",
+            "Programming Language :: Python :: 3.8",
+            "Programming Language :: Python :: 3.9",
+        ],
+        install_requires=["jinja2", "PyYAML"],
         scripts=["ionit"],
         py_modules=["ionit_plugin"],
         data_files=[(systemd_unit_path(), ["ionit.service"])],
+        python_requires=">=3.4",
     )
diff -Nru ionit-0.3.6/tests/config/python/number.py ionit-0.3.8/tests/config/python/number.py
--- ionit-0.3.6/tests/config/python/number.py	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/tests/config/python/number.py	2021-05-21 09:17:01.000000000 +0200
@@ -1,5 +1,2 @@
 def collect_context(_):
-    return {
-        "small": 42,
-        "big": 8000,
-    }
+    return {"small": 42, "big": 8000}
diff -Nru ionit-0.3.6/tests/__init__.py ionit-0.3.8/tests/__init__.py
--- ionit-0.3.6/tests/__init__.py	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/tests/__init__.py	2021-05-21 09:17:01.000000000 +0200
@@ -1,4 +1,4 @@
-# Copyright (C) 2017, Benjamin Drung <benjamin.drung@cloud.ionos.com>
+# Copyright (C) 2017-2021, Benjamin Drung <benjamin.drung@ionos.com>
 #
 # Permission to use, copy, modify, and/or distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -12,16 +12,15 @@
 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-"""Helper functions for testing ionit"""
+"""Helper functions for testing ionit."""
 
 import inspect
 import os
-import sys
 import unittest
 
 
 def get_source_files():
-    """Return a list of sources files/directories (to check with flake8/pylint)"""
+    """Return a list of sources files/directories (to check with flake8/pylint)."""
     scripts = ["ionit"]
     modules = ["tests"]
     py_files = ["ionit_plugin.py", "setup.py"]
@@ -36,8 +35,7 @@
         if is_script:
             with open(code_file, "rb") as script_file:
                 shebang = script_file.readline().decode("utf-8")
-            if ((sys.version_info[0] == 3 and "python3" in shebang) or
-                    ("python" in shebang and "python3" not in shebang)):
+            if "python" in shebang:
                 files.append(code_file)
         else:
             files.append(code_file)
@@ -45,8 +43,10 @@
 
 
 def unittest_verbosity():
-    """Return the verbosity setting of the currently running unittest
-    program, or None if none is running.
+    """
+    Return the verbosity setting of the currently running unittest.
+
+    If no test is running, return 0.
     """
     frame = inspect.currentframe()
     while frame:
@@ -54,4 +54,4 @@
         if isinstance(self, unittest.TestProgram):
             return self.verbosity
         frame = frame.f_back
-    return None  # pragma: no cover
+    return 0  # pragma: no cover
diff -Nru ionit-0.3.6/tests/mock_open.py ionit-0.3.8/tests/mock_open.py
--- ionit-0.3.6/tests/mock_open.py	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/tests/mock_open.py	2021-05-21 09:17:01.000000000 +0200
@@ -1,7 +1,7 @@
 # The MIT License (MIT)
 
 # Copyright (c) 2013 Ionuț Arțăriși <ionut@artarisi.eu>
-#               2018 Benjamin Drung <benjamin.drung@cloud.ionos.com>
+#               2018 Benjamin Drung <benjamin.drung@ionos.com>
 
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
diff -Nru ionit-0.3.6/tests/pylint.conf ionit-0.3.8/tests/pylint.conf
--- ionit-0.3.6/tests/pylint.conf	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/tests/pylint.conf	2021-05-21 09:17:01.000000000 +0200
@@ -27,7 +27,7 @@
 [SIMILARITIES]
 
 # Minimum lines number of a similarity.
-min-similarity-lines=5
+min-similarity-lines=6
 
 
 [FORMAT]
diff -Nru ionit-0.3.6/tests/test_black.py ionit-0.3.8/tests/test_black.py
--- ionit-0.3.6/tests/test_black.py	1970-01-01 01:00:00.000000000 +0100
+++ ionit-0.3.8/tests/test_black.py	2021-05-21 09:17:01.000000000 +0200
@@ -0,0 +1,45 @@
+# Copyright (C) 2021, Benjamin Drung <bdrung@debian.org>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+"""Run black code formatter in check mode."""
+
+import subprocess
+import sys
+import unittest
+
+from . import get_source_files, unittest_verbosity
+
+
+class BlackTestCase(unittest.TestCase):
+    """
+    This unittest class provides a test that runs the black code
+    formatter in check mode on the Python source code. The list of
+    source files is provided by the get_source_files() function.
+    """
+
+    def test_black(self):
+        """Test: Run black code formatter on Python source code."""
+
+        cmd = ["black", "--check", "--diff", "-l", "99"] + get_source_files()
+        if unittest_verbosity() >= 2:
+            sys.stderr.write("Running following command:\n{}\n".format(" ".join(cmd)))
+        process = subprocess.Popen(
+            cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True
+        )
+        output = process.communicate()[0].decode()
+
+        if process.returncode == 1:  # pragma: no cover
+            self.fail("black found code that needs reformatting:\n{}".format(output.strip()))
+        if process.returncode != 0:  # pragma: no cover
+            self.fail("black exited with code {}:\n{}".format(process.returncode, output.strip()))
diff -Nru ionit-0.3.6/tests/test_flake8.py ionit-0.3.8/tests/test_flake8.py
--- ionit-0.3.6/tests/test_flake8.py	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/tests/test_flake8.py	2021-05-21 09:17:01.000000000 +0200
@@ -12,7 +12,7 @@
 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-"""test_flake8.py - Run flake8 check"""
+"""Run flake8 check."""
 
 import subprocess
 import sys
@@ -30,7 +30,7 @@
     """
 
     def test_flake8(self):
-        """Test: Run flake8 on Python source code"""
+        """Test: Run flake8 on Python source code."""
         cmd = [sys.executable, "-m", "flake8", "--max-line-length=99"] + get_source_files()
         if unittest_verbosity() >= 2:
             sys.stderr.write("Running following command:\n{}\n".format(" ".join(cmd)))
diff -Nru ionit-0.3.6/tests/test_ionit.py ionit-0.3.8/tests/test_ionit.py
--- ionit-0.3.6/tests/test_ionit.py	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/tests/test_ionit.py	2021-05-21 09:17:01.000000000 +0200
@@ -1,4 +1,4 @@
-# Copyright (C) 2018-2019, Benjamin Drung <benjamin.drung@cloud.ionos.com>
+# Copyright (C) 2018-2021, Benjamin Drung <benjamin.drung@ionos.com>
 #
 # Permission to use, copy, modify, and/or distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -281,8 +281,9 @@
         template_dir = os.path.join(TEMPLATE_DIR, "static")
         context = {"first": "A", "second": "B"}
         with self.assertLogs("ionit", level="ERROR") as context_manager:
-            with mock_open(os.path.join(template_dir, "counting"),
-                           exception=PermissionError(13, "Permission denied"), complain=False):
+            counting_filename = os.path.join(template_dir, "counting")
+            permission_error = PermissionError(13, "Permission denied")
+            with mock_open(counting_filename, exception=permission_error, complain=False):
                 self.assertEqual(render_templates(template_dir, context, "jinja"), 1)
             self.assertFalse(os.path.exists(os.path.join(template_dir, "counting")))
             self.assertEqual(len(context_manager.output), 1)
diff -Nru ionit-0.3.6/tests/test_isort.py ionit-0.3.8/tests/test_isort.py
--- ionit-0.3.6/tests/test_isort.py	1970-01-01 01:00:00.000000000 +0100
+++ ionit-0.3.8/tests/test_isort.py	2021-05-21 09:17:01.000000000 +0200
@@ -0,0 +1,51 @@
+# Copyright (C) 2021, Benjamin Drung <bdrung@debian.org>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+"""Run isort to check if Python import definitions are sorted."""
+
+import subprocess
+import sys
+import unittest
+
+from . import get_source_files, unittest_verbosity
+
+
+class IsortTestCase(unittest.TestCase):
+    """
+    This unittest class provides a test that runs isort to check if
+    Python import definitions are sorted. The list of source files
+    is provided by the get_source_files() function.
+    """
+
+    def test_isort(self):
+        """Test: Run isort on Python source code."""
+
+        cmd = [
+            "isort",
+            "--check-only",
+            "--diff",
+            "-l",
+            "99",
+            "-p",
+            "ionit_plugin",
+        ] + get_source_files()
+        if unittest_verbosity() >= 2:
+            sys.stderr.write("Running following command:\n{}\n".format(" ".join(cmd)))
+        process = subprocess.Popen(
+            cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True
+        )
+        output = process.communicate()[0].decode()
+
+        if process.returncode != 0:  # pragma: no cover
+            self.fail("isort found unsorted Python import definitions:\n{}".format(output.strip()))
diff -Nru ionit-0.3.6/tests/test_pylint.py ionit-0.3.8/tests/test_pylint.py
--- ionit-0.3.6/tests/test_pylint.py	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/tests/test_pylint.py	2021-05-21 09:17:01.000000000 +0200
@@ -13,7 +13,7 @@
 # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-"""test_pylint.py - Run pylint"""
+"""Run pylint."""
 
 import os
 import re
@@ -35,7 +35,7 @@
     """
 
     def test_pylint(self):
-        """Test: Run pylint on Python source code"""
+        """Test: Run pylint on Python source code."""
 
         cmd = [sys.executable, "-m", "pylint", "--rcfile=" + CONFIG, "--"] + get_source_files()
         if unittest_verbosity() >= 2:
diff -Nru ionit-0.3.6/debian/changelog ionit-0.3.8/debian/changelog
--- ionit-0.3.6/debian/changelog	2020-12-15 12:48:40.000000000 +0100
+++ ionit-0.3.8/debian/changelog	2021-05-21 09:27:45.000000000 +0200
@@ -1,3 +1,26 @@
+ionit (0.3.8-1) unstable; urgency=medium
+
+  * New upstream bug-fix release:
+    - tests: Mark ionit_plugin as first party module
+  * Let autopkgtest depend on black and ionit as well
+
+ -- Benjamin Drung <benjamin.drung@ionos.com>  Fri, 21 May 2021 09:27:45 +0200
+
+ionit (0.3.7-1) unstable; urgency=medium
+
+  * New upstream bug-fix release:
+    - Check import definition order with isort
+    - Add test case for black code formatter
+    - Fix YAMLLoadWarning with PyYAML 5.1+
+    - Fix support for ruamel.yaml
+    - setup.py: Add PyYAML as dependency
+  * Build-depend on black and isort
+  * Use py3dist-overrides for alternative yaml dependencies
+  * Update my email to the new ionos.com domain
+  * Update year in debian/copyright
+
+ -- Benjamin Drung <benjamin.drung@ionos.com>  Thu, 20 May 2021 20:30:09 +0200
+
 ionit (0.3.6-2) unstable; urgency=medium
 
   * Create/Remove empty /etc/ionit at install/purge (Closes: #977016)
diff -Nru ionit-0.3.6/debian/control ionit-0.3.8/debian/control
--- ionit-0.3.6/debian/control	2020-12-15 12:47:26.000000000 +0100
+++ ionit-0.3.8/debian/control	2021-05-21 09:27:45.000000000 +0200
@@ -1,9 +1,11 @@
 Source: ionit
 Section: utils
 Priority: optional
-Maintainer: Benjamin Drung <benjamin.drung@cloud.ionos.com>
-Build-Depends: debhelper-compat (= 13),
+Maintainer: Benjamin Drung <benjamin.drung@ionos.com>
+Build-Depends: black,
+               debhelper-compat (= 13),
                dh-python,
+               isort,
                pandoc,
                pylint (>= 2.2.2-2~) | pylint3,
                python3,
@@ -19,9 +21,7 @@
 
 Package: ionit
 Architecture: all
-Depends: python3-yaml | python3-ruamel.yaml,
-         ${misc:Depends},
-         ${python3:Depends}
+Depends: ${misc:Depends}, ${python3:Depends}
 Description: Render configuration files from Jinja templates
  ionit is a simple and small configuration templating tool. It collects a
  context and renders Jinja templates in a given directory. The context can be
diff -Nru ionit-0.3.6/debian/py3dist-overrides ionit-0.3.8/debian/py3dist-overrides
--- ionit-0.3.6/debian/py3dist-overrides	1970-01-01 01:00:00.000000000 +0100
+++ ionit-0.3.8/debian/py3dist-overrides	2021-05-21 09:27:45.000000000 +0200
@@ -0,0 +1 @@
+PyYAML python3-yaml | python3-ruamel.yaml
diff -Nru ionit-0.3.6/debian/tests/control ionit-0.3.8/debian/tests/control
--- ionit-0.3.6/debian/tests/control	2020-09-28 12:12:50.000000000 +0200
+++ ionit-0.3.8/debian/tests/control	2021-05-21 09:27:45.000000000 +0200
@@ -1,3 +1,3 @@
 Tests: unittest
 Restrictions: allow-stderr
-Depends: ionit, pylint (>= 2.2.2-2~) | pylint3, python3-flake8
+Depends: black, ionit, isort, pylint (>= 2.2.2-2~) | pylint3, python3-flake8
diff -Nru ionit-0.3.6/ionit ionit-0.3.8/ionit
--- ionit-0.3.6/ionit	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/ionit	2021-05-21 09:17:01.000000000 +0200
@@ -24,10 +24,15 @@
 import sys
 
 import jinja2
-import yaml
 
 import ionit_plugin
 
+try:
+    import yaml
+except ImportError:
+    import ruamel.yaml as yaml
+
+
 DEFAULT_CONFIG = "/etc/ionit"
 LOG_FORMAT = "%(asctime)s %(name)s %(levelname)s: %(message)s"
 SCRIPT_NAME = "ionit"
@@ -128,7 +133,7 @@
             elif extension == ".yaml":
                 logger.info("Reading configuration file '%s'...", file)
                 with open(file) as config_file:
-                    file_context = yaml.load(config_file)
+                    file_context = yaml.load(config_file, Loader=yaml.SafeLoader)
             else:
                 logger.info(
                     "Skipping configuration file '%s', "
diff -Nru ionit-0.3.6/NEWS ionit-0.3.8/NEWS
--- ionit-0.3.6/NEWS	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/NEWS	2021-05-21 09:17:01.000000000 +0200
@@ -1,3 +1,16 @@
+ionit 0.3.7 (2021-05-21)
+
+* tests: Mark ionit_plugin as first party module
+
+ionit 0.3.7 (2021-05-20)
+
+* Check import definition order with isort
+* Fix code format for older black versions
+* Add test case for black code formatter
+* Fix YAMLLoadWarning with PyYAML 5.1+
+* Add support for ruamel.yaml
+* setup.py: Add PyYAML as dependency
+
 ionit 0.3.6 (2020-09-28)
 
 * Address issues found by pylint 2.6.0 (fixes Debian bug #971138)
diff -Nru ionit-0.3.6/setup.py ionit-0.3.8/setup.py
--- ionit-0.3.6/setup.py	2020-09-28 11:30:34.000000000 +0200
+++ ionit-0.3.8/setup.py	2021-05-21 09:17:01.000000000 +0200
@@ -32,22 +32,37 @@
 
 
 if __name__ == "__main__":
+    with open("README.md", "r", encoding="utf-8") as fh:
+        LONG_DESCRIPTION = fh.read()
+
     setup(
         name="ionit",
-        version="0.3.6",
+        version="0.3.8",
         description="Render configuration files from Jinja templates",
-        long_description=(
-            "ionit is a simple and small configuration templating tool. It collects a context and "
-            "renders Jinja templates in a given directory. The context can be either static JSON "
-            "or YAML files or dynamic Python files. Python files can also define functions passed "
-            "through to the rendering."
-        ),
+        long_description=LONG_DESCRIPTION,
+        long_description_content_type="text/markdown",
         author="Benjamin Drung",
-        author_email="benjamin.drung@cloud.ionos.com",
+        author_email="benjamin.drung@ionos.com",
         url="https://github.com/bdrung/ionit";,
+        project_urls={"Bug Tracker": "https://github.com/bdrung/ionit/issues"},
         license="ISC",
-        install_requires=["jinja2"],
+        classifiers=[
+            "Development Status :: 5 - Production/Stable",
+            "Environment :: Console",
+            "License :: OSI Approved :: ISC License (ISCL)",
+            "Operating System :: POSIX",
+            "Programming Language :: Python :: 3",
+            "Programming Language :: Python :: 3 :: Only",
+            "Programming Language :: Python :: 3.4",
+            "Programming Language :: Python :: 3.5",
+            "Programming Language :: Python :: 3.6",
+            "Programming Language :: Python :: 3.7",
+            "Programming Language :: Python :: 3.8",
+            "Programming Language :: Python :: 3.9",
+        ],
+        install_requires=["jinja2", "PyYAML"],
         scripts=["ionit"],
         py_modules=["ionit_plugin"],
         data_files=[(systemd_unit_path(), ["ionit.service"])],
+        python_requires=">=3.4",
     )

Reply to: