mirror of
https://github.com/sascha-hemi/hacs_waste_collection_schedule.git
synced 2026-03-21 04:06:03 +01:00
show ics howto in condfig flow
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@ import inspect
|
|||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
import site
|
import site
|
||||||
|
from functools import lru_cache
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
from typing import Any, Callable, Tuple, TypedDict, TypeVar
|
from typing import Any, Callable, Tuple, TypedDict, TypeVar
|
||||||
@@ -43,6 +44,14 @@ ARG_TRANSLATIONS_TO_KEEP = ["calendar_title"]
|
|||||||
ARG_DESCRIPTIONS_TO_KEEP = ["calendar_title"]
|
ARG_DESCRIPTIONS_TO_KEEP = ["calendar_title"]
|
||||||
ARG_GENERAL_KEYS_TO_KEEP = ["title", "description"]
|
ARG_GENERAL_KEYS_TO_KEEP = ["title", "description"]
|
||||||
|
|
||||||
|
PACKAGE_DIR = (
|
||||||
|
Path(__file__).resolve().parents[0]
|
||||||
|
/ "custom_components"
|
||||||
|
/ "waste_collection_schedule"
|
||||||
|
)
|
||||||
|
SOURCE_DIR = PACKAGE_DIR / "waste_collection_schedule" / "source"
|
||||||
|
DOC_URL_BASE = "https://github.com/mampfes/hacs_waste_collection_schedule/blob/master"
|
||||||
|
|
||||||
|
|
||||||
class SourceInfo:
|
class SourceInfo:
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -138,6 +147,41 @@ class SourceInfo:
|
|||||||
return self._custom_howto
|
return self._custom_howto
|
||||||
|
|
||||||
|
|
||||||
|
class IcsSourceInfo(SourceInfo):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
filename: str,
|
||||||
|
title: str,
|
||||||
|
url: str,
|
||||||
|
country: str,
|
||||||
|
limit_params: list[str],
|
||||||
|
extra_info_default_params: dict[str, Any] = {},
|
||||||
|
custom_howto: dict[str, str] = {},
|
||||||
|
):
|
||||||
|
_, ics_sources = get_source_by_file("ics")
|
||||||
|
ics_source = ics_sources[0]
|
||||||
|
params = set(ics_source.params) - set(limit_params)
|
||||||
|
translations = ics_source.custom_param_translation
|
||||||
|
descriptions = ics_source.custom_param_description
|
||||||
|
for translation in [*translations.values(), *descriptions.values()]:
|
||||||
|
for param in list(translation.keys()):
|
||||||
|
if param not in params:
|
||||||
|
translation.pop(param)
|
||||||
|
|
||||||
|
super().__init__(
|
||||||
|
filename=filename,
|
||||||
|
module=None,
|
||||||
|
title=title,
|
||||||
|
url=url,
|
||||||
|
country=country,
|
||||||
|
params=list(params),
|
||||||
|
extra_info_default_params=extra_info_default_params,
|
||||||
|
custom_param_translation=translations,
|
||||||
|
custom_param_description=descriptions,
|
||||||
|
custom_howto=custom_howto,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Section:
|
class Section:
|
||||||
def __init__(self, section):
|
def __init__(self, section):
|
||||||
self._section = section
|
self._section = section
|
||||||
@@ -225,19 +269,12 @@ def main() -> None:
|
|||||||
|
|
||||||
def browse_sources() -> list[SourceInfo]:
|
def browse_sources() -> list[SourceInfo]:
|
||||||
"""Browse all .py files in the `source` directory"""
|
"""Browse all .py files in the `source` directory"""
|
||||||
package_dir = (
|
|
||||||
Path(__file__).resolve().parents[0]
|
|
||||||
/ "custom_components"
|
|
||||||
/ "waste_collection_schedule"
|
|
||||||
)
|
|
||||||
source_dir = package_dir / "waste_collection_schedule" / "source"
|
|
||||||
|
|
||||||
# add module directory to path
|
# add module directory to path
|
||||||
site.addsitedir(str(package_dir))
|
site.addsitedir(str(PACKAGE_DIR))
|
||||||
|
|
||||||
files = filter(
|
files = filter(
|
||||||
lambda x: x != "__init__",
|
lambda x: x != "__init__",
|
||||||
map(lambda x: x.stem, source_dir.glob("*.py")),
|
map(lambda x: x.stem, SOURCE_DIR.glob("*.py")),
|
||||||
)
|
)
|
||||||
|
|
||||||
modules: dict[str, ModuleType] = {}
|
modules: dict[str, ModuleType] = {}
|
||||||
@@ -245,56 +282,9 @@ def browse_sources() -> list[SourceInfo]:
|
|||||||
|
|
||||||
# retrieve all data from sources
|
# retrieve all data from sources
|
||||||
for f in files:
|
for f in files:
|
||||||
# iterate through all *.py files in waste_collection_schedule/source
|
module, sources_out = get_source_by_file(f)
|
||||||
module = importlib.import_module(f"waste_collection_schedule.source.{f}")
|
|
||||||
modules[f] = module
|
modules[f] = module
|
||||||
|
sources += sources_out
|
||||||
title = module.TITLE
|
|
||||||
url = module.URL
|
|
||||||
country = getattr(module, "COUNTRY", f.split("_")[-1])
|
|
||||||
|
|
||||||
sig = inspect.signature(module.Source.__init__)
|
|
||||||
params = [param.name for param in sig.parameters.values()]
|
|
||||||
if "self" in params:
|
|
||||||
params.remove("self")
|
|
||||||
param_translations = getattr(module, "PARAM_TRANSLATIONS", {})
|
|
||||||
param_descriptions = getattr(module, "PARAM_DESCRIPTIONS", {})
|
|
||||||
howto = getattr(module, "HOW_TO_GET_ARGUMENTS_DESCRIPTION", {})
|
|
||||||
|
|
||||||
filename = f"/doc/source/{f}.md"
|
|
||||||
if title is not None:
|
|
||||||
sources.append(
|
|
||||||
SourceInfo(
|
|
||||||
filename=filename,
|
|
||||||
module=f,
|
|
||||||
title=title,
|
|
||||||
url=url,
|
|
||||||
country=country,
|
|
||||||
params=params,
|
|
||||||
custom_param_translation=param_translations,
|
|
||||||
custom_param_description=param_descriptions,
|
|
||||||
custom_howto=howto,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
extra_info: list[ExtraInfoDict] | Callable[[], list[ExtraInfoDict]] = getattr(
|
|
||||||
module, "EXTRA_INFO", []
|
|
||||||
)
|
|
||||||
if callable(extra_info):
|
|
||||||
extra_info = extra_info()
|
|
||||||
for e in extra_info:
|
|
||||||
sources.append(
|
|
||||||
SourceInfo(
|
|
||||||
filename=filename,
|
|
||||||
module=f,
|
|
||||||
title=e.get("title", title),
|
|
||||||
url=e.get("url", url),
|
|
||||||
country=e.get("country", country),
|
|
||||||
params=params,
|
|
||||||
extra_info_default_params=e.get("default_params", {}),
|
|
||||||
custom_howto=howto,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
update_awido_de(modules)
|
update_awido_de(modules)
|
||||||
update_ctrace_de(modules)
|
update_ctrace_de(modules)
|
||||||
@@ -306,6 +296,61 @@ def browse_sources() -> list[SourceInfo]:
|
|||||||
return sources
|
return sources
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache(maxsize=None)
|
||||||
|
def get_source_by_file(file: str) -> tuple[ModuleType, list[SourceInfo]]:
|
||||||
|
# iterate through all *.py files in waste_collection_schedule/source
|
||||||
|
module = importlib.import_module(f"waste_collection_schedule.source.{file}")
|
||||||
|
|
||||||
|
title = module.TITLE
|
||||||
|
url = module.URL
|
||||||
|
country = getattr(module, "COUNTRY", file.split("_")[-1])
|
||||||
|
|
||||||
|
sig = inspect.signature(module.Source.__init__)
|
||||||
|
params = [param.name for param in sig.parameters.values()]
|
||||||
|
if "self" in params:
|
||||||
|
params.remove("self")
|
||||||
|
param_translations = getattr(module, "PARAM_TRANSLATIONS", {})
|
||||||
|
param_descriptions = getattr(module, "PARAM_DESCRIPTIONS", {})
|
||||||
|
howto = getattr(module, "HOW_TO_GET_ARGUMENTS_DESCRIPTION", {})
|
||||||
|
|
||||||
|
filename = f"/doc/source/{file}.md"
|
||||||
|
sources = []
|
||||||
|
if title is not None:
|
||||||
|
sources.append(
|
||||||
|
SourceInfo(
|
||||||
|
filename=filename,
|
||||||
|
module=file,
|
||||||
|
title=title,
|
||||||
|
url=url,
|
||||||
|
country=country,
|
||||||
|
params=params,
|
||||||
|
custom_param_translation=param_translations,
|
||||||
|
custom_param_description=param_descriptions,
|
||||||
|
custom_howto=howto,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
extra_info: list[ExtraInfoDict] | Callable[[], list[ExtraInfoDict]] = getattr(
|
||||||
|
module, "EXTRA_INFO", []
|
||||||
|
)
|
||||||
|
if callable(extra_info):
|
||||||
|
extra_info = extra_info()
|
||||||
|
for e in extra_info:
|
||||||
|
sources.append(
|
||||||
|
SourceInfo(
|
||||||
|
filename=filename,
|
||||||
|
module=file,
|
||||||
|
title=e.get("title", title),
|
||||||
|
url=e.get("url", url),
|
||||||
|
country=e.get("country", country),
|
||||||
|
params=params,
|
||||||
|
extra_info_default_params=e.get("default_params", {}),
|
||||||
|
custom_howto=howto,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return module, sources
|
||||||
|
|
||||||
|
|
||||||
def browse_ics_yaml() -> list[SourceInfo]:
|
def browse_ics_yaml() -> list[SourceInfo]:
|
||||||
"""Browse all .yaml files which are descriptions for the ICS source"""
|
"""Browse all .yaml files which are descriptions for the ICS source"""
|
||||||
doc_dir = Path(__file__).resolve().parents[0] / "doc"
|
doc_dir = Path(__file__).resolve().parents[0] / "doc"
|
||||||
@@ -338,13 +383,12 @@ def browse_ics_yaml() -> list[SourceInfo]:
|
|||||||
country = data.get("country", f.stem.split("_")[-1])
|
country = data.get("country", f.stem.split("_")[-1])
|
||||||
# extract country code
|
# extract country code
|
||||||
sources.append(
|
sources.append(
|
||||||
SourceInfo(
|
IcsSourceInfo(
|
||||||
filename=f"/doc/ics/{filename.name}",
|
filename=f"/doc/ics/{filename.name}",
|
||||||
module=None,
|
|
||||||
title=data["title"],
|
title=data["title"],
|
||||||
url=data["url"],
|
url=data["url"],
|
||||||
country=country,
|
country=country,
|
||||||
params=[],
|
limit_params=[],
|
||||||
extra_info_default_params=data.get("default_params", {}),
|
extra_info_default_params=data.get("default_params", {}),
|
||||||
custom_howto=howto,
|
custom_howto=howto,
|
||||||
)
|
)
|
||||||
@@ -352,13 +396,12 @@ def browse_ics_yaml() -> list[SourceInfo]:
|
|||||||
if "extra_info" in data:
|
if "extra_info" in data:
|
||||||
for e in data["extra_info"]:
|
for e in data["extra_info"]:
|
||||||
sources.append(
|
sources.append(
|
||||||
SourceInfo(
|
IcsSourceInfo(
|
||||||
filename=f"/doc/ics/{filename.name}",
|
filename=f"/doc/ics/{filename.name}",
|
||||||
module=None,
|
|
||||||
title=e.get("title", data["title"]),
|
title=e.get("title", data["title"]),
|
||||||
url=e.get("url", data["url"]),
|
url=e.get("url", data["url"]),
|
||||||
country=e.get("country", country),
|
country=e.get("country", country),
|
||||||
params=[],
|
limit_params=[],
|
||||||
extra_info_default_params=data.get("default_params", {}),
|
extra_info_default_params=data.get("default_params", {}),
|
||||||
custom_howto=howto,
|
custom_howto=howto,
|
||||||
)
|
)
|
||||||
@@ -484,6 +527,8 @@ def get_custom_translations(
|
|||||||
) -> Tuple[
|
) -> Tuple[
|
||||||
dict[str, dict[str, dict[str, str | None]]],
|
dict[str, dict[str, dict[str, str | None]]],
|
||||||
dict[str, dict[str, dict[str, str | None]]],
|
dict[str, dict[str, dict[str, str | None]]],
|
||||||
|
dict[str, dict[str, str | None]],
|
||||||
|
dict[str, str],
|
||||||
]:
|
]:
|
||||||
"""gets all parameters and its custom translations for all languages
|
"""gets all parameters and its custom translations for all languages
|
||||||
|
|
||||||
@@ -491,38 +536,46 @@ def get_custom_translations(
|
|||||||
countries (dict[str, list[SourceInfo]]):
|
countries (dict[str, list[SourceInfo]]):
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Tuple[dict[str, dict[str, dict[str, str | None]]], dict[str, dict[str, dict[str, str | None]]]]: Translation dict[MODULE][PARAM][LANG][TRANSLATION|None], Description: dict[MODULE][PARAM][LANG][DESCRIPTION|None]
|
Tuple[dict[str, dict[str, dict[str, str | None]]], dict[str, dict[str, dict[str, str | None]]]]: Param translation dict[MODULE][PARAM][LANG][TRANSLATION|None], Param Description: dict[MODULE][PARAM][LANG][DESCRIPTION|None], Source howto: dict[MODULE][LANG][HOWTO|None], Source doc url: dict[MODULE][URL]
|
||||||
"""
|
"""
|
||||||
param_translations: dict[str, dict[str, dict[str, str | None]]] = {}
|
param_translations: dict[str, dict[str, dict[str, str | None]]] = {}
|
||||||
param_descriptions: dict[str, dict[str, dict[str, str | None]]] = {}
|
param_descriptions: dict[str, dict[str, dict[str, str | None]]] = {}
|
||||||
|
source_howto: dict[str, dict[str, str | None]] = {}
|
||||||
|
source_doc_url: dict[str, str] = {}
|
||||||
|
|
||||||
for country in sorted(countries):
|
for country in sorted(countries):
|
||||||
for e in sorted(
|
for e in sorted(
|
||||||
countries[country],
|
countries[country],
|
||||||
key=lambda e: (e.title.lower(), beautify_url(e.url), e.filename),
|
key=lambda e: (e.title.lower(), beautify_url(e.url), e.filename),
|
||||||
):
|
):
|
||||||
|
module = e.module
|
||||||
if e.module is None: # ICS source
|
if e.module is None: # ICS source
|
||||||
continue
|
module = "ics_" + e.filename.split("/")[-1].removesuffix(".md")
|
||||||
if not e.module in param_translations:
|
|
||||||
param_translations[e.module] = {}
|
source_doc_url[module] = DOC_URL_BASE + e.filename
|
||||||
if not e.module in param_descriptions:
|
|
||||||
param_descriptions[e.module] = {}
|
if not module in param_translations:
|
||||||
|
param_translations[module] = {}
|
||||||
|
if not module in param_descriptions:
|
||||||
|
param_descriptions[module] = {}
|
||||||
|
|
||||||
for param in e.params:
|
for param in e.params:
|
||||||
if param not in param_translations[e.module]:
|
if param not in param_translations[module]:
|
||||||
param_translations[e.module][param] = {}
|
param_translations[module][param] = {}
|
||||||
if param not in param_descriptions[e.module]:
|
if param not in param_descriptions[module]:
|
||||||
param_descriptions[e.module][param] = {}
|
param_descriptions[module][param] = {}
|
||||||
|
|
||||||
for lang, translations in e.custom_param_translation.items():
|
for lang, translations in e.custom_param_translation.items():
|
||||||
for param, translation in translations.items():
|
for param, translation in translations.items():
|
||||||
param_translations[e.module][param][lang] = translation
|
param_translations[module][param][lang] = translation
|
||||||
|
|
||||||
for lang, descriptions in e.custom_param_description.items():
|
for lang, descriptions in e.custom_param_description.items():
|
||||||
for param, description in descriptions.items():
|
for param, description in descriptions.items():
|
||||||
param_descriptions[e.module][param][lang] = description
|
param_descriptions[module][param][lang] = description
|
||||||
|
|
||||||
return param_translations, param_descriptions
|
source_howto[module] = e.custom_howto
|
||||||
|
|
||||||
|
return param_translations, param_descriptions, source_howto, source_doc_url
|
||||||
|
|
||||||
|
|
||||||
def update_json(
|
def update_json(
|
||||||
@@ -531,9 +584,13 @@ def update_json(
|
|||||||
countries = countries.copy()
|
countries = countries.copy()
|
||||||
countries["Generic"] = generics
|
countries["Generic"] = generics
|
||||||
update_sources_json(countries)
|
update_sources_json(countries)
|
||||||
|
(
|
||||||
|
param_translations,
|
||||||
|
param_descriptions,
|
||||||
|
source_howto,
|
||||||
|
source_doc_url,
|
||||||
|
) = get_custom_translations(countries)
|
||||||
|
|
||||||
|
|
||||||
param_translations, param_descriptions = get_custom_translations(countries)
|
|
||||||
for lang in LANGUAGES:
|
for lang in LANGUAGES:
|
||||||
tranlation_file = (
|
tranlation_file = (
|
||||||
f"custom_components/waste_collection_schedule/translations/{lang}.json"
|
f"custom_components/waste_collection_schedule/translations/{lang}.json"
|
||||||
@@ -621,6 +678,23 @@ def update_json(
|
|||||||
"data_description"
|
"data_description"
|
||||||
][param] = languages[lang]
|
][param] = languages[lang]
|
||||||
|
|
||||||
|
module_howto = source_howto.get(module, {})
|
||||||
|
|
||||||
|
howto_str = (
|
||||||
|
module_howto.get(lang, None) or module_howto.get("en", None) or ""
|
||||||
|
)
|
||||||
|
howto_str = format_howto(howto_str)
|
||||||
|
translations["config"]["step"][f"args_{module}"][
|
||||||
|
"description"
|
||||||
|
] = translations["config"]["step"]["args"]["description"].format(
|
||||||
|
howto=howto_str, docs_url=source_doc_url.get(module, "")
|
||||||
|
)
|
||||||
|
translations["config"]["step"][f"reconfigure_{module}"][
|
||||||
|
"description"
|
||||||
|
] = translations["config"]["step"]["reconfigure"]["description"].format(
|
||||||
|
howto=howto_str, docs_url=source_doc_url.get(module, "")
|
||||||
|
)
|
||||||
|
|
||||||
with open(
|
with open(
|
||||||
tranlation_file,
|
tranlation_file,
|
||||||
"w",
|
"w",
|
||||||
@@ -629,6 +703,46 @@ def update_json(
|
|||||||
json.dump(translations, f, indent=2, ensure_ascii=False)
|
json.dump(translations, f, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
|
def format_howto(howto: str) -> str:
|
||||||
|
if not howto:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
howto = "\n\n" + howto + "\n\n"
|
||||||
|
new_howto = ""
|
||||||
|
code_opened = False
|
||||||
|
code_buffer = ""
|
||||||
|
do_not_code = False
|
||||||
|
for c in howto:
|
||||||
|
match c:
|
||||||
|
case "`":
|
||||||
|
code_buffer += c if not do_not_code else "'"
|
||||||
|
code_opened = not code_opened
|
||||||
|
if not code_opened:
|
||||||
|
do_not_code = False
|
||||||
|
case "{":
|
||||||
|
code_buffer += "{"
|
||||||
|
do_not_code = True
|
||||||
|
case "}":
|
||||||
|
code_buffer += "}"
|
||||||
|
do_not_code = True
|
||||||
|
case "<":
|
||||||
|
if code_opened:
|
||||||
|
code_buffer += c
|
||||||
|
pass
|
||||||
|
case ">":
|
||||||
|
if code_opened:
|
||||||
|
code_buffer += c
|
||||||
|
case _:
|
||||||
|
code_buffer += c
|
||||||
|
if not code_opened:
|
||||||
|
new_howto += code_buffer
|
||||||
|
code_buffer = ""
|
||||||
|
if code_opened and do_not_code:
|
||||||
|
code_buffer = code_buffer.replace("`", "'")
|
||||||
|
|
||||||
|
return new_howto
|
||||||
|
|
||||||
|
|
||||||
def update_readme_md(countries: dict[str, list[SourceInfo]]):
|
def update_readme_md(countries: dict[str, list[SourceInfo]]):
|
||||||
# generate country list
|
# generate country list
|
||||||
str = ""
|
str = ""
|
||||||
|
|||||||
Reference in New Issue
Block a user