コード例 #1
0
ファイル: config_validation.py プロジェクト: zinefer/esphome
 def validator(value):
     if string_:
         value = string(value)
         value = value.replace(' ', space)
     if to_int:
         value = int_(value)
     if to_float:
         value = float_(value)
     if lower:
         value = Lower(value)
     if upper:
         value = Upper(value)
     if value not in values:
         import difflib
         options_ = [text_type(x) for x in values]
         option = text_type(value)
         matches = difflib.get_close_matches(option, options_)
         if matches:
             raise Invalid(
                 u"Unknown value '{}', did you mean {}?"
                 u"".format(value,
                            u", ".join(u"'{}'".format(x) for x in matches)))
         raise Invalid(u"Unknown value '{}', valid options are {}.".format(
             value, options))
     return value
コード例 #2
0
def logger_log_action_to_code(config, action_id, template_arg, args):
    esp_log = LOG_LEVEL_TO_ESP_LOG[config[CONF_LEVEL]]
    args_ = [cg.RawExpression(text_type(x)) for x in config[CONF_ARGS]]

    text = text_type(cg.statement(esp_log(config[CONF_TAG], config[CONF_FORMAT], *args_)))

    lambda_ = yield cg.process_lambda(Lambda(text), args, return_type=cg.void)
    yield cg.new_Pvariable(action_id, template_arg, lambda_)
コード例 #3
0
def logger_log_action_to_code(config, action_id, template_arg, args):
    esp_log = LOG_LEVEL_TO_ESP_LOG[config[CONF_LEVEL]]
    args_ = [RawExpression(text_type(x)) for x in config[CONF_ARGS]]

    text = text_type(
        statement(esp_log(config[CONF_TAG], config[CONF_FORMAT], *args_)))

    for lambda_ in process_lambda(Lambda(text), args, return_type=void):
        yield None
    rhs = LambdaAction.new(template_arg, lambda_)
    type = LambdaAction.template(template_arg)
    yield Pvariable(action_id, rhs, type=type)
コード例 #4
0
ファイル: config_validation.py プロジェクト: zinefer/esphome
def alphanumeric(value):
    if value is None:
        raise Invalid("string value is None")
    value = text_type(value)
    if not value.isalnum():
        raise Invalid("string value is not alphanumeric")
    return value
コード例 #5
0
def write_cpp(config):
    _LOGGER.info("Generating C++ source...")

    CORE.add_job(core_config.to_code, config[CONF_ESPHOME], domain='esphome')
    for domain in PRE_INITIALIZE:
        if domain == CONF_ESPHOME or domain not in config:
            continue
        CORE.add_job(get_component(domain).to_code,
                     config[domain],
                     domain=domain)

    for domain, component, conf in iter_components(config):
        if domain in PRE_INITIALIZE or not hasattr(component, 'to_code'):
            continue
        CORE.add_job(component.to_code, conf, domain=domain)

    CORE.flush_tasks()
    add(RawStatement(''))
    add(RawStatement(''))
    all_code = []
    for exp in CORE.expressions:
        if not config[CONF_ESPHOME][CONF_USE_CUSTOM_CODE]:
            if isinstance(exp, Expression) and not exp.required:
                continue
        all_code.append(text_type(statement(exp)))

    writer.write_platformio_project()

    code_s = indent('\n'.join(line.rstrip() for line in all_code))
    writer.write_cpp(code_s)
    return 0
コード例 #6
0
ファイル: storage_json.py プロジェクト: zinefer/esphome
 def get_default():  # type: () -> EsphomeStorageJSON
     return EsphomeStorageJSON(
         storage_version=1,
         cookie_secret=text_type(binascii.hexlify(os.urandom(64))),
         last_update_check=None,
         remote_version=None,
     )
コード例 #7
0
def read_config(args):
    while True:
        CORE.reset()
        data = json.loads(safe_input())
        assert data['type'] == 'validate'
        CORE.vscode = True
        CORE.ace = args.ace
        f = data['file']
        if CORE.ace:
            CORE.config_path = os.path.join(args.configuration[0], f)
        else:
            CORE.config_path = data['file']
        vs = VSCodeResult()
        try:
            res = load_config()
        except Exception as err:  # pylint: disable=broad-except
            vs.add_yaml_error(text_type(err))
        else:
            for err in res.errors:
                try:
                    range_ = _get_invalid_range(res, err)
                    vs.add_validation_error(range_,
                                            _format_vol_invalid(err, res))
                except Exception:  # pylint: disable=broad-except
                    continue
        print(vs.dump())
