Coverage for src/somesy/core/core.py: 78%
55 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-11-03 13:13 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-11-03 13:13 +0000
1"""Core somesy functions."""
3import json
4import logging
5from pathlib import Path
6from typing import Any
8import tomlkit
10from .log import VERBOSE
12logger = logging.getLogger("somesy")
14INPUT_FILES_ORDERED = [
15 ".somesy.toml",
16 "somesy.toml",
17 "pyproject.toml",
18 "package.json",
19 "Project.toml",
20 "fpm.toml",
21 "Cargo.toml",
22]
23"""Input files ordered by priority for discovery."""
26def write_json(data: Any, path: Path) -> None:
27 """Write data as UTF-8 JSON with 2-space indentation, unescaped non-ASCII and a trailing newline."""
28 with path.open("w", encoding="utf-8", newline="\n") as f:
29 json.dump(data, f, ensure_ascii=False, indent=2)
30 f.write("\n")
33def discover_input(input_file: Path | None = None) -> Path:
34 """Check given input file path. If not given, find somesy configuration file path from default list.
36 Args:
37 input_file: somesy configuration file path. Defaults to None.
39 Raises:
40 FileNotFoundError: Raised if no somesy input file found from cli input or the defaults.
42 Returns:
43 somesy configuration file path.
45 """
46 if input_file:
47 if input_file.is_file():
48 logger.info(f"Using provided file '{input_file}' as somesy input file.")
49 return input_file
50 else:
51 logger.warning(
52 f"Passed file '{input_file}' does not exist. Searching for usable somesy input file..."
53 )
55 for filename in INPUT_FILES_ORDERED:
56 input_file = Path(filename)
57 if input_file.is_file():
58 try:
59 get_input_content(input_file)
60 except RuntimeError:
61 continue
63 msg = f"Using '{input_file}' as somesy input file."
64 logger.log(VERBOSE, msg)
65 return input_file
67 raise FileNotFoundError("No somesy input file found.")
70def get_input_content(path: Path, *, no_unwrap: bool = False) -> dict[str, Any]:
71 """Read contents of a supported somesy input file.
73 Given a path to a TOML file, this function reads the file and returns its content as a TOMLDocument object.
74 The function checks if the file is a valid somesy input file by checking its name and content.
76 Args:
77 path (Path): path to the input file
78 no_unwrap (bool): if True, the function returns the TOMLDocument object instead of unwrapping it
80 Returns:
81 the content of the input file as a TOMLDocument object
83 Raises:
84 ValueError: if the input file is not a valid somesy input file or if the file is not a TOML file.
85 RuntimeError: if the input file does not contain a somesy input section at expected key
87 """
88 logger.debug(f"Path {path}")
89 # somesy.toml / .somesy.toml
90 if path.suffix == ".toml" and "somesy" in path.name:
91 with open(path, "r", encoding="utf-8") as f:
92 ret = tomlkit.load(f)
93 return ret if no_unwrap else ret.unwrap()
95 # pyproject.toml or fpm.toml
96 if (path.suffix == ".toml" and "pyproject" in path.name) or path.name in [
97 "Project.toml",
98 "fpm.toml",
99 ]:
100 with open(path, "r", encoding="utf-8") as f:
101 input_content = tomlkit.load(f)
102 if "tool" in input_content and "somesy" in input_content["tool"]:
103 return input_content["tool"]["somesy"].unwrap()
104 else:
105 raise RuntimeError(
106 "No tool.somesy section found in pyproject.toml file!"
107 )
109 # Cargo.toml
110 if path.name == "Cargo.toml":
111 with open(path, "r", encoding="utf-8") as f:
112 input_content = tomlkit.load(f)
113 if (
114 "package" in input_content
115 and "metadata" in input_content["package"]
116 and "somesy" in input_content["package"]["metadata"]
117 ):
118 return input_content["package"]["metadata"]["somesy"].unwrap()
119 else:
120 raise RuntimeError(
121 "No package.somesy section found in Cargo.toml file!"
122 )
124 # package.json
125 if path.suffix == ".json" and "package" in path.name:
126 with open(path, "r", encoding="utf-8") as f:
127 input_content = json.load(f)
128 if "somesy" in input_content:
129 return input_content["somesy"]
130 else:
131 raise RuntimeError("No somesy section found in package.json file!")
133 # no match:
134 raise ValueError("Unsupported input file.")