text: import jsonschema
  import copy
  from jsonschema import ValidationError
  from sqlalchemy.ext.mutable import Mutable
  
  from redash.utils import json_dumps, json_loads
  
  SECRET_PLACEHOLDER = "--------"
  
  
  class ConfigurationContainer(Mutable):
      @classmethod
      def coerce(cls, key, value):
          if not isinstance(value, ConfigurationContainer):
              if isinstance(value, dict):
                  return ConfigurationContainer(value)
  
              # this call will raise ValueError
              return Mutable.coerce(key, value)
          else:
              return value
  
      def __init__(self, config, schema=None):
          self._config = config
          self.set_schema(schema)
  
      def set_schema(self, schema):
          configuration_schema = copy.deepcopy(schema)
          if isinstance(configuration_schema, dict):
              for prop in configuration_schema.get("properties", {}).values():
                  if "extendedEnum" in prop:
                      prop["enum"] = [option["value"] for option in prop["extendedEnum"]]
                      del prop["extendedEnum"]
          self._schema = configuration_schema
  
      @property
      def schema(self):
          if self._schema is None:
              raise RuntimeError("Schema missing.")
  
          return self._schema
  
      def is_valid(self):
          try:
              self.validate()
          except (ValidationError, ValueError):
              return False
  
          return True
  
      def validate(self):
          jsonschema.validate(self._config, self._schema)
  
      def to_json(self):
          return json_dumps(self._config, sort_keys=True)
  
      def iteritems(self):
          return self._config.items()
  
      def to_dict(self, mask_secrets=False):
          if mask_secrets is False or "secret" not in self.schema:
              return self._config
  
          config = self._config.copy()
          for key in config:
              if key in self.schema["secret"]:
                  config[key] = SECRET_PLACEHOLDER
  
          return config
  
      def update(self, new_config):
          jsonschema.validate(new_config, self.schema)
  
          config = {}
          for k, v in new_config.items():
              if k in self.schema.get("secret", []) and v == SECRET_PLACEHOLDER:
                  config[k] = self[k]
              else:
                  config[k] = v
  
          self._config = config
          self.changed()
  
      def get(self, *args, **kwargs):
          return self._config.get(*args, **kwargs)
  
      def __setitem__(self, key, value):
          self._config[key] = value
          self.changed()
  
      def __getitem__(self, item):
          if item in self._config:
              return self._config[item]
  
          raise KeyError(item)
  
      def __contains__(self, item):
          return item in self._config
  
      @classmethod
      def from_json(cls, config_in_json):
          if config_in_json is None:
              return cls({})
          return cls(json_loads(config_in_json))
  