コード例 #8
0
def preload_core_config(config):
    if 'esphomeyaml' in config:
        _LOGGER.warning(
            "The esphomeyaml section has been renamed to esphome in 1.11.0. "
            "Please replace 'esphomeyaml:' in your configuration with 'esphome:'."
        )
        config[CONF_ESPHOME] = config.pop('esphomeyaml')
    if CONF_ESPHOME not in config:
        raise EsphomeError(u"No esphome section in config")
    core_conf = config[CONF_ESPHOME]
    if CONF_PLATFORM not in core_conf:
        raise EsphomeError("esphome.platform not specified.")
    if CONF_BOARD not in core_conf:
        raise EsphomeError("esphome.board not specified.")
    if CONF_NAME not in core_conf:
        raise EsphomeError("esphome.name not specified.")

    try:
        CORE.esp_platform = validate_platform(core_conf[CONF_PLATFORM])
        CORE.board = validate_board(core_conf[CONF_BOARD])
        CORE.name = cv.valid_name(core_conf[CONF_NAME])
        CORE.build_path = CORE.relative_path(
            cv.string(core_conf.get(CONF_BUILD_PATH, default_build_path())))
    except vol.Invalid as e:
        raise EsphomeError(text_type(e))
コード例 #9
0
 def __str__(self):
     if self.i > 4294967295:
         return u'{}ULL'.format(self.i)
     if self.i > 2147483647:
         return u'{}UL'.format(self.i)
     if self.i < -2147483648:
         return u'{}LL'.format(self.i)
     return text_type(self.i)
コード例 #10
0
def _secret_yaml(loader, node):
    """Load secrets and embed it into the configuration YAML."""
    secret_path = os.path.join(os.path.dirname(loader.name), SECRET_YAML)
    secrets = _load_yaml_internal(secret_path)
    if node.value not in secrets:
        raise EsphomeError(u"Secret {} not defined".format(node.value))
    val = secrets[node.value]
    _SECRET_VALUES[text_type(val)] = node.value
    return val
コード例 #11
0
    def cpp_global_section(self):
        from esphome.cpp_generator import statement

        global_code = []
        for exp in self.global_statements:
            text = text_type(statement(exp))
            text = text.rstrip()
            global_code.append(text)
        return u'\n'.join(global_code) + u'\n'
コード例 #12
0
ファイル: yaml_util.py プロジェクト: zinefer/esphome
 def construct_secret(self, node):
     secrets = _load_yaml_internal(self._rel_path(SECRET_YAML))
     if node.value not in secrets:
         raise yaml.MarkedYAMLError(
             context=u"Secret '{}' not defined".format(node.value),
             context_mark=node.start_mark)
     val = secrets[node.value]
     _SECRET_VALUES[text_type(val)] = node.value
     return val
コード例 #13
0
def humanize_error(config, validation_error):
    validation_error = text_type(validation_error)
    m = re.match(r'^(.*?)\s*(?:for dictionary value )?@ data\[.*$',
                 validation_error)
    if m is not None:
        validation_error = m.group(1)
    validation_error = validation_error.strip()
    if not validation_error.endswith(u'.'):
        validation_error += u'.'
    return validation_error
コード例 #14
0
ファイル: config_validation.py プロジェクト: zinefer/esphome
def string_strict(value):
    """Like string, but only allows strings, and does not automatically convert other types to
    strings."""
    check_not_templatable(value)
    if isinstance(value, text_type):
        return value
    if isinstance(value, string_types):
        return text_type(value)
    raise Invalid("Must be string, got {}. did you forget putting quotes "
                  "around the value?".format(type(value)))
コード例 #15
0
ファイル: sensor.py プロジェクト: timpur/esphome-components
def validate_enum(enum_values, units=None, int=True):
    _units = []
    if units is not None:
        _units = units if isinstance(units, list) else [units]
        _units = [text_type(x) for x in _units]
    enum_bound = cv.enum(enum_values, int=int)

    def validate_enum_bound(value):
        value = cv.string(value)
        for unit in _units:
            if value.endswith(unit):
                value = value[:-len(unit)]
                break
        return enum_bound(value)
    return validate_enum_bound
