diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-28 10:23:34 +0100 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-28 10:23:34 +0100 |
| commit | 8431493b1de912196ea66b9f27c89e4c68658d56 (patch) | |
| tree | 37bab84bd69aa40d824f42b14ed2bc164c0e2b9c | |
| parent | decd09d78505572634a7681e3c1c6b859d2d2f06 (diff) | |
| download | generat3D-8431493b1de912196ea66b9f27c89e4c68658d56.tar.gz generat3D-8431493b1de912196ea66b9f27c89e4c68658d56.zip | |
Add package base and config loading
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
| -rw-r--r-- | generat3d/__init__.py | 28 | ||||
| -rw-r--r-- | generat3d/config.py | 56 | ||||
| -rw-r--r-- | tests/__init__.py | 0 | ||||
| -rw-r--r-- | tests/test_config.py | 81 |
4 files changed, 165 insertions, 0 deletions
diff --git a/generat3d/__init__.py b/generat3d/__init__.py new file mode 100644 index 0000000..917b0c7 --- /dev/null +++ b/generat3d/__init__.py @@ -0,0 +1,28 @@ +# generat3D - evaluate Daz DSON scenes and write .dbz files +# Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import sys + +__version__ = "0.1.0" + + +class Error(Exception): + """Fatal problem. The CLI prints it and exits 1.""" + + +def warn(msg): + print(f"generat3d: warning: {msg}", file=sys.stderr) diff --git a/generat3d/config.py b/generat3d/config.py new file mode 100644 index 0000000..9ea7266 --- /dev/null +++ b/generat3d/config.py @@ -0,0 +1,56 @@ +# generat3D - evaluate Daz DSON scenes and write .dbz files +# Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import os +import tomllib +from pathlib import Path + +from . import Error + +KEYS = {"library_roots"} + + +def config_path(): + base = os.environ.get("XDG_CONFIG_HOME") or os.path.expanduser("~/.config") + return Path(base) / "generat3d" / "config.toml" + + +def library_roots(cli_roots, path=None): + """Library roots from -L if given (replacing the config), else from the config file.""" + path = Path(path) if path else config_path() + roots = list(cli_roots) + if not roots and path.exists(): + try: + with open(path, "rb") as f: + data = tomllib.load(f) + except tomllib.TOMLDecodeError as e: + raise Error(f"{path}: {e}") from None + unknown = sorted(set(data) - KEYS) + if unknown: + raise Error(f"{path}: unknown keys: {', '.join(unknown)}") + roots = data.get("library_roots", []) + if not isinstance(roots, list) or not all(isinstance(r, str) for r in roots): + raise Error(f"{path}: library_roots must be a list of strings") + if not roots: + raise Error(f"no library roots: pass -L or set library_roots in {path}") + out = [] + for r in roots: + p = Path(r).expanduser() + if not p.is_dir(): + raise Error(f"library root not found: {p}") + out.append(p) + return out diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/__init__.py diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 0000000..d1ad0d2 --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,81 @@ +# generat3D - evaluate Daz DSON scenes and write .dbz files +# Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import os +import tempfile +import unittest +from pathlib import Path + +from generat3d import Error +from generat3d.config import config_path, library_roots + + +class ConfigTest(unittest.TestCase): + def setUp(self): + self.tmp = tempfile.TemporaryDirectory() + self.dir = Path(self.tmp.name) + self.lib = self.dir / "lib" + self.lib.mkdir() + self.cfg = self.dir / "config.toml" + + def tearDown(self): + self.tmp.cleanup() + + def write(self, text): + self.cfg.write_text(text) + + def test_cli_roots_win_over_config(self): + self.write('library_roots = ["/nonexistent"]\n') + self.assertEqual(library_roots([str(self.lib)], self.cfg), [self.lib]) + + def test_roots_from_config(self): + self.write(f'library_roots = ["{self.lib}"]\n') + self.assertEqual(library_roots([], self.cfg), [self.lib]) + + def test_no_roots_anywhere(self): + with self.assertRaisesRegex(Error, "no library roots"): + library_roots([], self.cfg) + + def test_missing_root_is_fatal(self): + with self.assertRaisesRegex(Error, "library root not found"): + library_roots([str(self.dir / "nope")], self.cfg) + + def test_unknown_key_is_fatal(self): + self.write(f'library_roots = ["{self.lib}"]\nlibary = 1\n') + with self.assertRaisesRegex(Error, "unknown keys: libary"): + library_roots([], self.cfg) + + def test_bad_type_is_fatal(self): + self.write('library_roots = "/x"\n') + with self.assertRaisesRegex(Error, "list of strings"): + library_roots([], self.cfg) + + def test_bad_toml_is_fatal(self): + self.write("library_roots = [\n") + with self.assertRaisesRegex(Error, "config.toml"): + library_roots([], self.cfg) + + def test_xdg_config_home(self): + old = os.environ.get("XDG_CONFIG_HOME") + os.environ["XDG_CONFIG_HOME"] = "/tmp/xdg" + try: + self.assertEqual(config_path(), Path("/tmp/xdg/generat3d/config.toml")) + finally: + if old is None: + del os.environ["XDG_CONFIG_HOME"] + else: + os.environ["XDG_CONFIG_HOME"] = old |
