"""App metadata specification"""
from __future__ import annotations
from configparser import ConfigParser
from dataclasses import dataclass, field
from pathlib import Path
from typing import TYPE_CHECKING, Any, Generator
if TYPE_CHECKING:
from configparser import SectionProxy
from .git_util import GitPath
__all__ = [
"Metadata",
]
def _map_development_state(classifiers: str | list[str]) -> str:
"Map standard trove classifiers (PEP 301) to aiidalab development states."
if "Development Status :: 1 - Planning" in classifiers:
return "registered"
elif "Development Status :: 5 - Production/Stable" in classifiers:
return "stable"
elif any(
classifier in classifiers
for classifier in (
"Development Status :: 2 - Pre-Alpha",
"Development Status :: 3 - Alpha",
"Development Status :: 4 - Beta",
)
):
return "development"
else:
return "registered"
def _parse_config_dict(dict_: str) -> Generator[tuple[str, str], None, None]:
"Parse a config dict string for key-values pairs."
for line in dict_.splitlines():
if line:
key, value = line.split("=")
yield key.strip(), value.strip()
def _parse_setup_cfg(
setup_cfg: str,
) -> Generator[tuple[str, str | list[str]], None, None]:
"Parse a setup.cfg configuration file string for metadata."
cfg = ConfigParser()
cfg.read_string(setup_cfg)
metadata_pep426: SectionProxy | dict[Any, Any] = (
cfg["metadata"] if "metadata" in cfg else {}
)
aiidalab: SectionProxy | dict[Any, Any] = (
cfg["aiidalab"] if "aiidalab" in cfg else {}
)
yield "title", aiidalab.get("title", metadata_pep426.get("name"))
yield "version", aiidalab.get("version", metadata_pep426.get("version"))
yield "description", aiidalab.get("description", metadata_pep426.get("description"))
yield "authors", aiidalab.get("authors", metadata_pep426.get("author"))
yield "external_url", aiidalab.get("external_url", metadata_pep426.get("url"))
project_urls = dict(_parse_config_dict(metadata_pep426.get("project_urls", "")))
yield (
"documentation_url",
aiidalab.get(
"documentation_url",
project_urls.get("Documentation") or project_urls.get("documentation"),
),
)
yield (
"logo",
aiidalab.get("logo", project_urls.get("Logo") or project_urls.get("logo")),
)
yield (
"state",
aiidalab.get(
"state", _map_development_state(metadata_pep426.get("classifiers", ""))
),
)
# Allow passing single category and convert to list
# and allow parse line separated string as list
categories = aiidalab.get("categories", "")
if isinstance(categories, str):
categories = [c for c in categories.split("\n") if c]
yield "categories", categories