コード例 #16
0
def _format_vol_invalid(ex, config):
    # type: (vol.Invalid, Config) -> unicode
    message = u''

    paren = _get_parent_name(ex.path[:-1], config)

    if isinstance(ex, ExtraKeysInvalid):
        if ex.candidates:
            message += u'[{}] is an invalid option for [{}]. Did you mean {}?'.format(
                ex.path[-1], paren,
                u', '.join(u'[{}]'.format(x) for x in ex.candidates))
        else:
            message += u'[{}] is an invalid option for [{}]. Please check the indentation.'.format(
                ex.path[-1], paren)
    elif u'extra keys not allowed' in text_type(ex):
        message += u'[{}] is an invalid option for [{}].'.format(
            ex.path[-1], paren)
    elif u'required key not provided' in text_type(ex):
        message += u"'{}' is a required option for [{}].".format(
            ex.path[-1], paren)
    else:
        message += humanize_error(config, ex)

    return message
コード例 #17
0
ファイル: config.py プロジェクト: liuse2ee/esphome-tools-dc1
def humanize_error(config, validation_error):
    offending_item_summary = _nested_getitem(config, validation_error.path)
    if isinstance(offending_item_summary, dict):
        offending_item_summary = None
    validation_error = text_type(validation_error)
    m = re.match(r'^(.*?)\s*(?:for dictionary value )?@ data\[.*$',
                 validation_error)
    if m is not None:
        validation_error = m.group(1)
    validation_error = validation_error.strip()
    if not validation_error.endswith(u'.'):
        validation_error += u'.'
    if offending_item_summary is None or is_secret(offending_item_summary):
        return validation_error

    return u"{} Got '{}'".format(validation_error, offending_item_summary)
コード例 #18
0
def string(value):
    """Validate that a configuration value is a string. If not, automatically converts to a string.

    Note that this can be lossy, for example the input value 60.00 (float) will be turned into
    "60.0" (string). For values where this could be a problem `string_string` has to be used.
    """
    check_not_templatable(value)
    if isinstance(value, (dict, list)):
        raise Invalid("string value cannot be dictionary or list.")
    if isinstance(value, bool):
        raise Invalid("Auto-converted this value to boolean, please wrap the value in quotes.")
    if isinstance(value, text_type):
        return value
    if value is not None:
        return text_type(value)
    raise Invalid("string value is None")
コード例 #19
0
    def _send_message(self, msg):
        # type: (message.Message) -> None
        for message_type, klass in MESSAGE_TYPE_TO_PROTO.items():
            if isinstance(msg, klass):
                break
        else:
            raise ValueError

        encoded = msg.SerializeToString()
        _LOGGER.debug("Sending %s:\n%s", type(msg), indent(text_type(msg)))
        if IS_PY2:
            req = chr(0x00)
        else:
            req = bytes([0])
        req += _varuint_to_bytes(len(encoded))
        req += _varuint_to_bytes(message_type)
        req += encoded
        self._write(req)
コード例 #20
0
ファイル: yaml_util.py プロジェクト: zinefer/esphome
 def represent_float(self, value):
     if is_secret(value):
         return self.represent_secret(value)
     if math.isnan(value):
         value = u'.nan'
     elif math.isinf(value):
         value = u'.inf' if value > 0 else u'-.inf'
     else:
         value = text_type(repr(value)).lower()
         # Note that in some cases `repr(data)` represents a float number
         # without the decimal parts.  For instance:
         #   >>> repr(1e17)
         #   '1e17'
         # Unfortunately, this is not a valid float representation according
         # to the definition of the `!!float` tag.  We fix this by adding
         # '.0' before the 'e' symbol.
         if u'.' not in value and u'e' in value:
             value = value.replace(u'e', u'.0e', 1)
     return self.represent_scalar(tag=u'tag:yaml.org,2002:float',
                                  value=value)
コード例 #21
0
ファイル: cpp_helpers.py プロジェクト: zinefer/esphome
def register_component(var, config):
    """Register the given obj as a component.

    This is a coroutine, you must await it with a 'yield' expression!

    :param var: The variable representing the component.
    :param config: The configuration for the component.
    """
    id_ = text_type(var.base)
    if id_ not in CORE.component_ids:
        raise ValueError(
            u"Component ID {} was not declared to inherit from Component, "
            u"or was registered twice. Please create a bug report with your "
            u"configuration.".format(id_))
    CORE.component_ids.remove(id_)
    if CONF_SETUP_PRIORITY in config:
        add(var.set_setup_priority(config[CONF_SETUP_PRIORITY]))
    if CONF_UPDATE_INTERVAL in config:
        add(var.set_update_interval(config[CONF_UPDATE_INTERVAL]))
    add(App.register_component(var))
    yield var
