mirror of
https://github.com/esphome/esphome.git
synced 2025-09-06 05:12:21 +01:00
Drop Python 2 Support (#793)
* Remove Python 2 support * Remove u-strings * Remove docker symlinks * Remove from travis * Update requirements * Upgrade flake8/pylint * Fixes * Manual * Run pyupgrade * Lint * Remove base_int * Fix * Update platformio_api.py * Update component.cpp
This commit is contained in:
@@ -1,6 +1,4 @@
|
||||
# coding=utf-8
|
||||
"""Helpers for config validation using voluptuous."""
|
||||
from __future__ import print_function
|
||||
|
||||
import logging
|
||||
import os
|
||||
@@ -20,7 +18,6 @@ from esphome.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOVERY,
|
||||
from esphome.core import CORE, HexInt, IPAddress, Lambda, TimePeriod, TimePeriodMicroseconds, \
|
||||
TimePeriodMilliseconds, TimePeriodSeconds, TimePeriodMinutes
|
||||
from esphome.helpers import list_starts_with, add_class_to_obj
|
||||
from esphome.py_compat import integer_types, string_types, text_type, IS_PY2, decode_text
|
||||
from esphome.voluptuous_schema import _Schema
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@@ -43,7 +40,7 @@ ALLOW_EXTRA = vol.ALLOW_EXTRA
|
||||
UNDEFINED = vol.UNDEFINED
|
||||
RequiredFieldInvalid = vol.RequiredFieldInvalid
|
||||
|
||||
ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_'
|
||||
ALLOWED_NAME_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789_'
|
||||
|
||||
RESERVED_IDS = [
|
||||
# C++ keywords http://en.cppreference.com/w/cpp/keyword
|
||||
@@ -82,7 +79,7 @@ class Optional(vol.Optional):
|
||||
"""
|
||||
|
||||
def __init__(self, key, default=UNDEFINED):
|
||||
super(Optional, self).__init__(key, default=default)
|
||||
super().__init__(key, default=default)
|
||||
|
||||
|
||||
class Required(vol.Required):
|
||||
@@ -94,7 +91,7 @@ class Required(vol.Required):
|
||||
"""
|
||||
|
||||
def __init__(self, key):
|
||||
super(Required, self).__init__(key)
|
||||
super().__init__(key)
|
||||
|
||||
|
||||
def check_not_templatable(value):
|
||||
@@ -105,7 +102,7 @@ def check_not_templatable(value):
|
||||
def alphanumeric(value):
|
||||
if value is None:
|
||||
raise Invalid("string value is None")
|
||||
value = text_type(value)
|
||||
value = str(value)
|
||||
if not value.isalnum():
|
||||
raise Invalid("string value is not alphanumeric")
|
||||
return value
|
||||
@@ -115,8 +112,8 @@ def valid_name(value):
|
||||
value = string_strict(value)
|
||||
for c in value:
|
||||
if c not in ALLOWED_NAME_CHARS:
|
||||
raise Invalid(u"'{}' is an invalid character for names. Valid characters are: {}"
|
||||
u" (lowercase, no spaces)".format(c, ALLOWED_NAME_CHARS))
|
||||
raise Invalid(f"'{c}' is an invalid character for names. Valid characters are: "
|
||||
f"{ALLOWED_NAME_CHARS} (lowercase, no spaces)")
|
||||
return value
|
||||
|
||||
|
||||
@@ -131,10 +128,10 @@ def string(value):
|
||||
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):
|
||||
if isinstance(value, str):
|
||||
return value
|
||||
if value is not None:
|
||||
return text_type(value)
|
||||
return str(value)
|
||||
raise Invalid("string value is None")
|
||||
|
||||
|
||||
@@ -142,10 +139,8 @@ 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):
|
||||
if isinstance(value, str):
|
||||
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)))
|
||||
|
||||
@@ -172,14 +167,14 @@ def boolean(value):
|
||||
check_not_templatable(value)
|
||||
if isinstance(value, bool):
|
||||
return value
|
||||
if isinstance(value, string_types):
|
||||
if isinstance(value, str):
|
||||
value = value.lower()
|
||||
if value in ('true', 'yes', 'on', 'enable'):
|
||||
return True
|
||||
if value in ('false', 'no', 'off', 'disable'):
|
||||
return False
|
||||
raise Invalid(u"Expected boolean value, but cannot convert {} to a boolean. "
|
||||
u"Please use 'true' or 'false'".format(value))
|
||||
raise Invalid("Expected boolean value, but cannot convert {} to a boolean. "
|
||||
"Please use 'true' or 'false'".format(value))
|
||||
|
||||
|
||||
def ensure_list(*validators):
|
||||
@@ -228,7 +223,7 @@ def int_(value):
|
||||
Automatically also converts strings to ints.
|
||||
"""
|
||||
check_not_templatable(value)
|
||||
if isinstance(value, integer_types):
|
||||
if isinstance(value, int):
|
||||
return value
|
||||
if isinstance(value, float):
|
||||
if int(value) == value:
|
||||
@@ -242,15 +237,15 @@ def int_(value):
|
||||
try:
|
||||
return int(value, base)
|
||||
except ValueError:
|
||||
raise Invalid(u"Expected integer, but cannot parse {} as an integer".format(value))
|
||||
raise Invalid(f"Expected integer, but cannot parse {value} as an integer")
|
||||
|
||||
|
||||
def int_range(min=None, max=None, min_included=True, max_included=True):
|
||||
"""Validate that the config option is an integer in the given range."""
|
||||
if min is not None:
|
||||
assert isinstance(min, integer_types)
|
||||
assert isinstance(min, int)
|
||||
if max is not None:
|
||||
assert isinstance(max, integer_types)
|
||||
assert isinstance(max, int)
|
||||
return All(int_, Range(min=min, max=max, min_included=min_included, max_included=max_included))
|
||||
|
||||
|
||||
@@ -291,14 +286,14 @@ def validate_id_name(value):
|
||||
valid_chars = ascii_letters + digits + '_'
|
||||
for char in value:
|
||||
if char not in valid_chars:
|
||||
raise Invalid(u"IDs must only consist of upper/lowercase characters, the underscore"
|
||||
u"character and numbers. The character '{}' cannot be used"
|
||||
u"".format(char))
|
||||
raise Invalid("IDs must only consist of upper/lowercase characters, the underscore"
|
||||
"character and numbers. The character '{}' cannot be used"
|
||||
"".format(char))
|
||||
if value in RESERVED_IDS:
|
||||
raise Invalid(u"ID '{}' is reserved internally and cannot be used".format(value))
|
||||
raise Invalid(f"ID '{value}' is reserved internally and cannot be used")
|
||||
if value in CORE.loaded_integrations:
|
||||
raise Invalid(u"ID '{}' conflicts with the name of an esphome integration, please use "
|
||||
u"another ID name.".format(value))
|
||||
raise Invalid("ID '{}' conflicts with the name of an esphome integration, please use "
|
||||
"another ID name.".format(value))
|
||||
return value
|
||||
|
||||
|
||||
@@ -358,7 +353,7 @@ def only_on(platforms):
|
||||
|
||||
def validator_(obj):
|
||||
if CORE.esp_platform not in platforms:
|
||||
raise Invalid(u"This feature is only available on {}".format(platforms))
|
||||
raise Invalid(f"This feature is only available on {platforms}")
|
||||
return obj
|
||||
|
||||
return validator_
|
||||
@@ -463,7 +458,7 @@ def time_period_str_unit(value):
|
||||
"'{0}s'?".format(value))
|
||||
if isinstance(value, TimePeriod):
|
||||
value = str(value)
|
||||
if not isinstance(value, string_types):
|
||||
if not isinstance(value, str):
|
||||
raise Invalid("Expected string for time period with unit.")
|
||||
|
||||
unit_to_kwarg = {
|
||||
@@ -485,8 +480,8 @@ def time_period_str_unit(value):
|
||||
match = re.match(r"^([-+]?[0-9]*\.?[0-9]*)\s*(\w*)$", value)
|
||||
|
||||
if match is None:
|
||||
raise Invalid(u"Expected time period with unit, "
|
||||
u"got {}".format(value))
|
||||
raise Invalid("Expected time period with unit, "
|
||||
"got {}".format(value))
|
||||
kwarg = unit_to_kwarg[one_of(*unit_to_kwarg)(match.group(2))]
|
||||
|
||||
return TimePeriod(**{kwarg: float(match.group(1))})
|
||||
@@ -545,7 +540,7 @@ def time_of_day(value):
|
||||
try:
|
||||
date = datetime.strptime(value, '%H:%M:%S %p')
|
||||
except ValueError:
|
||||
raise Invalid("Invalid time of day: {}".format(err))
|
||||
raise Invalid(f"Invalid time of day: {err}")
|
||||
|
||||
return {
|
||||
CONF_HOUR: date.hour,
|
||||
@@ -577,7 +572,7 @@ def uuid(value):
|
||||
|
||||
METRIC_SUFFIXES = {
|
||||
'E': 1e18, 'P': 1e15, 'T': 1e12, 'G': 1e9, 'M': 1e6, 'k': 1e3, 'da': 10, 'd': 1e-1,
|
||||
'c': 1e-2, 'm': 0.001, u'µ': 1e-6, 'u': 1e-6, 'n': 1e-9, 'p': 1e-12, 'f': 1e-15, 'a': 1e-18,
|
||||
'c': 1e-2, 'm': 0.001, 'µ': 1e-6, 'u': 1e-6, 'n': 1e-9, 'p': 1e-12, 'f': 1e-15, 'a': 1e-18,
|
||||
'': 1
|
||||
}
|
||||
|
||||
@@ -594,11 +589,11 @@ def float_with_unit(quantity, regex_suffix, optional_unit=False):
|
||||
match = pattern.match(string(value))
|
||||
|
||||
if match is None:
|
||||
raise Invalid(u"Expected {} with unit, got {}".format(quantity, value))
|
||||
raise Invalid(f"Expected {quantity} with unit, got {value}")
|
||||
|
||||
mantissa = float(match.group(1))
|
||||
if match.group(2) not in METRIC_SUFFIXES:
|
||||
raise Invalid(u"Invalid {} suffix {}".format(quantity, match.group(2)))
|
||||
raise Invalid("Invalid {} suffix {}".format(quantity, match.group(2)))
|
||||
|
||||
multiplier = METRIC_SUFFIXES[match.group(2)]
|
||||
return mantissa * multiplier
|
||||
@@ -606,30 +601,17 @@ def float_with_unit(quantity, regex_suffix, optional_unit=False):
|
||||
return validator
|
||||
|
||||
|
||||
frequency = float_with_unit("frequency", u"(Hz|HZ|hz)?")
|
||||
resistance = float_with_unit("resistance", u"(Ω|Ω|ohm|Ohm|OHM)?")
|
||||
current = float_with_unit("current", u"(a|A|amp|Amp|amps|Amps|ampere|Ampere)?")
|
||||
voltage = float_with_unit("voltage", u"(v|V|volt|Volts)?")
|
||||
distance = float_with_unit("distance", u"(m)")
|
||||
framerate = float_with_unit("framerate", u"(FPS|fps|Fps|FpS|Hz)")
|
||||
angle = float_with_unit("angle", u"(°|deg)", optional_unit=True)
|
||||
_temperature_c = float_with_unit("temperature", u"(°C|° C|°|C)?")
|
||||
_temperature_k = float_with_unit("temperature", u"(° K|° K|K)?")
|
||||
_temperature_f = float_with_unit("temperature", u"(°F|° F|F)?")
|
||||
decibel = float_with_unit("decibel", u"(dB|dBm|db|dbm)", optional_unit=True)
|
||||
|
||||
if IS_PY2:
|
||||
# Override voluptuous invalid to unicode for py2
|
||||
def _vol_invalid_unicode(self):
|
||||
path = u' @ data[%s]' % u']['.join(map(repr, self.path)) \
|
||||
if self.path else u''
|
||||
# pylint: disable=no-member
|
||||
output = decode_text(self.message)
|
||||
if self.error_type:
|
||||
output += u' for ' + self.error_type
|
||||
return output + path
|
||||
|
||||
Invalid.__unicode__ = _vol_invalid_unicode
|
||||
frequency = float_with_unit("frequency", "(Hz|HZ|hz)?")
|
||||
resistance = float_with_unit("resistance", "(Ω|Ω|ohm|Ohm|OHM)?")
|
||||
current = float_with_unit("current", "(a|A|amp|Amp|amps|Amps|ampere|Ampere)?")
|
||||
voltage = float_with_unit("voltage", "(v|V|volt|Volts)?")
|
||||
distance = float_with_unit("distance", "(m)")
|
||||
framerate = float_with_unit("framerate", "(FPS|fps|Fps|FpS|Hz)")
|
||||
angle = float_with_unit("angle", "(°|deg)", optional_unit=True)
|
||||
_temperature_c = float_with_unit("temperature", "(°C|° C|°|C)?")
|
||||
_temperature_k = float_with_unit("temperature", "(° K|° K|K)?")
|
||||
_temperature_f = float_with_unit("temperature", "(°F|° F|F)?")
|
||||
decibel = float_with_unit("decibel", "(dB|dBm|db|dbm)", optional_unit=True)
|
||||
|
||||
|
||||
def temperature(value):
|
||||
@@ -672,15 +654,15 @@ def validate_bytes(value):
|
||||
match = re.match(r"^([0-9]+)\s*(\w*?)(?:byte|B|b)?s?$", value)
|
||||
|
||||
if match is None:
|
||||
raise Invalid(u"Expected number of bytes with unit, got {}".format(value))
|
||||
raise Invalid(f"Expected number of bytes with unit, got {value}")
|
||||
|
||||
mantissa = int(match.group(1))
|
||||
if match.group(2) not in METRIC_SUFFIXES:
|
||||
raise Invalid(u"Invalid metric suffix {}".format(match.group(2)))
|
||||
raise Invalid("Invalid metric suffix {}".format(match.group(2)))
|
||||
multiplier = METRIC_SUFFIXES[match.group(2)]
|
||||
if multiplier < 1:
|
||||
raise Invalid(u"Only suffixes with positive exponents are supported. "
|
||||
u"Got {}".format(match.group(2)))
|
||||
raise Invalid("Only suffixes with positive exponents are supported. "
|
||||
"Got {}".format(match.group(2)))
|
||||
return int(mantissa * multiplier)
|
||||
|
||||
|
||||
@@ -701,7 +683,7 @@ def domain(value):
|
||||
try:
|
||||
return str(ipv4(value))
|
||||
except Invalid:
|
||||
raise Invalid("Invalid domain: {}".format(value))
|
||||
raise Invalid(f"Invalid domain: {value}")
|
||||
|
||||
|
||||
def domain_name(value):
|
||||
@@ -730,7 +712,7 @@ def ssid(value):
|
||||
def ipv4(value):
|
||||
if isinstance(value, list):
|
||||
parts = value
|
||||
elif isinstance(value, string_types):
|
||||
elif isinstance(value, str):
|
||||
parts = value.split('.')
|
||||
elif isinstance(value, IPAddress):
|
||||
return value
|
||||
@@ -806,7 +788,7 @@ def mqtt_qos(value):
|
||||
try:
|
||||
value = int(value)
|
||||
except (TypeError, ValueError):
|
||||
raise Invalid(u"MQTT Quality of Service must be integer, got {}".format(value))
|
||||
raise Invalid(f"MQTT Quality of Service must be integer, got {value}")
|
||||
return one_of(0, 1, 2)(value)
|
||||
|
||||
|
||||
@@ -814,7 +796,7 @@ def requires_component(comp):
|
||||
"""Validate that this option can only be specified when the component `comp` is loaded."""
|
||||
def validator(value):
|
||||
if comp not in CORE.raw_config:
|
||||
raise Invalid("This option requires component {}".format(comp))
|
||||
raise Invalid(f"This option requires component {comp}")
|
||||
return value
|
||||
|
||||
return validator
|
||||
@@ -839,7 +821,7 @@ def percentage(value):
|
||||
|
||||
|
||||
def possibly_negative_percentage(value):
|
||||
has_percent_sign = isinstance(value, string_types) and value.endswith('%')
|
||||
has_percent_sign = isinstance(value, str) and value.endswith('%')
|
||||
if has_percent_sign:
|
||||
value = float(value[:-1].rstrip()) / 100.0
|
||||
if value > 1:
|
||||
@@ -856,7 +838,7 @@ def possibly_negative_percentage(value):
|
||||
|
||||
|
||||
def percentage_int(value):
|
||||
if isinstance(value, string_types) and value.endswith('%'):
|
||||
if isinstance(value, str) and value.endswith('%'):
|
||||
value = int(value[:-1].rstrip())
|
||||
return value
|
||||
|
||||
@@ -916,7 +898,7 @@ def one_of(*values, **kwargs):
|
||||
- *float* (``bool``, default=False): Whether to convert the incoming values to floats.
|
||||
- *space* (``str``, default=' '): What to convert spaces in the input string to.
|
||||
"""
|
||||
options = u', '.join(u"'{}'".format(x) for x in values)
|
||||
options = ', '.join(f"'{x}'" for x in values)
|
||||
lower = kwargs.pop('lower', False)
|
||||
upper = kwargs.pop('upper', False)
|
||||
string_ = kwargs.pop('string', False) or lower or upper
|
||||
@@ -940,13 +922,13 @@ def one_of(*values, **kwargs):
|
||||
value = Upper(value)
|
||||
if value not in values:
|
||||
import difflib
|
||||
options_ = [text_type(x) for x in values]
|
||||
option = text_type(value)
|
||||
options_ = [str(x) for x in values]
|
||||
option = str(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))
|
||||
raise Invalid("Unknown value '{}', did you mean {}?"
|
||||
"".format(value, ", ".join(f"'{x}'" for x in matches)))
|
||||
raise Invalid(f"Unknown value '{value}', valid options are {options}.")
|
||||
return value
|
||||
|
||||
return validator
|
||||
@@ -996,7 +978,7 @@ def returning_lambda(value):
|
||||
Additionally, make sure the lambda returns something.
|
||||
"""
|
||||
value = lambda_(value)
|
||||
if u'return' not in value.value:
|
||||
if 'return' not in value.value:
|
||||
raise Invalid("Lambda doesn't contain a 'return' statement, but the lambda "
|
||||
"is expected to return a value. \n"
|
||||
"Please make sure the lambda contains at least one "
|
||||
@@ -1007,24 +989,23 @@ def returning_lambda(value):
|
||||
def dimensions(value):
|
||||
if isinstance(value, list):
|
||||
if len(value) != 2:
|
||||
raise Invalid(u"Dimensions must have a length of two, not {}".format(len(value)))
|
||||
raise Invalid("Dimensions must have a length of two, not {}".format(len(value)))
|
||||
try:
|
||||
width, height = int(value[0]), int(value[1])
|
||||
except ValueError:
|
||||
raise Invalid(u"Width and height dimensions must be integers")
|
||||
raise Invalid("Width and height dimensions must be integers")
|
||||
if width <= 0 or height <= 0:
|
||||
raise Invalid(u"Width and height must at least be 1")
|
||||
raise Invalid("Width and height must at least be 1")
|
||||
return [width, height]
|
||||
value = string(value)
|
||||
match = re.match(r"\s*([0-9]+)\s*[xX]\s*([0-9]+)\s*", value)
|
||||
if not match:
|
||||
raise Invalid(u"Invalid value '{}' for dimensions. Only WIDTHxHEIGHT is allowed.")
|
||||
raise Invalid("Invalid value '{}' for dimensions. Only WIDTHxHEIGHT is allowed.")
|
||||
return dimensions([match.group(1), match.group(2)])
|
||||
|
||||
|
||||
def directory(value):
|
||||
import json
|
||||
from esphome.py_compat import safe_input
|
||||
value = string(value)
|
||||
path = CORE.relative_config_path(value)
|
||||
|
||||
@@ -1034,25 +1015,24 @@ def directory(value):
|
||||
'type': 'check_directory_exists',
|
||||
'path': path,
|
||||
}))
|
||||
data = json.loads(safe_input())
|
||||
data = json.loads(input())
|
||||
assert data['type'] == 'directory_exists_response'
|
||||
if data['content']:
|
||||
return value
|
||||
raise Invalid(u"Could not find directory '{}'. Please make sure it exists (full path: {})."
|
||||
u"".format(path, os.path.abspath(path)))
|
||||
raise Invalid("Could not find directory '{}'. Please make sure it exists (full path: {})."
|
||||
"".format(path, os.path.abspath(path)))
|
||||
|
||||
if not os.path.exists(path):
|
||||
raise Invalid(u"Could not find directory '{}'. Please make sure it exists (full path: {})."
|
||||
u"".format(path, os.path.abspath(path)))
|
||||
raise Invalid("Could not find directory '{}'. Please make sure it exists (full path: {})."
|
||||
"".format(path, os.path.abspath(path)))
|
||||
if not os.path.isdir(path):
|
||||
raise Invalid(u"Path '{}' is not a directory (full path: {})."
|
||||
u"".format(path, os.path.abspath(path)))
|
||||
raise Invalid("Path '{}' is not a directory (full path: {})."
|
||||
"".format(path, os.path.abspath(path)))
|
||||
return value
|
||||
|
||||
|
||||
def file_(value):
|
||||
import json
|
||||
from esphome.py_compat import safe_input
|
||||
value = string(value)
|
||||
path = CORE.relative_config_path(value)
|
||||
|
||||
@@ -1062,19 +1042,19 @@ def file_(value):
|
||||
'type': 'check_file_exists',
|
||||
'path': path,
|
||||
}))
|
||||
data = json.loads(safe_input())
|
||||
data = json.loads(input())
|
||||
assert data['type'] == 'file_exists_response'
|
||||
if data['content']:
|
||||
return value
|
||||
raise Invalid(u"Could not find file '{}'. Please make sure it exists (full path: {})."
|
||||
u"".format(path, os.path.abspath(path)))
|
||||
raise Invalid("Could not find file '{}'. Please make sure it exists (full path: {})."
|
||||
"".format(path, os.path.abspath(path)))
|
||||
|
||||
if not os.path.exists(path):
|
||||
raise Invalid(u"Could not find file '{}'. Please make sure it exists (full path: {})."
|
||||
u"".format(path, os.path.abspath(path)))
|
||||
raise Invalid("Could not find file '{}'. Please make sure it exists (full path: {})."
|
||||
"".format(path, os.path.abspath(path)))
|
||||
if not os.path.isfile(path):
|
||||
raise Invalid(u"Path '{}' is not a file (full path: {})."
|
||||
u"".format(path, os.path.abspath(path)))
|
||||
raise Invalid("Path '{}' is not a file (full path: {})."
|
||||
"".format(path, os.path.abspath(path)))
|
||||
return value
|
||||
|
||||
|
||||
@@ -1092,7 +1072,7 @@ def entity_id(value):
|
||||
for x in value.split('.'):
|
||||
for c in x:
|
||||
if c not in ENTITY_ID_CHARACTERS:
|
||||
raise Invalid("Invalid character for entity ID: {}".format(c))
|
||||
raise Invalid(f"Invalid character for entity ID: {c}")
|
||||
return value
|
||||
|
||||
|
||||
@@ -1103,9 +1083,9 @@ def extract_keys(schema):
|
||||
assert isinstance(schema, dict)
|
||||
keys = []
|
||||
for skey in list(schema.keys()):
|
||||
if isinstance(skey, string_types):
|
||||
if isinstance(skey, str):
|
||||
keys.append(skey)
|
||||
elif isinstance(skey, vol.Marker) and isinstance(skey.schema, string_types):
|
||||
elif isinstance(skey, vol.Marker) and isinstance(skey.schema, str):
|
||||
keys.append(skey.schema)
|
||||
else:
|
||||
raise ValueError()
|
||||
@@ -1136,14 +1116,14 @@ class GenerateID(Optional):
|
||||
"""Mark this key as being an auto-generated ID key."""
|
||||
|
||||
def __init__(self, key=CONF_ID):
|
||||
super(GenerateID, self).__init__(key, default=lambda: None)
|
||||
super().__init__(key, default=lambda: None)
|
||||
|
||||
|
||||
class SplitDefault(Optional):
|
||||
"""Mark this key to have a split default for ESP8266/ESP32."""
|
||||
|
||||
def __init__(self, key, esp8266=vol.UNDEFINED, esp32=vol.UNDEFINED):
|
||||
super(SplitDefault, self).__init__(key)
|
||||
super().__init__(key)
|
||||
self._esp8266_default = vol.default_factory(esp8266)
|
||||
self._esp32_default = vol.default_factory(esp32)
|
||||
|
||||
@@ -1165,7 +1145,7 @@ class OnlyWith(Optional):
|
||||
"""Set the default value only if the given component is loaded."""
|
||||
|
||||
def __init__(self, key, component, default=None):
|
||||
super(OnlyWith, self).__init__(key)
|
||||
super().__init__(key)
|
||||
self._component = component
|
||||
self._default = vol.default_factory(default)
|
||||
|
||||
@@ -1207,21 +1187,21 @@ def validate_registry_entry(name, registry):
|
||||
ignore_keys = extract_keys(base_schema)
|
||||
|
||||
def validator(value):
|
||||
if isinstance(value, string_types):
|
||||
if isinstance(value, str):
|
||||
value = {value: {}}
|
||||
if not isinstance(value, dict):
|
||||
raise Invalid(u"{} must consist of key-value mapping! Got {}"
|
||||
u"".format(name.title(), value))
|
||||
raise Invalid("{} must consist of key-value mapping! Got {}"
|
||||
"".format(name.title(), value))
|
||||
key = next((x for x in value if x not in ignore_keys), None)
|
||||
if key is None:
|
||||
raise Invalid(u"Key missing from {}! Got {}".format(name, value))
|
||||
raise Invalid(f"Key missing from {name}! Got {value}")
|
||||
if key not in registry:
|
||||
raise Invalid(u"Unable to find {} with the name '{}'".format(name, key), [key])
|
||||
raise Invalid(f"Unable to find {name} with the name '{key}'", [key])
|
||||
key2 = next((x for x in value if x != key and x not in ignore_keys), None)
|
||||
if key2 is not None:
|
||||
raise Invalid(u"Cannot have two {0}s in one item. Key '{1}' overrides '{2}'! "
|
||||
u"Did you forget to indent the block inside the {0}?"
|
||||
u"".format(name, key, key2))
|
||||
raise Invalid("Cannot have two {0}s in one item. Key '{1}' overrides '{2}'! "
|
||||
"Did you forget to indent the block inside the {0}?"
|
||||
"".format(name, key, key2))
|
||||
|
||||
if value[key] is None:
|
||||
value[key] = {}
|
||||
@@ -1296,7 +1276,7 @@ def polling_component_schema(default_update_interval):
|
||||
return COMPONENT_SCHEMA.extend({
|
||||
Required(CONF_UPDATE_INTERVAL): default_update_interval,
|
||||
})
|
||||
assert isinstance(default_update_interval, string_types)
|
||||
assert isinstance(default_update_interval, str)
|
||||
return COMPONENT_SCHEMA.extend({
|
||||
Optional(CONF_UPDATE_INTERVAL, default=default_update_interval): update_interval,
|
||||
})
|
||||
|
Reference in New Issue
Block a user