diff -pruN 1.3.9-1/PKG-INFO 1.4.0+dfsg-1/PKG-INFO
--- 1.3.9-1/PKG-INFO	2025-08-12 13:07:59.121064700 +0000
+++ 1.4.0+dfsg-1/PKG-INFO	2025-09-22 14:18:04.453243700 +0000
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: mkdocs-macros-plugin
-Version: 1.3.9
+Version: 1.4.0
 Summary: Unleash the power of MkDocs with macros and variables
 Author: Laurent Franceschetti
 License: MIT
@@ -23,7 +23,7 @@ Requires-Dist: packaging
 Requires-Dist: pathspec
 Requires-Dist: python-dateutil
 Requires-Dist: pyyaml
-Requires-Dist: super-collections
+Requires-Dist: super-collections>=0.5.7
 Requires-Dist: termcolor
 Provides-Extra: test
 Requires-Dist: mkdocs-include-markdown-plugin; extra == "test"
@@ -31,6 +31,8 @@ Requires-Dist: mkdocs-macros-test; extra
 Requires-Dist: mkdocs-material>=6.2; extra == "test"
 Requires-Dist: mkdocs-test; extra == "test"
 Requires-Dist: mkdocs-d2-plugin; extra == "test"
+Provides-Extra: doc
+Requires-Dist: mkdocs-mermaid2-plugin; extra == "doc"
 Dynamic: license-file
 
 <div align="center">
diff -pruN 1.3.9-1/debian/changelog 1.4.0+dfsg-1/debian/changelog
--- 1.3.9-1/debian/changelog	2025-08-21 10:57:03.000000000 +0000
+++ 1.4.0+dfsg-1/debian/changelog	2025-10-01 11:06:34.000000000 +0000
@@ -1,3 +1,11 @@
+mkdocs-macros-plugin (1.4.0+dfsg-1) unstable; urgency=medium
+
+  * New upstream release.
+    - Re-add accidentally dropped +dfsg suffix.
+  * Drop redundant Rules-Requires-Root: no.
+
+ -- Stefano Rivera <stefanor@debian.org>  Wed, 01 Oct 2025 13:06:34 +0200
+
 mkdocs-macros-plugin (1.3.9-1) unstable; urgency=medium
 
   * New upstream release.
diff -pruN 1.3.9-1/debian/control 1.4.0+dfsg-1/debian/control
--- 1.3.9-1/debian/control	2025-08-21 10:57:03.000000000 +0000
+++ 1.4.0+dfsg-1/debian/control	2025-10-01 11:06:34.000000000 +0000
@@ -23,7 +23,6 @@ Standards-Version: 4.7.2
 Homepage: https://github.com/fralau/mkdocs_macros_plugin
 Vcs-Git: https://salsa.debian.org/python-team/packages/mkdocs-macros-plugin.git
 Vcs-Browser: https://salsa.debian.org/python-team/packages/mkdocs-macros-plugin
-Rules-Requires-Root: no
 
 Package: mkdocs-macros-plugin
 Architecture: all
diff -pruN 1.3.9-1/mkdocs_macros/plugin.py 1.4.0+dfsg-1/mkdocs_macros/plugin.py
--- 1.3.9-1/mkdocs_macros/plugin.py	2025-08-11 15:30:01.000000000 +0000
+++ 1.4.0+dfsg-1/mkdocs_macros/plugin.py	2025-09-22 14:17:56.000000000 +0000
@@ -17,7 +17,8 @@ import yaml
 from jinja2 import (
     Environment, FileSystemLoader, Undefined, DebugUndefined, StrictUndefined,
 )
-from super_collections import SuperDict
+from super_collections import SuperDict, yaml_support
+yaml_support()
 
 from mkdocs.config import config_options
 from mkdocs.config.config_options import Type as PluginType
@@ -27,9 +28,9 @@ from mkdocs.structure.pages import Page
 from mkdocs_macros.errors import format_error
 from mkdocs_macros.context import define_env
 from mkdocs_macros.util import (
-    install_package, parse_package, trace, debug,
+    is_on_pypi, parse_package, trace, debug,
     update, import_local_module, format_chatter, LOG, get_log_level,
-    setup_directory, CustomEncoder,
+    setup_directory
     # SuperDict, 
 )
 