コード例 #22
0
 def __str__(self):
     text = u", ".join(text_type(x) for x in self.args)
     return indent_all_but_first_and_last(text)
コード例 #23
0
def strip_accents(value):
    return u''.join(c for c in unicodedata.normalize('NFD', text_type(value))
                    if unicodedata.category(c) != 'Mn')
コード例 #24
0
def dump_dict(config, path, at_root=True):
    # type: (Config, ConfigPath, bool) -> Tuple[unicode, bool]
    conf = config.get_nested_item(path)
    ret = u''
    multiline = False

    if at_root:
        error = config.get_error_for_path(path)
        if error is not None:
            ret += u'\n' + color('bold_red', _format_vol_invalid(
                error, config)) + u'\n'

    if isinstance(conf, (list, tuple)):
        multiline = True
        if not conf:
            ret += u'[]'
            multiline = False

        for i in range(len(conf)):
            path_ = path + [i]
            error = config.get_error_for_path(path_)
            if error is not None:
                ret += u'\n' + color(
                    'bold_red', _format_vol_invalid(error, config)) + u'\n'

            sep = u'- '
            if config.is_in_error_path(path_):
                sep = color('red', sep)
            msg, _ = dump_dict(config, path_, at_root=False)
            msg = indent(msg)
            inf = line_info(config.get_nested_item(path_),
                            highlight=config.is_in_error_path(path_))
            if inf is not None:
                msg = inf + u'\n' + msg
            elif msg:
                msg = msg[2:]
            ret += sep + msg + u'\n'
    elif isinstance(conf, dict):
        multiline = True
        if not conf:
            ret += u'{}'
            multiline = False

        for k in conf.keys():
            path_ = path + [k]
            error = config.get_error_for_path(path_)
            if error is not None:
                ret += u'\n' + color(
                    'bold_red', _format_vol_invalid(error, config)) + u'\n'

            st = u'{}: '.format(k)
            if config.is_in_error_path(path_):
                st = color('red', st)
            msg, m = dump_dict(config, path_, at_root=False)

            inf = line_info(config.get_nested_item(path_),
                            highlight=config.is_in_error_path(path_))
            if m:
                msg = u'\n' + indent(msg)

            if inf is not None:
                if m:
                    msg = u' ' + inf + msg
                else:
                    msg = msg + u' ' + inf
            ret += st + msg + u'\n'
    elif isinstance(conf, str):
        if is_secret(conf):
            conf = u'!secret {}'.format(is_secret(conf))
        if not conf:
            conf += u"''"

        if len(conf) > 80:
            conf = u'|-\n' + indent(conf)
        error = config.get_error_for_path(path)
        col = 'bold_red' if error else 'white'
        ret += color(col, text_type(conf))
    elif isinstance(conf, core.Lambda):
        if is_secret(conf):
            conf = u'!secret {}'.format(is_secret(conf))

        conf = u'!lambda |-\n' + indent(text_type(conf.value))
        error = config.get_error_for_path(path)
        col = 'bold_red' if error else 'white'
        ret += color(col, conf)
    elif conf is None:
        pass
    else:
        error = config.get_error_for_path(path)
        col = 'bold_red' if error else 'white'
        ret += color(col, text_type(conf))
        multiline = u'\n' in ret

    return ret, multiline
