Source code for steamship.invocable.config

import json
from enum import Enum
from pathlib import Path
from typing import Dict

from steamship.base.error import SteamshipError
from steamship.base.model import CamelModel
from steamship.data.manifest import ConfigParameter, ConfigParameterType


[docs] class Config(CamelModel): """Base class Steamship Package and Plugin configuration objects.""" def __init__(self, **kwargs): kwargs = {k: v for k, v in kwargs.items() if v is not None} super().__init__(**kwargs)
[docs] def extend_with_dict(self, d: dict, overwrite: bool = False): """Sets the attributes on this object with provided keys and values.""" for key, val in (d or {}).items(): if hasattr(self, key) and (overwrite or getattr(self, key) is None): setattr(self, key, val)
[docs] def extend_with_json_file( self, path: Path, overwrite: bool = False, fail_on_missing_file: bool = True ): """Extends this config object's values with a JSON file from disk. This is useful for applying late-bound defaults, such as API keys added to a deployment bundle.""" if not path.exists(): if fail_on_missing_file: raise SteamshipError( message=f"Attempted to extend Config object with {path}, but the file was not found." ) return with open(path) as f: data = json.load(f) if not isinstance(data, dict): raise SteamshipError( message=f"Attempted to extend Config object with {path}, but the file did not contain a JSON `dict` object." ) self.extend_with_dict(data, overwrite)
[docs] @staticmethod def strip_enum(default_value): if issubclass(type(default_value), Enum): return default_value.value else: return default_value
[docs] @classmethod def get_config_parameters(cls) -> Dict[str, ConfigParameter]: result = {} for field_name, field in cls.__fields__.items(): description = field.field_info.description type_ = ConfigParameterType.from_python_type(field.type_) default_ = cls.strip_enum(field.default) # Note: Pydantic treats any field with a default value as being `required == False`, which is not strictly # the same thing as being optional. Below we use "required is False and allow_none is True" so that # user interface generation code has access to BOTH the status of a default value and also # the notion of whether the absense of a value will truly be treated as absence. # That way it can provide hints to the user to minimize surprise about how their inputs will be interpreted. # optional_ = field.required is False and field.allow_none is True result[field_name] = ConfigParameter( type=type_, default=default_, description=description, # optional=optional_ ) return result