@@ -329,7 +330,7 @@ class MacrosPlugin(BasePlugin):
         Used to set the raw markdown of the current page.
         
         [Especially used in the `on_pre_page_macros()` and
-        `on_ost_page_macros()` hooks.]
+        `on_post_page_macros()` hooks.]
         """
         if not isinstance(value, str):
             raise ValueError("Value provided to attribute markdown "
@@ -566,18 +567,13 @@ class MacrosPlugin(BasePlugin):
             try:
                 module = importlib.import_module(module_name)
             except ModuleNotFoundError:
-                try:
-                    # if absent, install (from pypi)
-                    trace("Module '%s' not found, installing (source: '%s')" %
-                          (module_name, source_name))
-                    install_package(source_name)
-                    # install package raises NameError
-                    module = importlib.import_module(module_name)
-                except (NameError, ModuleNotFoundError):
-                    raise ModuleNotFoundError("Could not import installed "
-                                              "module '%s' (missing?)" %
-                                              module_name,
-                                              name=module_name)
+                if is_on_pypi(source_name, fail_silently=True):
+                    err_msg = (f"Counld not import pluglet '{source_name}'. "
+                                f"Please install it from Pypi:\n\n    pip install {source_name}")
+                    raise ModuleNotFoundError(err_msg, name=module_name)
+                else:
+                    raise ModuleNotFoundError(f"Could not import "
+                        "module '{module_name}' (missing?)")
             self._load_module(module, module_name)
         # local module (file or dir)
         local_module_name = self.config['module_name']
@@ -876,21 +872,20 @@ class MacrosPlugin(BasePlugin):
 
     def on_pre_build(self, *, config):
         """
-        Provide information on the variables.
-        It is put here, in case some plugin hooks into the config,
-        after the execution of the `on_config()` of this plugin.
+        Provide information on the variables, so that mkdocs-test
+        can capture the trace (for testing)
+        It is put here, in case some plugin hooks into the config
+        to add some variables, macros or filters, after the execution
+        of the `on_config()` of this plugin.
         """
         trace("Config variables:", list(self.variables.keys()))
-        debug("Config variables:\n", payload=json.dumps(self.variables, 
-                                                    cls=CustomEncoder))
+        debug("Config variables:", payload=SuperDict(self.variables).to_json())
         if self.macros:
             trace("Config macros:", list(self.macros.keys()))
-            debug("Config macros:", payload=json.dumps(self.macros,
-                                                    cls=CustomEncoder))
+            debug("Config macros:", payload=SuperDict(self.macros).to_json())
         if self.filters:
             trace("Config filters:", list(self.filters.keys()))
-            debug("Config filters:", payload=json.dumps(self.filters,
-                                                    cls=CustomEncoder))
+            debug("Config filters:", payload=SuperDict(self.filters).to_json())
 
 
     def on_nav(self, nav, config, files):
diff -pruN 1.3.9-1/mkdocs_macros/util.py 1.4.0+dfsg-1/mkdocs_macros/util.py
--- 1.3.9-1/mkdocs_macros/util.py	2024-10-18 19:54:29.000000000 +0000
+++ 1.4.0+dfsg-1/mkdocs_macros/util.py	2025-09-22 14:17:56.000000000 +0000
@@ -11,6 +11,7 @@ from typing import Literal
 from packaging.version import Version
 import json
 import inspect
+import requests
 from datetime import datetime
 from typing import Any
 
@@ -116,32 +117,7 @@ def format_chatter(*args, prefix:str, co
 
 
 
-from collections import UserDict
 
-class CustomEncoder(json.JSONEncoder):
-    """
-    Custom encoder for JSON serialization.
-    Used for debugging purposes.
-    """
-    def default(self, obj: Any) -> Any:
-        if isinstance(obj, datetime):
-            return obj.isoformat()
-        if isinstance(obj, UserDict):
-            # for objects used by MkDocs (config, plugin, etc.s)
-            return dict(obj)
-
-        elif inspect.isfunction(obj):
-            return f"Function: %s %s" % (inspect.signature(obj),
-                                        obj.__doc__)
-        try:
-            return super().default(obj)
-        except TypeError:
-            debug(f"json: cannot encode {obj.__class__}")
-            try:
-                return str(obj)
-            except Exception:
-                # in case something happens along the line
-                return f"!Non printable object: {obj.__class__}"
 
 
 
@@ -155,8 +131,9 @@ def parse_package(package:str):
     """
     Parse a package name
 
-    if it is in the forme 'foo:bar' then 'foo' is the source, 
-    and 'bar' is the (import) package name
+    if it is in the forme 'foo:bar' then it is a pluglet: 
+    - 'foo' is the source, 
+    - 'bar' is the (import) package name.
 
     Returns the source name (for pip install) and the package name (for import)
     """
@@ -167,14 +144,30 @@ def parse_package(package:str):
         source_name, package_name = l[:2]
     return source_name, package_name
 
-def install_package(package:str):
+
+
+def is_on_pypi(source_name: str, fail_silently: bool = False) -> bool:
     """
