text: import inspect
  import logging
  import hashlib
  
  from data.database import DerivedStorageForImage, TagManifest, Manifest, Image
  from data.registry_model.registry_oci_model import back_compat_oci_model, oci_model
  from data.registry_model.registry_pre_oci_model import pre_oci_model
  from data.registry_model.datatypes import LegacyImage, Manifest as ManifestDataType
  
  
  logger = logging.getLogger(__name__)
  
  
  class SplitModel(object):
      def __init__(
          self, oci_model_proportion, oci_namespace_whitelist, v22_namespace_whitelist, oci_only_mode
      ):
          self.v22_namespace_whitelist = set(v22_namespace_whitelist)
  
          self.oci_namespace_whitelist = set(oci_namespace_whitelist)
          self.oci_namespace_whitelist.update(v22_namespace_whitelist)
  
          self.oci_model_proportion = oci_model_proportion
          self.oci_only_mode = oci_only_mode
  
      def supports_schema2(self, namespace_name):
          """ Returns whether the implementation of the data interface supports schema 2 format
          manifests. """
          return namespace_name in self.v22_namespace_whitelist
  
      def _namespace_from_kwargs(self, args_dict):
          if "namespace_name" in args_dict:
              return args_dict["namespace_name"]
  
          if "repository_ref" in args_dict:
              return args_dict["repository_ref"].namespace_name
  
          if "tag" in args_dict:
              return args_dict["tag"].repository.namespace_name
  
          if "manifest" in args_dict:
              manifest = args_dict["manifest"]
              if manifest._is_tag_manifest:
                  return TagManifest.get(id=manifest._db_id).tag.repository.namespace_user.username
              else:
                  return Manifest.get(id=manifest._db_id).repository.namespace_user.username
  
          if "manifest_or_legacy_image" in args_dict:
              manifest_or_legacy_image = args_dict["manifest_or_legacy_image"]
              if isinstance(manifest_or_legacy_image, LegacyImage):
                  return Image.get(
                      id=manifest_or_legacy_image._db_id
                  ).repository.namespace_user.username
              else:
                  manifest = manifest_or_legacy_image
                  if manifest._is_tag_manifest:
                      return TagManifest.get(
                          id=manifest._db_id
                      ).tag.repository.namespace_user.username
                  else:
                      return Manifest.get(id=manifest._db_id).repository.namespace_user.username
  
          if "derived_image" in args_dict:
              return DerivedStorageForImage.get(
                  id=args_dict["derived_image"]._db_id
              ).source_image.repository.namespace_user.username
  
          if "blob" in args_dict:
              return ""  # Blob functions are shared, so no need to do anything.
  
          if "blob_upload" in args_dict:
              return ""  # Blob functions are shared, so no need to do anything.
  
          raise Exception("Unknown namespace for dict `%s`" % args_dict)
  
      def __getattr__(self, attr):
          def method(*args, **kwargs):
              if self.oci_model_proportion >= 1.0:
                  if self.oci_only_mode:
                      logger.debug(
                          "Calling method `%s` under full OCI data model for all namespaces", attr
                      )
                      return getattr(oci_model, attr)(*args, **kwargs)
                  else:
                      logger.debug(
                          "Calling method `%s` under compat OCI data model for all namespaces", attr
                      )
                      return getattr(back_compat_oci_model, attr)(*args, **kwargs)
  
              argnames = inspect.getargspec(getattr(back_compat_oci_model, attr))[0]
              if not argnames and isinstance(args[0], ManifestDataType):
                  args_dict = dict(manifest=args[0])
              else:
                  args_dict = {argnames[index + 1]: value for index, value in enumerate(args)}
  
              if attr in [
                  "yield_tags_for_vulnerability_notification",
                  "get_most_recent_tag_lifetime_start",
              ]:
                  use_oci = self.oci_model_proportion >= 1.0
                  namespace_name = "(implicit for " + attr + ")"
              else:
                  namespace_name = self._namespace_from_kwargs(args_dict)
                  use_oci = namespace_name in self.oci_namespace_whitelist
  
                  if not use_oci and self.oci_model_proportion:
                      # Hash the namespace name and see if it falls into the proportion bucket.
                      bucket = int(hashlib.md5(namespace_name).hexdigest(), 16) % 100
                      if bucket <= int(self.oci_model_proportion * 100):
                          logger.debug(
                              "Enabling OCI for namespace `%s` in proportional bucket", namespace_name
                          )
                          use_oci = True
  
              if use_oci:
                  logger.debug(
                      "Calling method `%s` under OCI data model for namespace `%s`",
                      attr,
                      namespace_name,
                  )
                  return getattr(back_compat_oci_model, attr)(*args, **kwargs)
              else:
                  return getattr(pre_oci_model, attr)(*args, **kwargs)
  
          return method
  