Use _load_artifact() for ArtifactElement

Artifact elements require access to the artifact early on to walk
dependencies. Use `_load_artifact()` for this instead of a custom code
path.
diff --git a/src/buildstream/_artifactelement.py b/src/buildstream/_artifactelement.py
index 9003503..cf7f55d 100644
--- a/src/buildstream/_artifactelement.py
+++ b/src/buildstream/_artifactelement.py
@@ -51,17 +51,10 @@
     def __init__(self, context, ref):
         project_name, element_name, key = verify_artifact_ref(ref)
 
-        # At this point we only know the key which was specified on the command line,
-        # so we will pretend all keys are equal.
-        #
-        # If the artifact is cached, then the real keys will be loaded from the
-        # artifact instead.
-        #
-        artifact = Artifact(self, context, strong_key=key, strict_key=key, weak_key=key)
         project = ArtifactProject(project_name, context)
         load_element = LoadElement(Node.from_dict({}), element_name, project.loader)  # NOTE element has no .bst suffix
 
-        super().__init__(context, project, load_element, None, artifact=artifact)
+        super().__init__(context, project, load_element, None, artifact_key=key)
 
     ########################################################
     #                      Public API                      #
@@ -128,6 +121,10 @@
     #         Override internal Element methods            #
     ########################################################
 
+    def _load_artifact(self, *, pull, strict=None):  # pylint: disable=useless-super-delegation
+        # Always operate in strict mode as artifact key has been specified explicitly.
+        return super()._load_artifact(pull=pull, strict=True)
+
     # Once we've finished loading an artifact, we assume the
     # state of the loaded artifact. This is also used if the
     # artifact is loaded after pulling.
diff --git a/src/buildstream/element.py b/src/buildstream/element.py
index 3b15bc1..9908702 100644
--- a/src/buildstream/element.py
+++ b/src/buildstream/element.py
@@ -226,7 +226,7 @@
         load_element: "LoadElement",
         plugin_conf: Dict[str, Any],
         *,
-        artifact: Artifact = None,
+        artifact_key: str = None,
     ):
 
         self.__cache_key_dict = None  # Dict for cache key calculation
@@ -318,8 +318,8 @@
         self.__environment: Dict[str, str] = {}
         self.__variables: Optional[Variables] = None
 
-        if artifact:
-            self.__initialize_from_artifact(artifact)
+        if artifact_key:
+            self.__initialize_from_artifact_key(artifact_key)
         else:
             self.__initialize_from_yaml(load_element, plugin_conf)
 
@@ -1907,9 +1907,12 @@
     #
     # Returns: True if the artifact has been downloaded, False otherwise
     #
-    def _load_artifact(self, *, pull):
+    def _load_artifact(self, *, pull, strict=None):
         context = self._get_context()
 
+        if strict is None:
+            strict = context.get_strict()
+
         pull_buildtrees = context.pull_buildtrees and not self._get_workspace()
 
         # First check whether we already have the strict artifact in the local cache
@@ -1932,7 +1935,7 @@
         # Attempt to pull artifact with the strict cache key
         pulled = pull and artifact.pull(pull_buildtrees=pull_buildtrees)
 
-        if artifact.cached() or context.get_strict():
+        if artifact.cached() or strict:
             self.__artifact = artifact
             return pulled
         elif self.__pull_pending:
@@ -2871,16 +2874,31 @@
         self.__variables.expand(sandbox_config)
         self.__sandbox_config = SandboxConfig.new_from_node(sandbox_config, platform=context.platform)
 
-    # __initialize_from_artifact()
+    # __initialize_from_artifact_key()
     #
-    # Initialize the element state from an Artifact object
+    # Initialize the element state from an artifact key
     #
-    def __initialize_from_artifact(self, artifact: Artifact):
-        self.__artifact = artifact
-        artifact.query_cache()
-        self._mimic_artifact()
-        if not artifact.cached():
+    def __initialize_from_artifact_key(self, key: str):
+        # At this point we only know the key which was specified on the command line,
+        # so we will pretend all keys are equal.
+        #
+        # If the artifact is cached, then the real keys will be loaded from the
+        # artifact in `_load_artifact()` and `_load_artifact_done()`.
+        #
+        self.__cache_key = key
+        self.__strict_cache_key = key
+        self.__weak_cache_key = key
+
+        # ArtifactElement requires access to the artifact early on to walk
+        # dependencies.
+        self._load_artifact(pull=False)
+
+        if not self._cached():
+            # Remotes are not initialized when artifact elements are loaded.
+            # Always consider pull pending if the artifact is not cached.
             self.__pull_pending = True
+        else:
+            self._load_artifact_done()
 
     @classmethod
     def __compose_default_splits(cls, project, defaults, first_pass):