コード例 #25
0
def validate_config(config):
    result = Config()

    # 1. Load substitutions
    if CONF_SUBSTITUTIONS in config:
        result[CONF_SUBSTITUTIONS] = config[CONF_SUBSTITUTIONS]
        result.add_output_path([CONF_SUBSTITUTIONS], CONF_SUBSTITUTIONS)
        try:
            substitutions.do_substitution_pass(config)
        except vol.Invalid as err:
            result.add_error(err)
            return result

    if 'esphomeyaml' in config:
        _LOGGER.warning(
            "The esphomeyaml section has been renamed to esphome in 1.11.0. "
            "Please replace 'esphomeyaml:' in your configuration with 'esphome:'."
        )
        config[CONF_ESPHOME] = config.pop('esphomeyaml')

    if CONF_ESPHOME not in config:
        result.add_str_error(
            "'esphome' section missing from configuration. Please make sure "
            "your configuration has an 'esphome:' line in it.", [])
        return result

    # 2. Load partial core config
    result[CONF_ESPHOME] = config[CONF_ESPHOME]
    result.add_output_path([CONF_ESPHOME], CONF_ESPHOME)
    try:
        core_config.preload_core_config(config)
    except vol.Invalid as err:
        result.add_error(err)
        return result
    # Remove temporary esphome config path again, it will be reloaded later
    result.remove_output_path([CONF_ESPHOME], CONF_ESPHOME)

    # 3. Load components.
    # Load components (also AUTO_LOAD) and set output paths of result
    # Queue of items to load, FIFO
    load_queue = collections.deque()
    for domain, conf in config.items():
        load_queue.append((domain, conf))

    # List of items to enter next stage
    check_queue = [
    ]  # type: List[Tuple[ConfigPath, str, ConfigType, ComponentManifest]]

    # This step handles:
    # - Adding output path
    # - Auto Load
    # - Loading configs into result

    while load_queue:
        domain, conf = load_queue.popleft()
        domain = text_type(domain)
        if domain.startswith(u'.'):
            # Ignore top-level keys starting with a dot
            continue
        result.add_output_path([domain], domain)
        result[domain] = conf
        component = get_component(domain)
        path = [domain]
        if component is None:
            result.add_str_error(u"Component not found: {}".format(domain),
                                 path)
            continue
        CORE.loaded_integrations.add(domain)

        # Process AUTO_LOAD
        for load in component.auto_load:
            if load not in config:
                load_conf = core.AutoLoad()
                config[load] = load_conf
                load_queue.append((load, load_conf))

        if not component.is_platform_component:
            check_queue.append(([domain], domain, conf, component))
            continue

        # This is a platform component, proceed to reading platform entries
        # Remove this is as an output path
        result.remove_output_path([domain], domain)

        # Ensure conf is a list
        if not conf:
            result[domain] = conf = []
        elif not isinstance(conf, list):
            result[domain] = conf = [conf]

        for i, p_config in enumerate(conf):
            path = [domain, i]
            # Construct temporary unknown output path
            p_domain = u'{}.unknown'.format(domain)
            result.add_output_path(path, p_domain)
            result[domain][i] = p_config
            if not isinstance(p_config, dict):
                result.add_str_error(
                    u"Platform schemas must be key-value pairs.", path)
                continue
            p_name = p_config.get('platform')
            if p_name is None:
                result.add_str_error(
                    u"No platform specified! See 'platform' key.", path)
                continue
            # Remove temp output path and construct new one
            result.remove_output_path(path, p_domain)
            p_domain = u'{}.{}'.format(domain, p_name)
            result.add_output_path(path, p_domain)
            # Try Load platform
            platform = get_platform(domain, p_name)
            if platform is None:
                result.add_str_error(
                    u"Platform not found: '{}'".format(p_domain), path)
                continue
            CORE.loaded_integrations.add(p_name)

            # Process AUTO_LOAD
            for load in platform.auto_load:
                if load not in config:
                    load_conf = core.AutoLoad()
                    config[load] = load_conf
                    load_queue.append((load, load_conf))

            check_queue.append((path, p_domain, p_config, platform))

    # 4. Validate component metadata, including
    # - Transformation (nullable, multi conf)
    # - Dependencies
    # - Conflicts
    # - Supported ESP Platform

    # List of items to proceed to next stage
    validate_queue = [
    ]  # type: List[Tuple[ConfigPath, ConfigType, ComponentManifest]]
    for path, domain, conf, comp in check_queue:
        if conf is None:
            result[domain] = conf = {}

        success = True
        for dependency in comp.dependencies:
            if dependency not in config:
                result.add_str_error(
                    u"Component {} requires component {}"
                    u"".format(domain, dependency), path)
                success = False
        if not success:
            continue

        success = True
        for conflict in comp.conflicts_with:
            if conflict in config:
                result.add_str_error(
                    u"Component {} cannot be used together with component {}"
                    u"".format(domain, conflict), path)
                success = False
        if not success:
            continue

        if CORE.esp_platform not in comp.esp_platforms:
            result.add_str_error(
                u"Component {} doesn't support {}.".format(
                    domain, CORE.esp_platform), path)
            continue

        if not comp.is_platform_component and comp.config_schema is None and \
                not isinstance(conf, core.AutoLoad):
            result.add_str_error(
                u"Component {} cannot be loaded via YAML "
                u"(no CONFIG_SCHEMA).".format(domain), path)
            continue

        if comp.is_multi_conf:
            if not isinstance(conf, list):
                result[domain] = conf = [conf]
            for i, part_conf in enumerate(conf):
                validate_queue.append((path + [i], part_conf, comp))
            continue

        validate_queue.append((path, conf, comp))

    # 5. Validate configuration schema
    for path, conf, comp in validate_queue:
        if comp.config_schema is None:
            continue
        with result.catch_error(path):
            if comp.is_platform:
                # Remove 'platform' key for validation
                input_conf = OrderedDict(conf)
                platform_val = input_conf.pop('platform')
                validated = comp.config_schema(input_conf)
                # Ensure result is OrderedDict so we can call move_to_end
                if not isinstance(validated, OrderedDict):
                    validated = OrderedDict(validated)
                validated['platform'] = platform_val
                validated.move_to_end('platform', last=False)
                result.set_by_path(path, validated)
            else:
                validated = comp.config_schema(conf)
                result.set_by_path(path, validated)

    # 6. If no validation errors, check IDs
    if not result.errors:
        # Only parse IDs if no validation error. Otherwise
        # user gets confusing messages
        do_id_pass(result)
    return result
