From 3498aade85f10e342efcd03bccc1dcdeceff5b5f Mon Sep 17 00:00:00 2001 From: Guillermo Ruffino Date: Wed, 3 May 2023 19:18:45 -0300 Subject: [PATCH] update schema gen to 2023.4.0 (#4772) --- script/build_language_schema.py | 100 ++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 30 deletions(-) diff --git a/script/build_language_schema.py b/script/build_language_schema.py index 4c8639a1b..dd8eccde9 100644 --- a/script/build_language_schema.py +++ b/script/build_language_schema.py @@ -63,7 +63,7 @@ solve_registry = [] def get_component_names(): from esphome.loader import CORE_COMPONENTS_PATH - component_names = ["esphome", "sensor"] + component_names = ["esphome", "sensor", "esp32", "esp8266"] for d in os.listdir(CORE_COMPONENTS_PATH): if not d.startswith("__") and os.path.isdir( @@ -109,6 +109,13 @@ def write_file(name, obj): print(f"Wrote {full_path}") +def delete_extra_files(keep_names): + for d in os.listdir(args.output_path): + if d.endswith(".json") and not d[:-5] in keep_names: + os.remove(os.path.join(args.output_path, d)) + print(f"Deleted {d}") + + def register_module_schemas(key, module, manifest=None): for name, schema in module_schemas(module): register_known_schema(key, name, schema) @@ -150,7 +157,7 @@ def module_schemas(module): schemas = {} for m_attr_name in dir(module): m_attr_obj = getattr(module, m_attr_name) - if isConvertibleSchema(m_attr_obj): + if is_convertible_schema(m_attr_obj): schemas[module_str.find(m_attr_name)] = [m_attr_name, m_attr_obj] for pos in sorted(schemas.keys()): @@ -240,25 +247,34 @@ def do_pins(): pins_providers.append(pin_registry) +def setBoards(obj, boards): + obj[S_TYPE] = "enum" + obj["values"] = {} + for k, v in boards.items(): + obj["values"][k] = {"docs": v["name"]} + + def do_esp32(): import esphome.components.esp32.boards as esp32_boards - setEnum( + setBoards( output["esp32"]["schemas"]["CONFIG_SCHEMA"]["schema"]["config_vars"]["board"], - list(esp32_boards.BOARDS.keys()), + esp32_boards.BOARDS, ) def do_esp8266(): import esphome.components.esp8266.boards as esp8266_boards - setEnum( + setBoards( output["esp8266"]["schemas"]["CONFIG_SCHEMA"]["schema"]["config_vars"]["board"], - list(esp8266_boards.ESP8266_BOARD_PINS.keys()), + esp8266_boards.BOARDS, ) def fix_remote_receiver(): + if "remote_receiver.binary_sensor" not in output: + return remote_receiver_schema = output["remote_receiver.binary_sensor"]["schemas"] remote_receiver_schema["CONFIG_SCHEMA"] = { "type": "schema", @@ -275,6 +291,8 @@ def fix_remote_receiver(): def fix_script(): + if "script" not in output: + return output["script"][S_SCHEMAS][S_CONFIG_SCHEMA][S_TYPE] = S_SCHEMA config_schema = output["script"][S_SCHEMAS][S_CONFIG_SCHEMA] config_schema[S_SCHEMA][S_CONFIG_VARS]["id"]["id_type"] = { @@ -283,7 +301,17 @@ def fix_script(): config_schema["is_list"] = True +def fix_font(): + if "font" not in output: + return + output["font"][S_SCHEMAS]["FILE_SCHEMA"] = output["font"][S_SCHEMAS].pop( + "TYPED_FILE_SCHEMA" + ) + + def fix_menu(): + if "display_menu_base" not in output: + return # # Menu has a recursive schema which is not kept properly schemas = output["display_menu_base"][S_SCHEMAS] # 1. Move items to a new schema @@ -330,6 +358,8 @@ def get_logger_tags(): def add_logger_tags(): + if "logger" not in output or "schemas" not in output["logger"]: + return tags = get_logger_tags() logs = output["logger"]["schemas"]["CONFIG_SCHEMA"]["schema"]["config_vars"][ "logs" @@ -429,6 +459,12 @@ def merge(source, destination): return destination +def is_platform_schema(schema_name): + # added mostly because of schema_name == "microphone.MICROPHONE_SCHEMA" + # which is shrunk because there is only one component of the schema (i2s_audio) + return schema_name == "microphone.MICROPHONE_SCHEMA" + + def shrink(): """Shrink the extending schemas which has just an end type, e.g. at this point ota / port is type schema with extended pointing to core.port, this should instead be @@ -454,7 +490,7 @@ def shrink(): add_referenced_recursive(referenced_schemas, vvv, [k, kv, kvv]) for x, paths in referenced_schemas.items(): - if len(paths) == 1: + if len(paths) == 1 and not is_platform_schema(x): key_s = get_str_path_schema(x) arr_s = get_arr_path_schema(paths[0]) # key_s |= arr_s @@ -508,6 +544,7 @@ def shrink(): if ( not s.endswith("." + S_CONFIG_SCHEMA) and s not in referenced_schemas.keys() + and not is_platform_schema(s) ): print(f"Removing {s}") output[domain][S_SCHEMAS].pop(schema_name) @@ -589,6 +626,7 @@ def build_schema(): do_esp32() fix_remote_receiver() fix_script() + fix_font() add_logger_tags() shrink() fix_menu() @@ -611,17 +649,13 @@ def build_schema(): for c, s in data.items(): write_file(c, s) + delete_extra_files(data.keys()) -def setEnum(obj, items): - obj[S_TYPE] = "enum" - obj["values"] = items - - -def isConvertibleSchema(schema): +def is_convertible_schema(schema): if schema is None: return False - if isinstance(schema, (cv.Schema, cv.All)): + if isinstance(schema, (cv.Schema, cv.All, cv.Any)): return True if repr(schema) in ejs.hidden_schemas: return True @@ -640,20 +674,23 @@ def isConvertibleSchema(schema): def convert_config(schema, path): converted = {} - convert_1(schema, converted, path) + convert(schema, converted, path) return converted -def convert_1(schema, config_var, path): +def convert(schema, config_var, path): """config_var can be a config_var or a schema: both are dicts config_var has a S_TYPE property, if this is S_SCHEMA, then it has a S_SCHEMA property schema does not have a type property, schema can have optionally both S_CONFIG_VARS and S_EXTENDS """ repr_schema = repr(schema) + if path.startswith("ads1115.sensor") and path.endswith("gain"): + print(path) + if repr_schema in known_schemas: schema_info = known_schemas[(repr_schema)] - for (schema_instance, name) in schema_info: + for schema_instance, name in schema_info: if schema_instance is schema: assert S_CONFIG_VARS not in config_var assert S_EXTENDS not in config_var @@ -665,7 +702,7 @@ def convert_1(schema, config_var, path): config_var[S_SCHEMA] = {} if S_EXTENDS not in config_var[S_SCHEMA]: config_var[S_SCHEMA][S_EXTENDS] = [name] - else: + elif name not in config_var[S_SCHEMA][S_EXTENDS]: config_var[S_SCHEMA][S_EXTENDS].append(name) return @@ -679,25 +716,25 @@ def convert_1(schema, config_var, path): return assert len(extended) == 2 - convert_1(extended[0], config_var, path + "/extL") - convert_1(extended[1], config_var, path + "/extR") + convert(extended[0], config_var, path + "/extL") + convert(extended[1], config_var, path + "/extR") return if isinstance(schema, cv.All): i = 0 for inner in schema.validators: i = i + 1 - convert_1(inner, config_var, path + f"/val {i}") + convert(inner, config_var, path + f"/val {i}") return if hasattr(schema, "validators"): i = 0 for inner in schema.validators: i = i + 1 - convert_1(inner, config_var, path + f"/val {i}") + convert(inner, config_var, path + f"/val {i}") if isinstance(schema, cv.Schema): - convert_1(schema.schema, config_var, path + "/all") + convert(schema.schema, config_var, path + "/all") return if isinstance(schema, dict): @@ -707,7 +744,7 @@ def convert_1(schema, config_var, path): if repr_schema in ejs.list_schemas: config_var["is_list"] = True items_schema = ejs.list_schemas[repr_schema][0] - convert_1(items_schema, config_var, path + "/list") + convert(items_schema, config_var, path + "/list") return if DUMP_RAW: @@ -741,10 +778,10 @@ def convert_1(schema, config_var, path): # enums, e.g. esp32/variant if schema_type == "one_of": config_var[S_TYPE] = "enum" - config_var["values"] = list(data) + config_var["values"] = dict.fromkeys(list(data)) elif schema_type == "enum": config_var[S_TYPE] = "enum" - config_var["values"] = list(data.keys()) + config_var["values"] = dict.fromkeys(list(data.keys())) elif schema_type == "maybe": config_var[S_TYPE] = S_SCHEMA config_var["maybe"] = data[1] @@ -785,13 +822,13 @@ def convert_1(schema, config_var, path): config_var["filter"] = data[0] elif schema_type == "templatable": config_var["templatable"] = True - convert_1(data, config_var, path + "/templat") + convert(data, config_var, path + "/templat") elif schema_type == "triggers": # remote base - convert_1(data, config_var, path + "/trigger") + convert(data, config_var, path + "/trigger") elif schema_type == "sensor": schema = data - convert_1(data, config_var, path + "/trigger") + convert(data, config_var, path + "/trigger") elif schema_type == "declare_id": # pylint: disable=protected-access parents = data._parents @@ -856,6 +893,9 @@ def convert_1(schema, config_var, path): if DUMP_PATH: config_var["path"] = path + if S_TYPE not in config_var: + pass + # print(path) def get_overridden_config(key, converted): @@ -921,7 +961,7 @@ def convert_keys(converted, schema, path): result["default"] = str(default_value) # Do value - convert_1(v, result, path + f"/{str(k)}") + convert(v, result, path + f"/{str(k)}") if "schema" not in converted: converted[S_TYPE] = "schema" converted["schema"] = {S_CONFIG_VARS: {}}