-    Install a package from pip
+    Check if a package is available on PyPI.
+
+    Parameters:
+    - source_name: the name of the package to check
+    - fail_silently: if True, return False on network error; if False, raise the error
+
+    Returns:
+    - True if the package exists on PyPI
+    - False if not found.
+      (will raise a RunTime error on network error, 
+      unless fail_silently=True: will report False)
     """
+    url = f"https://pypi.org/pypi/{source_name}/json"
     try:
-        subprocess.check_call(["pip3", "install", package])
-    except subprocess.CalledProcessError:
-        raise NameError("Could not install package '%s'" % package)
+        response = requests.get(url, timeout=3)
+        return response.status_code == 200
+    except requests.exceptions.RequestException as e:
+        if fail_silently:
+            return False
+        raise RuntimeError(f"Unable to reach PyPI to check for '{source_name}': {e}")
 
 
 def import_local_module(project_dir, module_name):
diff -pruN 1.3.9-1/mkdocs_macros_plugin.egg-info/PKG-INFO 1.4.0+dfsg-1/mkdocs_macros_plugin.egg-info/PKG-INFO
--- 1.3.9-1/mkdocs_macros_plugin.egg-info/PKG-INFO	2025-08-12 13:07:59.000000000 +0000
+++ 1.4.0+dfsg-1/mkdocs_macros_plugin.egg-info/PKG-INFO	2025-09-22 14:18:04.000000000 +0000
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: mkdocs-macros-plugin
-Version: 1.3.9
+Version: 1.4.0
 Summary: Unleash the power of MkDocs with macros and variables
 Author: Laurent Franceschetti
 License: MIT
@@ -23,7 +23,7 @@ Requires-Dist: packaging
 Requires-Dist: pathspec
 Requires-Dist: python-dateutil
 Requires-Dist: pyyaml
-Requires-Dist: super-collections
+Requires-Dist: super-collections>=0.5.7
 Requires-Dist: termcolor
 Provides-Extra: test
 Requires-Dist: mkdocs-include-markdown-plugin; extra == "test"
@@ -31,6 +31,8 @@ Requires-Dist: mkdocs-macros-test; extra
 Requires-Dist: mkdocs-material>=6.2; extra == "test"
 Requires-Dist: mkdocs-test; extra == "test"
 Requires-Dist: mkdocs-d2-plugin; extra == "test"
+Provides-Extra: doc
+Requires-Dist: mkdocs-mermaid2-plugin; extra == "doc"
 Dynamic: license-file
 
 <div align="center">
diff -pruN 1.3.9-1/mkdocs_macros_plugin.egg-info/SOURCES.txt 1.4.0+dfsg-1/mkdocs_macros_plugin.egg-info/SOURCES.txt
--- 1.3.9-1/mkdocs_macros_plugin.egg-info/SOURCES.txt	2025-08-12 13:07:59.000000000 +0000
+++ 1.4.0+dfsg-1/mkdocs_macros_plugin.egg-info/SOURCES.txt	2025-09-22 14:18:04.000000000 +0000
@@ -19,6 +19,9 @@ mkdocs_macros_plugin.egg-info/top_level.
 test/__init__.py
 test/fixture.py
 test/main_sample.py
+test/test_various.py
+test/missing_macros/__init__.py
+test/missing_macros/test_site.py
 test/module/__init__.py
 test/module/main.py
 test/module/test_site.py
diff -pruN 1.3.9-1/mkdocs_macros_plugin.egg-info/requires.txt 1.4.0+dfsg-1/mkdocs_macros_plugin.egg-info/requires.txt
--- 1.3.9-1/mkdocs_macros_plugin.egg-info/requires.txt	2025-08-12 13:07:59.000000000 +0000
+++ 1.4.0+dfsg-1/mkdocs_macros_plugin.egg-info/requires.txt	2025-09-22 14:18:04.000000000 +0000
@@ -5,9 +5,12 @@ packaging
 pathspec
 python-dateutil
 pyyaml
-super-collections
+super-collections>=0.5.7
 termcolor
 
+[doc]
+mkdocs-mermaid2-plugin
+
 [test]
 mkdocs-include-markdown-plugin
 mkdocs-macros-test
diff -pruN 1.3.9-1/pyproject.toml 1.4.0+dfsg-1/pyproject.toml
--- 1.3.9-1/pyproject.toml	2025-08-11 15:30:01.000000000 +0000
+++ 1.4.0+dfsg-1/pyproject.toml	2025-09-22 14:17:56.000000000 +0000
@@ -3,21 +3,14 @@ name = "mkdocs-macros-plugin"
 
 # This version number is the REFERENCE for the rest of the project,
 # particularly for update_pypi.sh
-version = "1.3.9"
+version = "1.4.0"
 
 description = "Unleash the power of MkDocs with macros and variables"
 readme = "README.md"
 license = { text = "MIT" }
 requires-python = ">=3.8"
-authors = [
-    { name = "Laurent Franceschetti"},
-]
-keywords = [
-    "macros",
-    "markdown",
-    "mkdocs",
-    "python",
-]
+authors = [{ name = "Laurent Franceschetti" }]
+keywords = ["macros", "markdown", "mkdocs", "python"]
 classifiers = [
     "Development Status :: 5 - Production/Stable",
     "Intended Audience :: Developers",
@@ -35,7 +28,7 @@ dependencies = [
     "pathspec",
     "python-dateutil",
     "pyyaml",
-    "super-collections",
+    "super-collections >= 0.5.7",
     "termcolor",
 ]
 
@@ -48,12 +41,14 @@ test = [
     "mkdocs-macros-test",
     "mkdocs-material>=6.2",
     "mkdocs-test",
-    "mkdocs-d2-plugin"
+    "mkdocs-d2-plugin",
 ]
 
+# for the MkDocs documentation (webdoc/)
+doc = ["mkdocs-mermaid2-plugin"]
+
 [project.entry-points."mkdocs.plugins"]
 macros = "mkdocs_macros.plugin:MacrosPlugin"
 
 [project.urls]
 Homepage = "https://github.com/fralau/mkdocs_macros_plugin"
-
diff -pruN 1.3.9-1/test/fixture.py 1.4.0+dfsg-1/test/fixture.py
--- 1.3.9-1/test/fixture.py	2024-10-28 18:45:22.000000000 +0000
+++ 1.4.0+dfsg-1/test/fixture.py	2025-09-22 14:17:56.000000000 +0000
@@ -56,50 +56,59 @@ class MacrosDocProject(DocProject):
     # ------------------------------------
     @property
     def variables(self):
-         "Return the variables"
-         try:
-              return self._variables
-         except AttributeError:
-            entry = self.find_entry("config variables",
-                                          source='macros',
-                                          severity='debug')
-            if entry and entry.payload:
-                self._variables = SuperDict(json.loads(entry.payload))
-            else:
-                 print(entry)
-                 raise ValueError("Cannot find variables")
-            return self._variables
+          "Return the variables"
+          try:
+               return self._variables
+          except AttributeError:
+               print("ENTRIES:", self.find_entries("config variables",
+                                             source='',
+                                             severity='debug'))
+               print("ENTRIES:", self.find_entries("config variables",
+                                             source='macros'))
+               entry = self.find_entry("config variables",
+                                             source='macros',
+                                             severity='debug')
+               if entry and entry.payload:
+                    payload = json.loads(entry.payload)
+                    self._variables = SuperDict(payload)
+               else:
+                    # print(entry)
+                    # raise ValueError("Cannot find variables")
+                    self._variables = {}
+               return self._variables
 
 
     @property
     def macros(self):
-         "Return the macros"
-         try:
+          "Return the macros"
+          try:
               return self._macros
-         except AttributeError:
-            entry = self.find_entry("config macros",
+          except AttributeError:
+               entry = self.find_entry("config macros",
                                           source='macros',
                                           severity='debug')
-            if entry and entry.payload:
-                self._macros = SuperDict(json.loads(entry.payload))
-            else:
-                 print(entry)
-                 raise ValueError("Cannot find macros")
-            return self._macros
+               if entry and entry.payload:
+                    self._macros = SuperDict(json.loads(entry.payload))
+               else:
+                    # print(entry)
+                    # raise ValueError("Cannot find macros")
+                    self._macros = {}
+               return self._macros
          
 
     @property
     def filters(self):
-         "Return the filters"
-         try:
+          "Return the filters"
+          try:
               return self._filters
-         except AttributeError:
-            entry = self.find_entry("config filters",
-                                          source='macros',
-                                          severity='debug')
-            if entry and entry.payload:
-                self._filters = SuperDict(json.loads(entry.payload))
-            else:
-                 print(entry)
-                 raise ValueError("Cannot find filters")
-            return self._filters
+          except AttributeError:
+               entry = self.find_entry("config filters",
+                                             source='macros',
+                                             severity='debug')
+               if entry and entry.payload:
+                    self._filters = SuperDict(json.loads(entry.payload))
+               else:
+                    #   print(entry)
+                    #   raise ValueError("Cannot find filters")
+                    self._filters = {}
+               return self._filters
diff -pruN 1.3.9-1/test/missing_macros/__init__.py 1.4.0+dfsg-1/test/missing_macros/__init__.py
--- 1.3.9-1/test/missing_macros/__init__.py	1970-01-01 00:00:00.000000000 +0000
+++ 1.4.0+dfsg-1/test/missing_macros/__init__.py	2025-09-22 14:17:56.000000000 +0000
@@ -0,0 +1,4 @@
+"""
+This __init__.py file is indispensable for pytest to
+recognize its packages.
+"""
\ No newline at end of file
diff -pruN 1.3.9-1/test/missing_macros/test_site.py 1.4.0+dfsg-1/test/missing_macros/test_site.py
--- 1.3.9-1/test/missing_macros/test_site.py	1970-01-01 00:00:00.000000000 +0000
+++ 1.4.0+dfsg-1/test/missing_macros/test_site.py	2025-09-22 14:17:56.000000000 +0000
@@ -0,0 +1,29 @@
+"""
+Testing the project
+
+(C) Laurent Franceschetti 2024
+"""
+
+
+import pytest
+
+from mkdocs_test import DocProject
+
+
+
+
+
+def test_build():
+    project = DocProject(".")
+    # did not fail
+
+    print("building website...")
+    build_result = project.build(strict=True)
+    result = build_result.stderr
+    print("Result:", result)
+    # fails, declaring that the pluglet exists and must be installed.
+    assert build_result.returncode != 0 # failure 
+    assert "pluglet" in result
+    assert "pip install" in result
+
+    
\ No newline at end of file
diff -pruN 1.3.9-1/test/register_macros/test_doc.py 1.4.0+dfsg-1/test/register_macros/test_doc.py
--- 1.3.9-1/test/register_macros/test_doc.py	2024-10-28 18:38:14.000000000 +0000
+++ 1.4.0+dfsg-1/test/register_macros/test_doc.py	2025-09-22 14:17:56.000000000 +0000
@@ -12,20 +12,32 @@ from test.fixture import MacrosDocProjec
 
 from .hooks import MY_VARIABLES, MY_FUNCTIONS, MY_FILTERS, bar, scramble
 
+project = None
 
-def test_pages():
+
+def test_build_project():
+    global project
     project = MacrosDocProject(".")
     build_result = project.build(strict=True)
     # did not fail
     return_code = project.build_result.returncode
     assert not return_code, f"Build returned with {return_code} {build_result.args})" 
+    print("Build successful")
+    
+    print("Variables?")
+    # entry = project.find_entries("config variables", severity="debug")
+    # print(entry)
 
+def test_variables():
     # check the presence of variables in the environment
     print("Variables:", list(project.variables.keys()))
     for variable in MY_VARIABLES:
+        print(f"{variable}...")
         assert variable in project.variables
-        print(f"{variable}: {project.variables[variable]}")
+        print(f"...{project.variables[variable]}")
 
+def test_macros_and_filters():
+    print("Macros:", project.macros)
     print("Macros:", list(project.macros.keys()))
     for macro in MY_FUNCTIONS:
         assert macro in project.macros
@@ -36,6 +48,8 @@ def test_pages():
         assert filter in project.filters
         print(f"{filter}: {project.filters[filter]}") 
 
+
+def test_pages():
     # ----------------
     # First page
     # ----------------
diff -pruN 1.3.9-1/test/test_various.py 1.4.0+dfsg-1/test/test_various.py
--- 1.3.9-1/test/test_various.py	1970-01-01 00:00:00.000000000 +0000
+++ 1.4.0+dfsg-1/test/test_various.py	2025-09-22 14:17:56.000000000 +0000
@@ -0,0 +1,32 @@
+"""
+Various tests
+"""
+
+import pytest
+
+# ----------------------
+# is_on_pypi
+# ----------------------
+
+from mkdocs_macros.util import is_on_pypi  # Replace with actual import path
+
+def test_known_package_exists():
+    # requires connection
+    assert is_on_pypi("requests", fail_silently=True) is True
+
+def test_nonexistent_package():
+    assert is_on_pypi("this_package_does_not_exist_123456", fail_silently=True) is False
+
+def test_network_failure(monkeypatch):
+    # Simulate network failure by patching requests.get to raise a RequestException
+    import requests
+
+    def mock_get(*args, **kwargs):
+        raise requests.exceptions.ConnectionError("Simulated network failure")
+
+    monkeypatch.setattr(requests, "get", mock_get)
+
+    assert is_on_pypi("requests", fail_silently=True) is False
+
+    with pytest.raises(RuntimeError):
+        is_on_pypi("requests", fail_silently=False)