コード例 #26
0
def do_id_pass(result):  # type: (Config) -> None
    from esphome.cpp_generator import MockObjClass
    from esphome.cpp_types import Component

    declare_ids = []  # type: List[Tuple[core.ID, ConfigPath]]
    searching_ids = []  # type: List[Tuple[core.ID, ConfigPath]]
    for id, path in iter_ids(result):
        if id.is_declaration:
            if id.id is not None:
                # Look for duplicate definitions
                match = next((v for v in declare_ids if v[0].id == id.id),
                             None)
                if match is not None:
                    opath = u'->'.join(text_type(v) for v in match[1])
                    result.add_str_error(
                        u"ID {} redefined! Check {}".format(id.id, opath),
                        path)
                    continue
            declare_ids.append((id, path))
        else:
            searching_ids.append((id, path))
    # Resolve default ids after manual IDs
    for id, _ in declare_ids:
        id.resolve([v[0].id for v in declare_ids])
        if isinstance(id.type,
                      MockObjClass) and id.type.inherits_from(Component):
            CORE.component_ids.add(id.id)

    # Check searched IDs
    for id, path in searching_ids:
        if id.id is not None:
            # manually declared
            match = next((v[0] for v in declare_ids if v[0].id == id.id), None)
            if match is None:
                # No declared ID with this name
                import difflib
                error = (
                    "Couldn't find ID '{}'. Please check you have defined "
                    "an ID with that name in your configuration.".format(
                        id.id))
                # Find candidates
                matches = difflib.get_close_matches(
                    id.id, [v[0].id for v in declare_ids])
                if matches:
                    matches_s = ', '.join('"{}"'.format(x) for x in matches)
                    error += " These IDs look similar: {}.".format(matches_s)
                result.add_str_error(error, path)
                continue
            if not isinstance(match.type, MockObjClass) or not isinstance(
                    id.type, MockObjClass):
                continue
            if not match.type.inherits_from(id.type):
                result.add_str_error(
                    "ID '{}' of type {} doesn't inherit from {}. Please "
                    "double check your ID is pointing to the correct value"
                    "".format(id.id, match.type, id.type), path)

        if id.id is None and id.type is not None:
            for v in declare_ids:
                if v[0] is None or not isinstance(v[0].type, MockObjClass):
                    continue
                inherits = v[0].type.inherits_from(id.type)
                if inherits:
                    id.id = v[0].id
                    break
            else:
                result.add_str_error(
                    "Couldn't resolve ID for type '{}'".format(id.type), path)
コード例 #27
0
def represent_secret(value):
    return yaml.ScalarNode(tag=u'!secret',
                           value=_SECRET_VALUES[text_type(value)])
コード例 #28
0
def _lambda(loader, node):
    return Lambda(text_type(node.value))
コード例 #29
0
def is_secret(value):
    try:
        return _SECRET_VALUES[text_type(value)]
    except (KeyError, ValueError):
        return None
コード例 #30
0
ファイル: config.py プロジェクト: liuse2ee/esphome-tools-dc1
 def add_error(self, message, path):
     # type: (basestring, ConfigPath) -> None
     if not isinstance(message, text_type):
         message = text_type(message)
     self.errors.append((message, path))