code: def link(self, variables):
      pfolio_name = variables.get("artifactPortfolioName")
      artifact_id = variables.get("artifactID") or variables.get(
          "clientID"
      )
      if not pfolio_name or not artifact_id:
          raise ValueError(
              "query variables must contain artifactPortfolioName and either artifactID or clientID"
          )
      aliases = variables.get("aliases")
      # We automatically create a portfolio for the user if we can't find the one given.
      links = self._portfolio_links.setdefault(pfolio_name, [])
      if not any(map(lambda x: x["id"] == artifact_id, links)):
          art = {
              "id": artifact_id,
              "aliases": [a["alias"] for a in aliases],
          }
          links.append(art)
  
      self._ctx["portfolio_links"].setdefault(pfolio_name, {})
      num = len(links)
      self._ctx["portfolio_links"][pfolio_name]["num"] = num
      response = {"data": {"linkArtifact": {"versionIndex": num - 1}}}
      return response
  
file_path: wandb/tests/pytest_tests/unit_tests_old/utils/artifact_emu.py
imports: import copy
label_desc: Use image node_id 3 for calling the ArtifactEmulator obj's underlying member method code with example usage: obj.link(variables) and returns: response