New vscode schema gen (#3336)

This commit is contained in:
Guillermo Ruffino
2022-04-03 04:30:22 -03:00
committed by GitHub
parent 9de61fcf58
commit 05dc97099a
8 changed files with 887 additions and 58 deletions
+8 -13
View File
@@ -262,21 +262,16 @@ async def repeat_action_to_code(config, action_id, template_arg, args):
return var
def validate_wait_until(value):
schema = cv.Schema(
{
cv.Required(CONF_CONDITION): validate_potentially_and_condition,
cv.Optional(CONF_TIMEOUT): cv.templatable(
cv.positive_time_period_milliseconds
),
}
)
if isinstance(value, dict) and CONF_CONDITION in value:
return schema(value)
return validate_wait_until({CONF_CONDITION: value})
_validate_wait_until = cv.maybe_simple_value(
{
cv.Required(CONF_CONDITION): validate_potentially_and_condition,
cv.Optional(CONF_TIMEOUT): cv.templatable(cv.positive_time_period_milliseconds),
},
key=CONF_CONDITION,
)
@register_action("wait_until", WaitUntilAction, validate_wait_until)
@register_action("wait_until", WaitUntilAction, _validate_wait_until)
async def wait_until_action_to_code(config, action_id, template_arg, args):
conditions = await build_condition(config[CONF_CONDITION], template_arg, args)
var = cg.new_Pvariable(action_id, template_arg, conditions)
+5 -13
View File
@@ -203,15 +203,6 @@ async def to_code(config):
)
def maybe_simple_message(schema):
def validator(value):
if isinstance(value, dict):
return cv.Schema(schema)(value)
return cv.Schema(schema)({CONF_FORMAT: value})
return validator
def validate_printf(value):
# https://stackoverflow.com/questions/30011379/how-can-i-parse-a-c-format-string-in-python
cfmt = r"""
@@ -234,7 +225,7 @@ def validate_printf(value):
CONF_LOGGER_LOG = "logger.log"
LOGGER_LOG_ACTION_SCHEMA = cv.All(
maybe_simple_message(
cv.maybe_simple_value(
{
cv.Required(CONF_FORMAT): cv.string,
cv.Optional(CONF_ARGS, default=list): cv.ensure_list(cv.lambda_),
@@ -242,9 +233,10 @@ LOGGER_LOG_ACTION_SCHEMA = cv.All(
*LOG_LEVEL_TO_ESP_LOG, upper=True
),
cv.Optional(CONF_TAG, default="main"): cv.string,
}
),
validate_printf,
},
validate_printf,
key=CONF_FORMAT,
)
)
@@ -71,9 +71,9 @@ SENSOR_VALUE_TYPE = {
"S_DWORD": SensorValueType.S_DWORD,
"S_DWORD_R": SensorValueType.S_DWORD_R,
"U_QWORD": SensorValueType.U_QWORD,
"U_QWORDU_R": SensorValueType.U_QWORD_R,
"U_QWORD_R": SensorValueType.U_QWORD_R,
"S_QWORD": SensorValueType.S_QWORD,
"U_QWORD_R": SensorValueType.S_QWORD_R,
"S_QWORD_R": SensorValueType.S_QWORD_R,
"FP32": SensorValueType.FP32,
"FP32_R": SensorValueType.FP32_R,
}
@@ -87,9 +87,9 @@ TYPE_REGISTER_MAP = {
"S_DWORD": 2,
"S_DWORD_R": 2,
"U_QWORD": 4,
"U_QWORDU_R": 4,
"S_QWORD": 4,
"U_QWORD_R": 4,
"S_QWORD": 4,
"S_QWORD_R": 4,
"FP32": 2,
"FP32_R": 2,
}
@@ -2,7 +2,6 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import select
from esphome.const import CONF_ADDRESS, CONF_ID, CONF_LAMBDA, CONF_OPTIMISTIC
from esphome.jsonschema import jschema_composite
from .. import (
SENSOR_VALUE_TYPE,
@@ -30,7 +29,6 @@ ModbusSelect = modbus_controller_ns.class_(
)
@jschema_composite
def ensure_option_map():
def validator(value):
cv.check_not_templatable(value)
+7 -3
View File
@@ -58,7 +58,7 @@ from esphome.core import (
)
from esphome.helpers import list_starts_with, add_class_to_obj
from esphome.jsonschema import (
jschema_composite,
jschema_list,
jschema_extractor,
jschema_registry,
jschema_typed,
@@ -327,7 +327,7 @@ def boolean(value):
)
@jschema_composite
@jschema_list
def ensure_list(*validators):
"""Validate this configuration option to be a list.
@@ -494,7 +494,11 @@ def templatable(other_validators):
"""
schema = Schema(other_validators)
@jschema_extractor("templatable")
def validator(value):
# pylint: disable=comparison-with-callable
if value == jschema_extractor:
return other_validators
if isinstance(value, Lambda):
return returning_lambda(value)
if isinstance(other_validators, dict):
@@ -1546,7 +1550,7 @@ def validate_registry(name, registry):
return ensure_list(validate_registry_entry(name, registry))
@jschema_composite
@jschema_list
def maybe_simple_value(*validators, **kwargs):
key = kwargs.pop("key", CONF_VALUE)
validator = All(*validators)
+7 -7
View File
@@ -1,7 +1,7 @@
"""Helpers to retrieve schema from voluptuous validators.
These are a helper decorators to help get schema from some
components which uses volutuous in a way where validation
components which uses voluptuous in a way where validation
is hidden in local functions
These decorators should not modify at all what the functions
originally do.
@@ -24,7 +24,7 @@ def jschema_extractor(validator_name):
if EnableJsonSchemaCollect:
def decorator(func):
hidden_schemas[str(func)] = validator_name
hidden_schemas[repr(func)] = validator_name
return func
return decorator
@@ -41,7 +41,7 @@ def jschema_extended(func):
def decorate(*args, **kwargs):
ret = func(*args, **kwargs)
assert len(args) == 2
extended_schemas[str(ret)] = args
extended_schemas[repr(ret)] = args
return ret
return decorate
@@ -49,13 +49,13 @@ def jschema_extended(func):
return func
def jschema_composite(func):
def jschema_list(func):
if EnableJsonSchemaCollect:
def decorate(*args, **kwargs):
ret = func(*args, **kwargs)
# args length might be 2, but 2nd is always validator
list_schemas[str(ret)] = args
list_schemas[repr(ret)] = args
return ret
return decorate
@@ -67,7 +67,7 @@ def jschema_registry(registry):
if EnableJsonSchemaCollect:
def decorator(func):
registry_schemas[str(func)] = registry
registry_schemas[repr(func)] = registry
return func
return decorator
@@ -83,7 +83,7 @@ def jschema_typed(func):
def decorate(*args, **kwargs):
ret = func(*args, **kwargs)
typed_schemas[str(ret)] = (args, kwargs)
typed_schemas[repr(ret)] = (args, kwargs)
return ret
return decorate
+43 -16
View File
@@ -70,7 +70,7 @@ def add_definition_array_or_single_object(ref):
def add_core():
from esphome.core.config import CONFIG_SCHEMA
base_props["esphome"] = get_jschema("esphome", CONFIG_SCHEMA.schema)
base_props["esphome"] = get_jschema("esphome", CONFIG_SCHEMA)
def add_buses():
@@ -216,7 +216,7 @@ def add_components():
add_module_registries(domain, c.module)
add_module_schemas(domain, c.module)
# need first to iterate all platforms then iteate components
# need first to iterate all platforms then iterate components
# a platform component can have other components as properties,
# e.g. climate components usually have a temperature sensor
@@ -325,7 +325,9 @@ def get_entry(parent_key, vschema):
if DUMP_COMMENTS:
entry[JSC_COMMENT] = "entry: " + parent_key + "/" + str(vschema)
if isinstance(vschema, list):
if isinstance(vschema, dict):
entry = {"what": "is_this"}
elif isinstance(vschema, list):
ref = get_jschema(parent_key + "[]", vschema[0])
entry = {"type": "array", "items": ref}
elif isinstance(vschema, schema_type) and hasattr(vschema, "schema"):
@@ -387,8 +389,10 @@ def get_entry(parent_key, vschema):
v = vschema(None)
if isinstance(v, ID):
if v.type.base != "script::Script" and (
v.type.inherits_from(Trigger) or v.type == Automation
if (
v.type.base != "script::Script"
and v.type.base != "switch_::Switch"
and (v.type.inherits_from(Trigger) or v.type == Automation)
):
return None
entry = {"type": "string", "id_type": v.type.base}
@@ -410,6 +414,8 @@ def default_schema():
def is_default_schema(jschema):
if jschema is None:
return False
if is_ref(jschema):
jschema = unref(jschema)
if not jschema:
@@ -425,6 +431,9 @@ def get_jschema(path, vschema, create_return_ref=True):
jschema = convert_schema(path, vschema)
if jschema is None:
return None
if is_ref(jschema):
# this can happen when returned extended
# schemas where all properties found in previous extended schema
@@ -450,6 +459,9 @@ def get_schema_str(vschema):
def create_ref(name, vschema, jschema):
if jschema is None:
raise ValueError("Cannot create a ref with null jschema for " + name)
if name in schema_names:
raise ValueError("Not supported")
@@ -523,6 +535,15 @@ def convert_schema(path, vschema, un_extend=True):
extended = ejs.extended_schemas.get(str(vschema))
if extended:
lhs = get_jschema(path, extended[0], False)
# The midea actions are extending an empty schema (resulted in the templatize not templatizing anything)
# this causes a recursion in that this extended looks the same in extended schema as the extended[1]
if ejs.extended_schemas.get(str(vschema)) == ejs.extended_schemas.get(
str(extended[1])
):
assert path.startswith("midea_ac")
return convert_schema(path, extended[1], False)
rhs = get_jschema(path, extended[1], False)
# check if we are not merging properties which are already in base component
@@ -567,6 +588,8 @@ def convert_schema(path, vschema, un_extend=True):
# we should take the valid schema,
# commonly all is used to validate a schema, and then a function which
# is not a schema es also given, get_schema will then return a default_schema()
if v == dict:
continue # this is a dict in the SCHEMA of packages
val_schema = get_jschema(path, v, False)
if is_default_schema(val_schema):
if not output:
@@ -673,6 +696,11 @@ def add_pin_registry():
for mode in ("INPUT", "OUTPUT"):
schema_name = f"PIN.GPIO_FULL_{mode}_PIN_SCHEMA"
# TODO: get pin definitions properly
if schema_name not in definitions:
definitions[schema_name] = {"type": ["object", "null"], JSC_PROPERTIES: {}}
internal = definitions[schema_name]
definitions[schema_name]["additionalItems"] = False
definitions[f"PIN.{mode}_INTERNAL"] = internal
@@ -683,12 +711,11 @@ def add_pin_registry():
definitions[schema_name] = {"oneOf": schemas, "type": ["string", "object"]}
for k, v in pin_registry.items():
pin_jschema = get_jschema(
f"PIN.{mode}_" + k, v[1][0 if mode == "OUTPUT" else 1]
)
if unref(pin_jschema):
pin_jschema["required"] = [k]
schemas.append(pin_jschema)
if isinstance(v[1], vol.validators.All):
pin_jschema = get_jschema(f"PIN.{mode}_" + k, v[1])
if unref(pin_jschema):
pin_jschema["required"] = [k]
schemas.append(pin_jschema)
def dump_schema():
@@ -730,9 +757,9 @@ def dump_schema():
cv.valid_name,
cv.hex_int,
cv.hex_int_range,
pins.output_pin,
pins.input_pin,
pins.input_pullup_pin,
pins.gpio_output_pin_schema,
pins.gpio_input_pin_schema,
pins.gpio_input_pullup_pin_schema,
cv.float_with_unit,
cv.subscribe_topic,
cv.publish_topic,
@@ -753,12 +780,12 @@ def dump_schema():
for v in [pins.gpio_input_pin_schema, pins.gpio_input_pullup_pin_schema]:
schema_registry[v] = get_ref("PIN.GPIO_FULL_INPUT_PIN_SCHEMA")
for v in [pins.internal_gpio_input_pin_schema, pins.input_pin]:
for v in [pins.internal_gpio_input_pin_schema, pins.gpio_input_pin_schema]:
schema_registry[v] = get_ref("PIN.INPUT_INTERNAL")
for v in [pins.gpio_output_pin_schema, pins.internal_gpio_output_pin_schema]:
schema_registry[v] = get_ref("PIN.GPIO_FULL_OUTPUT_PIN_SCHEMA")
for v in [pins.internal_gpio_output_pin_schema, pins.output_pin]:
for v in [pins.internal_gpio_output_pin_schema, pins.gpio_output_pin_schema]:
schema_registry[v] = get_ref("PIN.OUTPUT_INTERNAL")
add_module_schemas("CONFIG", cv)
File diff suppressed because it is too large Load Diff