Repository: axem-solutions/dem

Issue:
[BUG] DEM loads irrelevant registries/repositories from Docker Hub
## Description
Something has changed in the Docker Hub API. When DEM tries to load the repositories from the saved Docker Hub registries many other non-relevant repositories are loaded. This affects all commands that load the repositories. 

The communication with Docker Hub must be fixed, so the proper repositories are loaded.

## Example faulty behavior

Prerequisite: at least one Docker Hub registry should be added to DEM, for example axemsolutions.
![image](https://github.com/user-attachments/assets/9f71a284-f4e0-4a71-94f7-5132c847c663)

1. `dem create test`
In the status row, it is already visible that unexpected repositories are loading.
2. On the Dev Env Settings Window, the available tool list contains irrelevant items from unknown repositories.

## Expected behavior

Prerequisite: at least one Docker Hub registry should be added to DEM, for example axemsolutions.
![image](https://github.com/user-attachments/assets/9f71a284-f4e0-4a71-94f7-5132c847c663)

1. `dem create test`
The DEM should load the repositories from the added registries.
2. On the Dev Env Settings Window only the added registries' repositories should be visible.

Jira: https://axem.atlassian.net/browse/DEM-284

Discussion:

Solution patch:
diff --git a/dem/core/container_engine.py b/dem/core/container_engine.py
index c52cf9b..143a3a9 100644
--- a/dem/core/container_engine.py
+++ b/dem/core/container_engine.py
@@ -115,17 +115,4 @@ class ContainerEngine(Core):
         except docker.errors.ImageNotFound:
             self.user_output.msg(f"[yellow]The {image} doesn't exist. Unable to remove it.[/]\n")
         except docker.errors.APIError:
-            raise ContainerEngineError(f"The {image} is used by a container. Unable to remove it.\n")
-
-    def search(self, registry: str) -> list[str]:
-        """ Search repository in the axemsolutions registry.
-        
-            Args:
-                registry -- registry to search
-        """
-        local_registryimagelist = []
-
-        for repositories in self._docker_client.images.search(registry):
-            local_registryimagelist.append(repositories['name'])
-
-        return local_registryimagelist
\ No newline at end of file
+            raise ContainerEngineError(f"The {image} is used by a container. Unable to remove it.\n")
\ No newline at end of file
diff --git a/dem/core/platform.py b/dem/core/platform.py
index 7110506..c29fc87 100644
--- a/dem/core/platform.py
+++ b/dem/core/platform.py
@@ -97,7 +97,7 @@ class Platform(Core):
             The Registries() gets instantiated only at the first access.
         """
         if self._registries is None:
-            self._registries = Registries(self.container_engine)
+            self._registries = Registries()
 
         return self._registries
 
diff --git a/dem/core/registry.py b/dem/core/registry.py
index f925421..cca9665 100644
--- a/dem/core/registry.py
+++ b/dem/core/registry.py
@@ -1,68 +1,117 @@
-"""Direct access to the registry over HTTP. or using the container engine."""
+""" Communicate with the registries. """
 # dem/core/registry.py
 
 from dem.core.core import Core
-from dem.core.container_engine import ContainerEngine
 from dem.core.exceptions import RegistryError
+
 import requests
 from typing import Generator
 from abc import ABC, abstractmethod
 
 class Registry(Core, ABC):
     """ Abstract base class for a registry."""
-    def __init__(self, container_engine: ContainerEngine, registry_config: dict) -> None:
+    def __init__(self, registry_config: dict) -> None:
         """ Init the class.
         
             Args:
-                container_engine -- the container engine
                 registry_config -- container the name of the registry and its URL
         """
-        self._container_engine = container_engine
-        self._registry_config = registry_config
+        try:
+            self._url = registry_config["url"]
+            self._name = registry_config["name"]
+        except KeyError:
+            raise RegistryError("Invalid registry configuration.")
+        self._namespace = registry_config.get("namespace", "")
         self._repos = []
 
+    @property
+    @abstractmethod
+    def _tag_endpoint_response_key(self) -> str:
+        """ Used to obtain the tags from the endpoint response."""
+
+    @property
+    @abstractmethod
+    def _repo_endpoint_response_key(self) -> str:
+        """ Used to obtain the repositories from the endpoint response."""
+
     @abstractmethod
     def _append_repo_with_tag(self, endpoint_response: dict, repo: str) -> None:
         """ Get the tags from the endpoint response. Save the tags alongside with the actual repo
             in the private repo list.
+
+            Args:
+                endpoint_response -- the response from the endpoint
+                repo -- append the tags of this repoistory
         """
 
     @abstractmethod
-    def _get_tag_endpoint_url(self, repo_name: str) -> str:
-        """ Get the registry specific endpoint to obtain the tags."""
+    def _get_repo_endpoint_url(self) -> str:
+        """ The registry type specific endpoint to obtain the repositories.
+        
+            Returns with the endpoint url.
+        """
 
     @abstractmethod
-    def _list_repos_in_registry(self) -> Generator:
-        """ Generator function for listing the repos. """
+    def _get_tag_endpoint_url(self, repo_name: str) -> str:
+        """ The registry type specific endpoint to obtain the tags.
+        
+            Args:
+                repo_name -- we would like to get the tags for this repository
+                
+            Returns with the endpoint url.
+        """
 
-    def _list_tags(self, repo: str) -> None:
+    def _list_tags(self, repo_name: str) -> None:
         """ Get the tags from the respective endpoint and call the registry specific function to 
             populate the private repo list.
 
             Args:
-                repo -- get the tags of this repository
+                repo_name -- get the tags of this repository
         """
         try:
-            response = requests.get(self._get_tag_endpoint_url(repo), 
+            response = requests.get(self._get_tag_endpoint_url(repo_name), 
                                               timeout=self.config_file.http_request_timeout_s)
         except Exception as e:
             self.user_output.error(str(e))
         else:
             if response.status_code == requests.codes.ok:
-                self._append_repo_with_tag(response.json(), repo)
+                self._append_repo_with_tag(response.json(), repo_name)
                 return
             else:
                 self.user_output.error("Error in communication with the registry. Failed to retrieve tags. Response status code: " + str(response.status_code))
 
-        self.user_output.msg("Skipping repository: " + repo)
+        self.user_output.msg("Skipping repository: " + repo_name)
+    
+    def _list_repos(self) -> Generator:
+        """ Generator function for listing the repos. """
+        try:
+            response = requests.get(self._get_repo_endpoint_url(), 
+                                    timeout=self.config_file.http_request_timeout_s)
+        except Exception as e:
+            self.user_output.error(str(e))
+        else:
+            if response.status_code == requests.codes.ok:
+                try:
+                    for repo in response.json()[self._repo_endpoint_response_key]:
+                        yield "Loading image data from: " + repo["name"]
+                        self._list_tags(repo["name"])
+                    return
+                except requests.exceptions.JSONDecodeError as e:
+                    self.user_output.error(f"Invalid JSON format in response from the registry: {str(e)}")
+                except Exception as e:
+                    self.user_output.error(str(e))
+            else:
+                self.user_output.error("Error in communication with the registry. Failed to retrieve the repositories. Response status code: " + str(response.status_code))
+
+        self.user_output.msg(f"Skipping [bold]{self._name}[/bold].")
     
     @property
     def repos(self) -> list[str]:
-        """ Getter function for the repos in the registry.
+        """ Repos in the registry filtered by namespace if applicable.
         
             Returns with list of the repos.
         """
-        self.user_output.status_generator(self._list_repos_in_registry())
+        self.user_output.status_generator(self._list_repos())
         return self._repos
 
 class DockerHub(Registry):
@@ -72,9 +121,23 @@ class DockerHub(Registry):
             _docker_hub_domain -- the Docker Hub domain (used to determine if the config is for a 
                                   Docker Hub registry)
             _tag_endpoint_response_key -- used to obtain the tags from the endpoint response
+            _repo_endpoint_response_key -- used to obtain the repositories from the endpoint response
     """
     _docker_hub_domain = "registry.hub.docker.com"
     _tag_endpoint_response_key = "results"
+    _repo_endpoint_response_key = "results"
+
+    def __init__(self, registry_config: dict) -> None:
+        """ Init the class.
+            
+            Args:
+                registry_config -- contains the name of the registry, its URL and optionally the
+                                   namespace
+        """
+        super().__init__(registry_config)
+
+        if not self._namespace:
+            raise RegistryError("Invalid registry configuration. For Docker Hub the namesapce must be set.")
 
     def _append_repo_with_tag(self, endpoint_response: dict, repo: str) -> None:
         """ Get the tags from the endpoint response. Save the tags alongside with the actual repo
@@ -87,27 +150,32 @@ class DockerHub(Registry):
         for result in endpoint_response[self._tag_endpoint_response_key]:
             self._repos.append(repo + ":" + result["name"])
 
-    def _get_tag_endpoint_url(self, repo: str) -> str:
+    def _get_repo_endpoint_url(self) -> str:
+        """ Get the Docker Hub specific endpoint url to obtain the repositories.
+            
+            Returns with the endpoint url.
+        """
+        return f"{self._url}/v2/namespaces/{self._namespace}/repositories"
+
+    def _get_tag_endpoint_url(self, repo_name: str) -> str:
         """ Get the Docker Hub specific endpoint url to obtain the tags.
             
             Args:
-                repo -- we would like to get the tags for this repository
-        """
-        return self._registry_config["url"] + "/v2/repositories/" + repo + "/tags/"
+                repo_name -- we would like to get the tags for this repository
 
-    def _list_repos_in_registry(self) -> Generator:
-        """ Generator function for listing the repos. """
-        for repo in self._container_engine.search(self._registry_config["name"]):
-            yield "Loading image data from: " + repo
-            self._list_tags(repo)
+            Returns with the endpoint url.
+        """
+        return f"{self._url}/v2/namespaces/{self._namespace}/repositories/{repo_name}/tags"
 
 class DockerRegistry(Registry):
     """ Docker Registry
     
         Class variables:
             _tag_endpoint_response_key -- used to obtain the tags from the endpoint response
+            _repo_endpoint_response_key -- used to obtain the repositories from the endpoint response
     """
     _tag_endpoint_response_key = "tags"
+    _repo_endpoint_response_key = "repositories"
 
     def _append_repo_with_tag(self, endpoint_response: dict, repo: str) -> None:
         """ Get the tags from the endpoint response. Save the tags alongside with the actual repo
@@ -120,56 +188,27 @@ class DockerRegistry(Registry):
         for result in endpoint_response[self._tag_endpoint_response_key]:
             self._repos.append(repo + ":" + result)
 
-    def _get_tag_endpoint_url(self, repo: str) -> str:
-        """ Get the Docker Registry specific endpoint url to obtain the tags.
+    def _get_repo_endpoint_url(self) -> str:
+        """ Get the Docker Registry specific endpoint url to obtain the repositories.
             
-            Args:
-                repo -- we would like to get the tags for this repository
+            Returns with the endpoint url.
         """
-        return self._registry_config["url"] + "/v2/" + repo.split("/")[1] + "/tags/list"
+        return f"{self._url}/v2/_catalog"
 
-    def _search(self) -> list[str]:
-        """ Search the registry for the repositories
-        
-            Return with the repo list or an empty list if something bad happened.
+    def _get_tag_endpoint_url(self, repo_name: str) -> str:
+        """ Get the Docker Registry specific endpoint url to obtain the tags.
+            
+            Args:
+                repo_name -- we would like to get the tags for this repository
+                
+            Returns with the endpoint url.
         """
-        repo_endpoint = self._registry_config["url"] + "/v2/_catalog"
-
-        try:
-            response = requests.get(repo_endpoint, timeout=self.config_file.http_request_timeout_s)
-        except Exception as e:
-            self.user_output.error(str(e))
-        else:
-            if response.status_code == requests.codes.ok:
-                try:
-                    return response.json()["repositories"]
-                except requests.exceptions.JSONDecodeError as e:
-                    self.user_output.error("Invalid JSON format in response. " + str(e))
-                except Exception as e:
-                    self.user_output.error(str(e))
-            else:
-                self.user_output.error("Error in communication with the registry. Failed to retrieve the repositories. Response status code: " + str(response.status_code))
-
-        self.user_output.msg("Skipping registry: " + self._registry_config["name"])
-        return []
-
-    def _list_repos_in_registry(self) -> Generator:
-        """ Generator function for listing the repos. """
-        for repo_name in self._search():
-            repo = self._registry_config["name"] + '/' + repo_name
-            yield "Loading image data from: " + repo
-            self._list_tags(repo)
+        return f"{self._url}/v2/{repo_name.split('/')[1]}/tags/list"
 
 class Registries(Core):
     """ Contains all configured registiries."""
-    def __init__(self, container_engine: ContainerEngine) -> None:
-        """ Init the class by creating the registry instances.
-            
-            Args:
-                container_engine -- the container engine
-                config_file -- config file that contains the registry parameters
-        """
-        self._container_engine = container_engine
+    def __init__(self) -> None:
+        """ Init the class by creating the registry instances."""
         self.registries: list[Registry] = []
         for registry_config in self.config_file.registries:
             self._add_registry_instance(registry_config)
@@ -182,9 +221,9 @@ class Registries(Core):
                 registry_config -- registry config
             """
         if DockerHub._docker_hub_domain in registry_config["url"]:
-            self.registries.append(DockerHub(self._container_engine, registry_config))
+            self.registries.append(DockerHub(registry_config))
         else:
-            self.registries.append(DockerRegistry(self._container_engine, registry_config))
+            self.registries.append(DockerRegistry(registry_config))
 
     def list_repos(self, reg_selection: list[str]) -> list[str]:
         """ List the available repositories.
@@ -197,13 +236,8 @@ class Registries(Core):
         repo_list: list[str] = []
 
         for registry in self.registries:
-            if not reg_selection or registry._registry_config["name"] in reg_selection:
-                try:
-                    repo_list.extend(registry.repos)
-                except Exception as e:
-                    self.user_output.error(str(e))
-                    self.user_output.error("[red]Error: The " + registry._registry_config["name"] + \
-                                           " registry is not available.[/]")
+            if not reg_selection or registry._name in reg_selection:
+                repo_list.extend(registry.repos)
 
         return repo_list
 
@@ -211,7 +245,7 @@ class Registries(Core):
         """ Add a new registry.
         
             Args:
-                registry -- the registry to add
+                registry_config -- the registry to add
         """
         self._add_registry_instance(registry_config)
 
@@ -229,10 +263,10 @@ class Registries(Core):
         """ Delete the registry.
         
             Args:
-                registry -- the registry to delete
+                registry_config -- the registry to delete
         """
         for registry in self.registries.copy():
-            if registry._registry_config == registry_config:
+            if registry._name == registry_config["name"]:
                 self.registries.remove(registry)
 
         self.config_file.registries.remove(registry_config)


Test patch:
diff --git a/tests/core/test_container_engine.py b/tests/core/test_container_engine.py
index 79c1853..b0bfbc6 100644
--- a/tests/core/test_container_engine.py
+++ b/tests/core/test_container_engine.py
@@ -292,31 +292,4 @@ def test_remove_APIError(mock_from_env: MagicMock) -> None:
         # Check expectations
         assert str(exported_exception_info) == f"The {test_image_to_remove} is used by a container. Unable to remove it.[/]\n"
 
-        mock_docker_client.images.remove.assert_called_once_with(test_image_to_remove)
-
-@patch("docker.from_env")
-def test_search(mock_from_env):
-    # Test setup
-    mock_docker_client = MagicMock()
-    mock_from_env.return_value = mock_docker_client
-    test_registry = "test_registry"
-    test_repositories = [
-        {
-            "name": "repo1"
-        },
-        {
-            "name": "repo2"
-        },
-    ]
-    mock_docker_client.images.search.return_value = test_repositories
-
-    test_container_engine = container_engine.ContainerEngine()
-
-    # Run unit under test
-    actual_registry_image_list = test_container_engine.search(test_registry)
-
-    # Check expectations
-    mock_docker_client.images.search.assert_called_once_with(test_registry)
-
-    expected_registry_image_list = ["repo1", "repo2"]
-    assert actual_registry_image_list == expected_registry_image_list
\ No newline at end of file
+        mock_docker_client.images.remove.assert_called_once_with(test_image_to_remove)
\ No newline at end of file
diff --git a/tests/core/test_platform.py b/tests/core/test_platform.py
index 1d2494d..0683503 100644
--- a/tests/core/test_platform.py
+++ b/tests/core/test_platform.py
@@ -144,9 +144,6 @@ def test_Platform_registries(mock___init__: MagicMock, mock_Registries: MagicMoc
     test_platform = platform.Platform()
     test_platform._registries = None
 
-    mock_container_engine = MagicMock()
-    test_platform._container_engine = mock_container_engine
-
     mock_registries = MagicMock()
     mock_Registries.return_value = mock_registries
 
@@ -158,7 +155,7 @@ def test_Platform_registries(mock___init__: MagicMock, mock_Registries: MagicMoc
     assert test_platform._registries is mock_registries
 
     mock___init__.assert_called_once()
-    mock_Registries.assert_called_once_with(mock_container_engine)
+    mock_Registries.assert_called_once()
 
 @patch("dem.core.platform.DevEnvCatalogs")
 @patch.object(platform.Platform, "__init__")
diff --git a/tests/core/test_registry.py b/tests/core/test_registry.py
index 46ee5e1..bf2f278 100644
--- a/tests/core/test_registry.py
+++ b/tests/core/test_registry.py
@@ -6,32 +6,45 @@ import dem.core.registry as registry
 
 # Test framework
 import pytest
-from unittest.mock import patch, MagicMock, call, PropertyMock
+from unittest.mock import patch, MagicMock, call
 
 import requests
-from typing import Generator
 
 class HelperRegistry(registry.Registry):
     """ The registry.Registry is an abstract base class, so it is not possible to directly 
         instantiate. The HelperRegistry class only acts as a helper for testing.
     """
+    _tag_endpoint_response_key = "results"
+    _repo_endpoint_response_key = "repositories"
+
     def _append_repo_with_tag(self, endpoint_response: dict, repo: str) -> None:
         return super()._append_repo_with_tag(endpoint_response, repo)
+
+    def _get_repo_endpoint_url(self) -> str:
+        return super()._get_repo_endpoint_url()
     
     def _get_tag_endpoint_url(self, repo_name: str) -> str:
         return super()._get_tag_endpoint_url(repo_name)
-    
-    def _list_repos_in_registry(self) -> Generator:
-        return super()._list_repos_in_registry()
+
+def test_Registry___init___RegistryError() -> None:
+    # Test setup
+    test_registry_config = {}
+
+    # Run unit under test
+    with pytest.raises(registry.RegistryError):
+        HelperRegistry(test_registry_config)
 
 @patch.object(registry.Core, "config_file")
 @patch.object(registry.Registry, "_append_repo_with_tag")
 @patch.object(registry.Registry, "_get_tag_endpoint_url")
+@patch.object(registry.Registry, "__init__")
 @patch("dem.core.registry.requests.get")
-def test_Registry__list_tags(mock_requests_get: MagicMock, mock__get_tag_endpoint_url: MagicMock,
+def test_Registry__list_tags(mock_requests_get: MagicMock, mock___init__: MagicMock,
+                             mock__get_tag_endpoint_url: MagicMock,
                              mock__append_repo_with_tag: MagicMock, mock_config_file: MagicMock) -> None:
     # Test setup
-    mock_container_engine = MagicMock()
+    mock___init__.return_value = None
+
     test_registry_config = {}
 
     test_repo = "test_repo"
@@ -46,12 +59,13 @@ def test_Registry__list_tags(mock_requests_get: MagicMock, mock__get_tag_endpoin
     test_http_request_timeout_s = 10
     mock_config_file.http_request_timeout_s = test_http_request_timeout_s
 
-    test_registry = HelperRegistry(mock_container_engine, test_registry_config)
+    test_registry = HelperRegistry(test_registry_config)
 
     # Run unit under test
     test_registry._list_tags(test_repo)
 
     # Check expectations
+    mock___init__.assert_called_once()
     mock__get_tag_endpoint_url.assert_called_once_with(test_repo)
     mock_requests_get.assert_called_once_with(test_tag_endpoint_url, timeout=test_http_request_timeout_s)
     mock_response.json.assert_called_once()
@@ -60,12 +74,14 @@ def test_Registry__list_tags(mock_requests_get: MagicMock, mock__get_tag_endpoin
 @patch.object(registry.Core, "config_file")
 @patch.object(registry.Core, "user_output")
 @patch.object(registry.Registry, "_get_tag_endpoint_url")
+@patch.object(registry.Registry, "__init__")
 @patch("dem.core.registry.requests.get")
-def test_Registry__list_tags_MissingSchema(mock_requests_get: MagicMock, 
+def test_Registry__list_tags_MissingSchema(mock_requests_get: MagicMock, mock___init__: MagicMock,
                                            mock__get_tag_endpoint_url: MagicMock,
                                            mock_user_output: MagicMock, mock_config_file: MagicMock) -> None:
     # Test setup
-    mock_container_engine = MagicMock()
+    mock___init__.return_value = None
+
     test_registry_config = {}
 
     test_repo = "test_repo"
@@ -77,12 +93,13 @@ def test_Registry__list_tags_MissingSchema(mock_requests_get: MagicMock,
     test_http_request_timeout_s = 10
     mock_config_file.http_request_timeout_s = test_http_request_timeout_s
 
-    test_registry = HelperRegistry(mock_container_engine, test_registry_config)
+    test_registry = HelperRegistry(test_registry_config)
 
     # Run unit under test
     test_registry._list_tags(test_repo)
 
     # Check expectations
+    mock___init__.assert_called_once()
     mock__get_tag_endpoint_url.assert_called_once_with(test_repo)
     mock_requests_get.assert_called_once_with(test_tag_endpoint_url, timeout=test_http_request_timeout_s)
     mock_user_output.error.assert_called_once_with(test_exception_text)
@@ -91,13 +108,15 @@ def test_Registry__list_tags_MissingSchema(mock_requests_get: MagicMock,
 @patch.object(registry.Core, "config_file")
 @patch.object(registry.Core, "user_output")
 @patch.object(registry.Registry, "_get_tag_endpoint_url")
+@patch.object(registry.Registry, "__init__")
 @patch("dem.core.registry.requests.get")
-def test_Registry__list_tags_invalid_status(mock_requests_get: MagicMock, 
+def test_Registry__list_tags_invalid_status(mock_requests_get: MagicMock, mock___init__: MagicMock,
                                             mock__get_tag_endpoint_url: MagicMock,
                                             mock_user_output: MagicMock, 
                                             mock_config_file: MagicMock) -> None:
     # Test setup
-    mock_container_engine = MagicMock()
+    mock___init__.return_value = None
+
     test_registry_config = {}
 
     test_repo = "test_repo"
@@ -110,354 +129,375 @@ def test_Registry__list_tags_invalid_status(mock_requests_get: MagicMock,
     test_http_request_timeout_s = 10
     mock_config_file.http_request_timeout_s = test_http_request_timeout_s
 
-    test_registry = HelperRegistry(mock_container_engine, test_registry_config)
+    test_registry = HelperRegistry(test_registry_config)
 
     # Run unit under test
     test_registry._list_tags(test_repo)
 
     # Check expectations
+    mock___init__.assert_called_once()
     mock__get_tag_endpoint_url.assert_called_once_with(test_repo)
     mock_requests_get.assert_called_once_with(test_tag_endpoint_url, timeout=test_http_request_timeout_s)
     mock_user_output.error.assert_called_once_with("Error in communication with the registry. Failed to retrieve tags. Response status code: " + str(mock_response.status_code))
     mock_user_output.msg.assert_called_once_with("Skipping repository: " + test_repo)
 
-@patch.object(registry.Core, "user_output")
-@patch.object(registry.Registry, "_list_repos_in_registry")
-def test_Registry_repos(mock__list_repos_in_registry: MagicMock, mock_user_output: MagicMock):
+@patch("dem.core.registry.requests.get")
+@patch.object(registry.Registry, "_list_tags")
+@patch.object(registry.Registry, "_get_repo_endpoint_url")
+@patch.object(registry.Registry, "__init__")
+def test_Registry__list_repos(mock___init__: MagicMock, mock__get_repo_endpoint_url: MagicMock,
+                              mock__list_tags: MagicMock, mock_requests_get: MagicMock) -> None:
     # Test setup
-    mock_container_engine = MagicMock()
-    test_registry_config = {}
-
-    mock__repos = MagicMock()
-
-    mock_generator = MagicMock()
-    mock__list_repos_in_registry.return_value = mock_generator
-
-    test_registry = HelperRegistry(mock_container_engine, test_registry_config)
-    test_registry._repos = mock__repos
-
-    # Run unit under test
-    actual_repos = test_registry.repos
-
-    # Check expectations
-    assert actual_repos is mock__repos
+    mock___init__.return_value = None
 
-    mock__list_repos_in_registry.assert_called_once()
-    mock_user_output.status_generator.assert_called_once_with(mock_generator)
+    test_repo_endpoint_url = "test_repo_endpoint_url"
+    mock__get_repo_endpoint_url.return_value = test_repo_endpoint_url
 
-def test_DockerHub__append_repo_with_tag():
-    # Test setup
-    mock_container_engine = MagicMock()
-    test_registry_config = {}
+    mock_response = MagicMock()
+    mock_response.status_code = requests.codes.ok
 
     test_endpoint_response = {
-        "results": [
+        "repositories": [
             {
-                "name": "latest"
+                "name": "test_repo1"
             },
             {
-                "name": "v0.0.1"
+                "name": "test_repo2"
             }
         ]
     }
-    test_repo = "test_repo"
 
-    test_docker_hub = registry.DockerHub(mock_container_engine, test_registry_config)
+    mock_requests_get.return_value = mock_response
+    mock_response.json.return_value = test_endpoint_response
+
+    test_registry = HelperRegistry({})
+    test_registry.config_file.http_request_timeout_s = 10
 
     # Run unit under test
-    test_docker_hub._append_repo_with_tag(test_endpoint_response, test_repo)
+    actual_generator_items = []
+    for item in test_registry._list_repos():
+        actual_generator_items.append(item)
 
     # Check expectations
-    expected_repos = []
-    for test_result in test_endpoint_response["results"]:
-        expected_repos.append(test_repo + ":" + test_result["name"])
-    assert expected_repos == test_docker_hub._repos
+    expected_generator_items = [
+        "Loading image data from: test_repo1",
+        "Loading image data from: test_repo2"
+    ]
+    assert expected_generator_items == actual_generator_items
 
-def test_DockerHub__get_tag_endpoint_url():
+    mock___init__.assert_called_once()
+    mock_requests_get.assert_called_once_with(test_repo_endpoint_url, 
+                                               timeout=test_registry.config_file.http_request_timeout_s)
+    mock_response.json.assert_called_once()
+    mock__list_tags.assert_has_calls([call("test_repo1"), call("test_repo2")])
+
+@patch("dem.core.registry.requests.get")
+@patch.object(registry.Registry, "user_output")
+@patch.object(registry.Registry, "_get_repo_endpoint_url")
+def test_Registry__list_repos_requests_get_Exception(mock__get_repo_endpoint_url: MagicMock,
+                                                     mock_user_output: MagicMock, 
+                                                     mock_requests_get: MagicMock) -> None:
     # Test setup
-    mock_container_engine = MagicMock()
     test_registry_config = {
         "url": "test_url",
+        "name": "test_name",
+        "namespace": "test_namespace"
     }
 
-    test_repo = "registry/test_repo"
+    test_repo_endpoint_url = "test_repo_endpoint_url"
+    mock__get_repo_endpoint_url.return_value = test_repo_endpoint_url
+
+    test_exception_text = "test_exception_text"
+    mock_requests_get.side_effect = Exception(test_exception_text)
 
-    test_docker_hub = registry.DockerHub(mock_container_engine, test_registry_config)
+    test_registry = HelperRegistry(test_registry_config)
+    test_registry.config_file.http_request_timeout_s = 10
 
     # Run unit under test
-    actual_endpoint_url = test_docker_hub._get_tag_endpoint_url(test_repo)
+    for _ in test_registry._list_repos():
+        pass
 
     # Check expectations
-    expected_endpoint_url = test_registry_config["url"] + "/v2/repositories/" + test_repo + "/tags/"
-    assert expected_endpoint_url == actual_endpoint_url
+    mock_requests_get.assert_called_once_with(test_repo_endpoint_url, 
+                                               timeout=test_registry.config_file.http_request_timeout_s)
+    mock_user_output.error.assert_called_once_with(test_exception_text)
+    mock_user_output.msg.assert_called_once_with(f"Skipping [bold]{test_registry_config['name']}[/bold].")
 
-@patch.object(registry.DockerHub, "_list_tags")
-def test_DockerHub__list_repos_in_registry(mock__list_tags: MagicMock):
+@patch("dem.core.registry.requests.get")
+@patch.object(registry.Registry, "user_output")
+@patch.object(registry.Registry, "_get_repo_endpoint_url")
+def test_Registry__list_repos_request_failed(mock__get_repo_endpoint_url: MagicMock,
+                                             mock_user_output: MagicMock, 
+                                             mock_requests_get: MagicMock) -> None:
     # Test setup
-    mock_container_engine = MagicMock()
     test_registry_config = {
-        "name": "test_registry_name"
+        "url": "test_url",
+        "name": "test_name",
+        "namespace": "test_namespace"
     }
-    test_repos = [
-        test_registry_config["name"] + "/test_repo1",
-        test_registry_config["name"] + "/test_repo2",
-    ]
 
-    mock_container_engine.search.return_value = test_repos
+    test_repo_endpoint_url = "test_repo_endpoint_url"
+    mock__get_repo_endpoint_url.return_value = test_repo_endpoint_url
 
-    test_docker_hub = registry.DockerHub(mock_container_engine, test_registry_config)
+    mock_response = MagicMock()
+    mock_response.status_code = "404"
+
+    mock_requests_get.return_value = mock_response
+
+    test_registry = HelperRegistry(test_registry_config)
+    test_registry.config_file.http_request_timeout_s = 10
 
     # Run unit under test
-    generator = test_docker_hub._list_repos_in_registry()
+    for _ in test_registry._list_repos():
+        pass
 
     # Check expectations
-    calls = []
-    for idx, item in enumerate(generator):
-        expected_item = "Loading image data from: " + test_repos[idx]
-        assert expected_item == item
+    mock_requests_get.assert_called_once_with(test_repo_endpoint_url, 
+                                               timeout=test_registry.config_file.http_request_timeout_s)
+    mock_user_output.error.assert_called_once_with(f"Error in communication with the registry. Failed to retrieve the repositories. Response status code: {mock_response.status_code}")
+    mock_user_output.msg.assert_called_once_with(f"Skipping [bold]{test_registry_config['name']}[/bold].")
 
-        calls.append(call(test_repos[idx]))
+@patch("dem.core.registry.requests.get")
+@patch.object(registry.Registry, "user_output")
+@patch.object(registry.Registry, "_get_repo_endpoint_url")
+def test_Registry__list_repos_JSONDecodeError(mock__get_repo_endpoint_url: MagicMock,
+                                              mock_user_output: MagicMock, 
+                                              mock_requests_get: MagicMock) -> None:
+    # Test setup
+    test_registry_config = {
+        "url": "test_url",
+        "name": "test_name",
+        "namespace": "test_namespace"
+    }
 
-    mock_container_engine.search.assert_called_once_with(test_registry_config["name"])
-    mock__list_tags.assert_has_calls(calls)
+    test_repo_endpoint_url = "test_repo_endpoint_url"
+    mock__get_repo_endpoint_url.return_value = test_repo_endpoint_url
 
-def test_DockerRegistry__append_repo_with_tag():
-    # Test setup
-    mock_container_engine = MagicMock()
-    test_registry_config = {}
+    mock_response = MagicMock()
+    mock_response.status_code = requests.codes.ok
 
-    test_endpoint_response = {
-        "tags": ["latest", "v0.0.1"]
-    }
-    test_repo = "test_repo"
+    mock_requests_get.return_value = mock_response
+    mock_response.json.side_effect = registry.requests.exceptions.JSONDecodeError("test", "test", 0)
 
-    test_docker_registry = registry.DockerRegistry(mock_container_engine, test_registry_config)
+    test_registry = HelperRegistry(test_registry_config)
+    test_registry.config_file.http_request_timeout_s = 10
 
     # Run unit under test
-    test_docker_registry._append_repo_with_tag(test_endpoint_response, test_repo)
+    for _ in test_registry._list_repos():
+        pass
 
     # Check expectations
-    expected_repos = [test_repo + ":" + test_result for test_result in test_endpoint_response["tags"]]
-    assert expected_repos == test_docker_registry._repos
+    mock_requests_get.assert_called_once_with(test_repo_endpoint_url, 
+                                               timeout=test_registry.config_file.http_request_timeout_s)
+    mock_response.json.assert_called_once()
+    mock_user_output.error.assert_called_once_with(f"Invalid JSON format in response from the registry: test: line 1 column 1 (char 0)")
+    mock_user_output.msg.assert_called_once_with(f"Skipping [bold]{test_registry_config['name']}[/bold].")
 
-def test_DockerRegistry__get_tag_endpoint_url():
+@patch("dem.core.registry.requests.get")
+@patch.object(registry.Registry, "user_output")
+@patch.object(registry.Registry, "_get_repo_endpoint_url")
+def test_Registry__list_repos_json_Exception(mock__get_repo_endpoint_url: MagicMock,
+                                             mock_user_output: MagicMock, 
+                                             mock_requests_get: MagicMock) -> None:
     # Test setup
-    mock_container_engine = MagicMock()
     test_registry_config = {
         "url": "test_url",
+        "name": "test_name",
+        "namespace": "test_namespace"
     }
 
-    test_repo = "registry/test_repo"
+    test_repo_endpoint_url = "test_repo_endpoint_url"
+    mock__get_repo_endpoint_url.return_value = test_repo_endpoint_url
 
-    test_docker_registry = registry.DockerRegistry(mock_container_engine, test_registry_config)
+    mock_response = MagicMock()
+    mock_response.status_code = requests.codes.ok
+
+    mock_requests_get.return_value = mock_response
+    test_exception_text = "test_exception_text"
+    mock_response.json.side_effect = Exception(test_exception_text)
+
+    test_registry = HelperRegistry(test_registry_config)
+    test_registry.config_file.http_request_timeout_s = 10
 
     # Run unit under test
-    actual_endpoint_url = test_docker_registry._get_tag_endpoint_url(test_repo)
+    for _ in test_registry._list_repos():
+        pass
 
     # Check expectations
-    expected_endpoint_url = test_registry_config["url"] + "/v2/" + test_repo.split("/")[1] + "/tags/list"
-    assert expected_endpoint_url == actual_endpoint_url
+    mock_requests_get.assert_called_once_with(test_repo_endpoint_url, 
+                                               timeout=test_registry.config_file.http_request_timeout_s)
+    mock_response.json.assert_called_once()
+    mock_user_output.error.assert_called_once_with(test_exception_text)
+    mock_user_output.msg.assert_called_once_with(f"Skipping [bold]{test_registry_config['name']}[/bold].")
 
-@patch.object(registry.DockerRegistry, "_list_tags")
-@patch.object(registry.DockerRegistry, "_search")
-def test_DockerRegistry__list_repos_in_registry(mock__search: MagicMock, mock__list_tags: MagicMock):
+@patch.object(registry.Core, "user_output")
+@patch.object(registry.Registry, "_list_repos")
+@patch.object(registry.Registry, "__init__")
+def test_Registry_repos(mock___init_: MagicMock, mock__list_repos: MagicMock, 
+                        mock_user_output: MagicMock):
     # Test setup
-    mock_container_engine = MagicMock()
-    test_registry_config = {
-        "name": "test_registry_name"
-    }
-    test_repo_names = [
-        "test_repo1",
-        "test_repo2",
-    ]
+    mock___init_.return_value = None
 
-    mock__search.return_value = test_repo_names
+    test_registry_config = {}
 
-    test_docker_registry = registry.DockerRegistry(mock_container_engine, test_registry_config)
+    mock__repos = MagicMock()
+
+    mock_generator = MagicMock()
+    mock__list_repos.return_value = mock_generator
+
+    test_registry = HelperRegistry(test_registry_config)
+    test_registry._repos = mock__repos
 
     # Run unit under test
-    generator = test_docker_registry._list_repos_in_registry()
+    actual_repos = test_registry.repos
 
     # Check expectations
-    calls = []
-    for idx, item in enumerate(generator):
-        expected_repo = test_registry_config["name"] + "/" + test_repo_names[idx]
-        expected_item = "Loading image data from: " + expected_repo
-        assert expected_item == item
-
-        calls.append(call(expected_repo))
+    assert actual_repos is mock__repos
 
-    mock__search.assert_called_once()
-    mock__list_tags.assert_has_calls(calls)
+    mock___init_.assert_called_once()
+    mock__list_repos.assert_called_once()
+    mock_user_output.status_generator.assert_called_once_with(mock_generator)
 
-@patch.object(registry.Core, "config_file")
-@patch("dem.core.registry.requests.get")
-def test_DockerRegistry__search(mock_requests_get: MagicMock, mock_config_file) -> None:
+def test_DockerHub_invalid_registry_config() -> None:
     # Test setup
-    mock_container_engine = MagicMock()
     test_registry_config = {
-        "url": "test_url"
-    }
-    test_response = {
-        "repositories": [
-            "test_repo1",
-            "test_repo2",
-        ] 
+        "url": "test_url",
+        "name": "test_name"
     }
 
-    mock_response = MagicMock()
-    mock_response.status_code = registry.requests.codes.ok
-    mock_response.json.return_value = test_response
-    mock_requests_get.return_value = mock_response
+    # Run unit under test
+    with pytest.raises(registry.RegistryError):
+        registry.DockerHub(test_registry_config)
 
-    test_http_request_timeout_s = 10
-    mock_config_file.http_request_timeout_s = test_http_request_timeout_s
+@patch.object(registry.DockerHub, "__init__")
+def test_DockerHub__append_repo_with_tag(mock___init__: MagicMock) -> None:
+    # Test setup
+    mock___init__.return_value = None
 
-    test_docker_registry = registry.DockerRegistry(mock_container_engine, test_registry_config)
+    test_registry_config = {}
+
+    test_endpoint_response = {
+        "results": [
+            {
+                "name": "latest"
+            },
+            {
+                "name": "v0.0.1"
+            }
+        ]
+    }
+    test_repo = "test_repo"
+
+    test_docker_hub = registry.DockerHub(test_registry_config)
+    test_docker_hub._repos = []
 
     # Run unit under test
-    actual_repo_names = test_docker_registry._search()
+    test_docker_hub._append_repo_with_tag(test_endpoint_response, test_repo)
 
     # Check expectations
-    assert actual_repo_names is test_response["repositories"]
+    expected_repos = []
+    for test_result in test_endpoint_response["results"]:
+        expected_repos.append(test_repo + ":" + test_result["name"])
+    assert expected_repos == test_docker_hub._repos
 
-    mock_requests_get.assert_called_once_with(test_registry_config["url"] + "/v2/_catalog", 
-                                              timeout=test_http_request_timeout_s)
-    mock_response.json.assert_called_once()
+    mock___init__.assert_called_once()
 
-@patch.object(registry.Core, "config_file")
-@patch.object(registry.DockerRegistry, "user_output")
-@patch("dem.core.registry.requests.get")
-def test_DockerRegistry__search_requests_get_exception(mock_requests_get: MagicMock, 
-                                                       mock_user_output: MagicMock,
-                                                       mock_config_file: MagicMock) -> None:
+def test_DockerHub__get_repo_endpoint_url():
     # Test setup
-    mock_container_engine = MagicMock()
     test_registry_config = {
+        "url": "test_url",
         "name": "test_name",
-        "url": "test_url"
+        "namespace": "test_namespace"
     }
 
-    mock_requests_get.side_effect = Exception("test")
-
-    test_http_request_timeout_s = 10
-    mock_config_file.http_request_timeout_s = test_http_request_timeout_s
-
-    test_docker_registry = registry.DockerRegistry(mock_container_engine, test_registry_config)
+    test_docker_hub = registry.DockerHub(test_registry_config)
 
     # Run unit under test
-    actual_repo_names = test_docker_registry._search()
+    actual_endpoint_url = test_docker_hub._get_repo_endpoint_url()
 
     # Check expectations
-    assert actual_repo_names == []
-
-    mock_requests_get.assert_called_once_with(test_registry_config["url"] + "/v2/_catalog", 
-                                              timeout=test_http_request_timeout_s)
-    mock_user_output.error(str(mock_requests_get.side_effect))
-    mock_user_output.msg("Skipping registry: " + test_registry_config["name"])
+    expected_endpoint_url = f"{test_registry_config['url']}/v2/namespaces/{test_registry_config['namespace']}/repositories"
+    assert expected_endpoint_url == actual_endpoint_url
 
-@patch.object(registry.Core, "config_file")
-@patch.object(registry.DockerRegistry, "user_output")
-@patch("dem.core.registry.requests.get")
-def test_DockerRegistry__search_invalid_status_code(mock_requests_get: MagicMock, 
-                                                    mock_user_output: MagicMock,
-                                                    mock_config_file: MagicMock) -> None:
+def test_DockerHub__get_tag_endpoint_url():
     # Test setup
-    mock_container_engine = MagicMock()
     test_registry_config = {
+        "url": "test_url",
         "name": "test_name",
-        "url": "test_url"
+        "namespace": "test_namespace"
     }
 
-    mock_response = MagicMock()
-    mock_response.status_code = 0
-    mock_requests_get.return_value = mock_response
+    test_repo = "registry/test_repo"
 
-    test_http_request_timeout_s = 10
-    mock_config_file.http_request_timeout_s = test_http_request_timeout_s
+    test_docker_hub = registry.DockerHub(test_registry_config)
 
-    test_docker_registry = registry.DockerRegistry(mock_container_engine, test_registry_config)
+    # Run unit under test
+    actual_endpoint_url = test_docker_hub._get_tag_endpoint_url(test_repo)
+
+    # Check expectations
+    expected_endpoint_url = f"{test_registry_config['url']}/v2/namespaces/{test_registry_config['namespace']}/repositories/{test_repo}/tags"
+    assert expected_endpoint_url == actual_endpoint_url
+
+
+@patch.object(registry.Registry, "__init__")
+def test_DockerRegistry__append_repo_with_tag(mock___init__: MagicMock) -> None:
+    # Test setup
+    mock___init__.return_value = None
+
+    test_registry_config = {}
+
+    test_endpoint_response = {
+        "tags": ["latest", "v0.0.1"]
+    }
+    test_repo = "test_repo"
+
+    test_docker_registry = registry.DockerRegistry(test_registry_config)
+    test_docker_registry._repos = []
 
     # Run unit under test
-    actual_repo_names = test_docker_registry._search()
+    test_docker_registry._append_repo_with_tag(test_endpoint_response, test_repo)
 
     # Check expectations
-    assert actual_repo_names == []
+    expected_repos = [test_repo + ":" + test_result for test_result in test_endpoint_response["tags"]]
+    assert expected_repos == test_docker_registry._repos
 
-    mock_requests_get.assert_called_once_with(test_registry_config["url"] + "/v2/_catalog", 
-                                              timeout=test_http_request_timeout_s)
-    mock_user_output.error("Error in communication with the registry. Failed to retrieve the repositories. Response status code: " + str(mock_response.status_code))
-    mock_user_output.msg("Skipping registry: " + test_registry_config["name"])
+    mock___init__.assert_called_once()
 
-@patch.object(registry.Core, "config_file")
-@patch.object(registry.DockerRegistry, "user_output")
-@patch("dem.core.registry.requests.get")
-def test_DockerRegistry__search_json_decode_exception(mock_requests_get: MagicMock, 
-                                                      mock_user_output: MagicMock,
-                                                      mock_config_file: MagicMock) -> None:
+def test_DockerRegistry__get_repo_endpoint_url():
     # Test setup
-    mock_container_engine = MagicMock()
     test_registry_config = {
+        "url": "test_url",
         "name": "test_name",
-        "url": "test_url"
+        "namespace": "test_namespace"
     }
 
-    mock_response = MagicMock()
-    mock_response.status_code = requests.codes.ok
-    mock_response.json.side_effect = requests.exceptions.JSONDecodeError("dummy_msg", "dummy_doc", 0)
-    mock_requests_get.return_value = mock_response
-
-    test_http_request_timeout_s = 10
-    mock_config_file.http_request_timeout_s = test_http_request_timeout_s
-
-    test_docker_registry = registry.DockerRegistry(mock_container_engine, test_registry_config)
+    test_docker_registry = registry.DockerRegistry(test_registry_config)
 
     # Run unit under test
-    actual_repo_names = test_docker_registry._search()
+    actual_endpoint_url = test_docker_registry._get_repo_endpoint_url()
 
     # Check expectations
-    assert actual_repo_names == []
-
-    mock_requests_get.assert_called_once_with(test_registry_config["url"] + "/v2/_catalog", 
-                                              timeout=test_http_request_timeout_s)
-    mock_response.json.assert_called_once()
-    mock_user_output.error("Invalid JSON format in response. " + str(mock_response.json.side_effect))
-    mock_user_output.msg("Skipping registry: " + test_registry_config["name"])
+    expected_endpoint_url = f"{test_registry_config['url']}/v2/_catalog"
+    assert expected_endpoint_url == actual_endpoint_url
 
-@patch.object(registry.Core, "config_file")
-@patch.object(registry.DockerRegistry, "user_output")
-@patch("dem.core.registry.requests.get")
-def test_DockerRegistry__search_json_generic_exception(mock_requests_get: MagicMock, 
-                                                       mock_user_output: MagicMock,
-                                                       mock_config_file: MagicMock) -> None:
+def test_DockerRegistry__get_tag_endpoint_url():
     # Test setup
-    mock_container_engine = MagicMock()
     test_registry_config = {
+        "url": "test_url",
         "name": "test_name",
-        "url": "test_url"
+        "namespace": "test_namespace"
     }
 
-    mock_response = MagicMock()
-    mock_response.status_code = requests.codes.ok
-    mock_response.json.side_effect = Exception("test")
-    mock_requests_get.return_value = mock_response
+    test_repo = "registry/test_repo"
 
-    test_http_request_timeout_s = 10
-    mock_config_file.http_request_timeout_s = test_http_request_timeout_s
+    test_docker_registry = registry.DockerRegistry(test_registry_config)
 
-    test_docker_registry = registry.DockerRegistry(mock_container_engine, test_registry_config)
-    
     # Run unit under test
-    actual_repo_names = test_docker_registry._search()
+    actual_endpoint_url = test_docker_registry._get_tag_endpoint_url(test_repo)
 
     # Check expectations
-    assert actual_repo_names == []
-
-    mock_requests_get.assert_called_once_with(test_registry_config["url"] + "/v2/_catalog", 
-                                              timeout=test_http_request_timeout_s)
-    mock_response.json.assert_called_once()
-    mock_user_output.error(str(mock_response.json.side_effect))
-    mock_user_output.msg("Skipping registry: " + test_registry_config["name"])
+    expected_endpoint_url = f"{test_registry_config['url']}/v2/{test_repo.split('/')[1]}/tags/list"
+    assert expected_endpoint_url == actual_endpoint_url
 
 @patch.object(registry.Core, "config_file")
 @patch("dem.core.registry.DockerRegistry")
@@ -465,7 +505,6 @@ def test_DockerRegistry__search_json_generic_exception(mock_requests_get: MagicM
 def test_Registries(mock_DockerHub: MagicMock, mock_DockerRegistry: MagicMock, 
                     mock_config_file: MagicMock) -> None:
     # Test setup
-    mock_container_engine = MagicMock()
     mock_config_file.registries = [
         {
             "name": "registry_config1",
@@ -484,15 +523,14 @@ def test_Registries(mock_DockerHub: MagicMock, mock_DockerRegistry: MagicMock,
     mock_DockerRegistry.return_value = mock_docker_registry
 
     # Run unit under test
-    test_registries = registry.Registries(mock_container_engine)
+    test_registries = registry.Registries()
 
     # Check expectations
-    assert test_registries._container_engine is mock_container_engine
     assert mock_docker_hub in test_registries.registries
     assert mock_docker_registry in test_registries.registries
 
-    mock_DockerHub.assert_called_once_with(mock_container_engine, mock_config_file.registries[0])
-    mock_DockerRegistry.assert_called_once_with(mock_container_engine, mock_config_file.registries[1])
+    mock_DockerHub.assert_called_once_with(mock_config_file.registries[0])
+    mock_DockerRegistry.assert_called_once_with(mock_config_file.registries[1])
 
 @patch.object(registry.Core, "config_file")
 @patch("dem.core.registry.DockerRegistry")
@@ -500,7 +538,6 @@ def test_Registries(mock_DockerHub: MagicMock, mock_DockerRegistry: MagicMock,
 def test_Registries_list_repos(mock_DockerHub: MagicMock, mock_DockerRegistry: MagicMock,
                                mock_config_file: MagicMock) -> None:
     # Test setup
-    mock_container_engine = MagicMock()
     mock_config_file.registries = [
         {
             "name": "registry_config1",
@@ -525,7 +562,7 @@ def test_Registries_list_repos(mock_DockerHub: MagicMock, mock_DockerRegistry: M
     mock_DockerHub._docker_hub_domain = "registry.hub.docker.com"
     mock_DockerRegistry.return_value = mock_docker_registry
 
-    test_registries = registry.Registries(mock_container_engine)
+    test_registries = registry.Registries()
 
     # Run unit under test
     actual_repos = test_registries.list_repos([])
@@ -534,55 +571,11 @@ def test_Registries_list_repos(mock_DockerHub: MagicMock, mock_DockerRegistry: M
     expected_repos = [*test_repos * 2]
     assert expected_repos == actual_repos
 
-@patch.object(registry.Registries, "user_output")
-@patch.object(registry.Registries, "__init__")
-def test_Registries_list_repos_handle_exception(mock___init__: MagicMock, 
-                                                mock_user_output: MagicMock):
-    # Test setup
-    mock___init__.return_value = None
-
-    test_exception_text = "test_exception_test"
-    test_registry_name = "test_registry_name"
-    class StubRegistry(registry.Registry):
-        def __init__(self) -> None:
-            self._registry_config = {
-                "name": test_registry_name
-            }
-
-        def _append_repo_with_tag(self, endpoint_response: dict, repo: str) -> None:
-            pass
-
-        def _get_tag_endpoint_url(self, repo_name: str) -> str:
-            return "test"
-
-        def _list_repos_in_registry(self) -> Generator:
-            yield "test"
-
-        @property
-        def repos(self) -> list[str]:
-            raise Exception(test_exception_text)
-
-    test_registries = registry.Registries(MagicMock())
-    test_registries.registries = [StubRegistry()]
-
-    # Run unit under test
-    test_registries.list_repos([])
-
-    # Check expectations
-    mock___init__.assert_called_once()
-
-    calls = [
-        call(test_exception_text),
-        call("[red]Error: The " + test_registry_name + " registry is not available.[/]")
-    ]
-    mock_user_output.error.assert_has_calls(calls)
-
 @patch.object(registry.Core, "config_file")
 @patch.object(registry.Registries, "_add_registry_instance")
 def test_Registries_add_registry(mock__add_registry_instance: MagicMock, 
                                  mock_config_file: MagicMock) -> None:
     # Test setup
-    mock_container_engine = MagicMock()
     mock_config_file.registries = []
 
     registry_to_add = {
@@ -590,7 +583,7 @@ def test_Registries_add_registry(mock__add_registry_instance: MagicMock,
         "url": "https://registry.hub.docker.com/v2/"
     }
 
-    test_registries = registry.Registries(mock_container_engine)
+    test_registries = registry.Registries()
 
     # Run unit under test
     test_registries.add_registry(registry_to_add)
@@ -602,15 +595,15 @@ def test_Registries_add_registry(mock__add_registry_instance: MagicMock,
     mock_config_file.flush.assert_called_once()
 
 @patch.object(registry.Core, "config_file")
-def test_list_registries(mock_config_file: MagicMock) -> None:
+def test_Registries_list_registry_configs(mock_config_file: MagicMock) -> None:
     # Test setup
-    mock_container_engine = MagicMock()
     mock_config_file.registries = [{
         "name": "test_registry_name",
-        "url": "https://registry.hub.docker.com/v2/"
+        "url": "https://registry.hub.docker.com/v2/",
+        "namespace": "test_namespace"
     }]
 
-    test_registries = registry.Registries(mock_container_engine)
+    test_registries = registry.Registries()
 
     # Run unit under test
     actual_registry_list = test_registries.list_registry_configs()
@@ -619,15 +612,15 @@ def test_list_registries(mock_config_file: MagicMock) -> None:
     assert actual_registry_list is mock_config_file.registries
 
 @patch.object(registry.Core, "config_file")
-def test_delete_registry(mock_config_file: MagicMock) -> None:
+def test_Registries_delete_registry(mock_config_file: MagicMock) -> None:
     # Test setup
-    mock_container_engine = MagicMock()
     mock_config_file.registries = [{
         "name": "test_registry_name",
-        "url": "https://registry.hub.docker.com/v2/"
+        "url": "https://registry.hub.docker.com/v2/",
+        "namespace": "test_namespace"
     }]
 
-    test_registries = registry.Registries(mock_container_engine)
+    test_registries = registry.Registries()
 
     # Run unit under test
     test_registries.delete_registry(mock_config_file.registries[0])