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

Bug#989077: marked as done (unblock: ionit/0.3.8-1)



Your message dated Fri, 28 May 2021 21:32:16 +0000
with message-id <E1lmk5Y-0005MC-51@respighi.debian.org>
and subject line unblock ionit
has caused the Debian Bug report #989077,
regarding unblock: ionit/0.3.8-1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
989077: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=989077
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
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",
     )

--- End Message ---
--- Begin Message ---
Unblocked.

--- End Message ---

Reply to: