docstr: Upload a new asset
docstr_tok: ["Upload","a","new","asset"]
code: def new(
      self, asset_path: str, name: str, version: str, dry_run=False
  ):
      """
      Upload a new asset
      """
      versions_object_name = self.get_versions_object_name(name)
      if self.driver.exists(versions_object_name):
          raise errors.AssetAlreadyExistsError(name)
      logger.info("Pushing new asset", name=name, asset_path=asset_path)
      self.push(asset_path, name, version, dry_run=dry_run)
  
      with tempfile.TemporaryDirectory() as dversions:
          with open(os.path.join(dversions, "versions.json"), "w") as f:
              json.dump({"versions": [version]}, f)
          logger.debug("Pushing versions file", name=name)
          if not dry_run:
              self.driver.upload_object(
                  os.path.join(dversions, "versions.json"),
                  versions_object_name,
              )
  
imports: import datetime
  import glob
  import json
  import os
  import tempfile
  import time
  from typing import Any, Optional
  import humanize
  from dateutil import parser, tz
  from structlog import get_logger
  from modelkit.assets import errors
  from modelkit.assets.drivers.abc import StorageDriver
  from modelkit.assets.drivers.local import LocalStorageDriver, LocalStorageDriverSettings
  from modelkit.assets.settings import AssetSpec
  from modelkit.utils.logging import ContextualizedLogging
label_desc: Use image node_id 7 for calling the StorageProvider obj's underlying member method code with example usage: obj.new(asset_path, name, version, dry_run) without return types