feat: use settings for paths in cli and add tests
This commit is contained in:
@@ -14,6 +14,7 @@ dependencies = [
|
||||
"copier>=9.10.3",
|
||||
"gitpython>=3.1.50",
|
||||
"pydantic>=2.13.4",
|
||||
"pydantic-settings>=2.14.2",
|
||||
"pyyaml>=6.0.3",
|
||||
"typer>=0.23.2",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
from pathlib import Path
|
||||
|
||||
from pydantic import DirectoryPath, FilePath
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
from core.utils import get_git_root
|
||||
|
||||
REPO_ROOT = get_git_root(__file__)
|
||||
|
||||
|
||||
class Paths(BaseSettings):
|
||||
# fmt: off
|
||||
repo_root: DirectoryPath = REPO_ROOT
|
||||
|
||||
service_registry_file: FilePath = repo_root / "config" / "services_registry.yml"
|
||||
iocs_overview_filename: FilePath = repo_root / "docs" / "user" / "ioc" / "ioc_overview.md"
|
||||
master_hla_names_file: FilePath = repo_root / "services" / "master" / "current" / "app" / "config" / "hla_names.yml"
|
||||
master_ioc_subs_file: FilePath = repo_root / "services" / "master" / "current" / "ioc" / "AGEBD-CPCL-MASTER_main.subs"
|
||||
service_manager_ui_file: FilePath = repo_root / "qt" / "A_BD_ServiceManager.ui"
|
||||
# fmt: on
|
||||
|
||||
def relative(self, path: Path) -> str:
|
||||
"""
|
||||
Convert any absolute path into a string path relative to repo_root.
|
||||
"""
|
||||
return str(path.relative_to(self.repo_root))
|
||||
|
||||
def get_service_dir(self, service_dir_name: str) -> Path:
|
||||
"""
|
||||
Helper to get a service path dynamically.
|
||||
"""
|
||||
return self.repo_root / "services" / service_dir_name / "current"
|
||||
|
||||
|
||||
paths = Paths()
|
||||
+7
-21
@@ -1,27 +1,13 @@
|
||||
import re
|
||||
import xml.etree.ElementTree as ET
|
||||
from pathlib import Path
|
||||
from typing import Any, ClassVar
|
||||
|
||||
import yaml
|
||||
from pydantic import BaseModel, ConfigDict, field_validator
|
||||
|
||||
from config.paths import paths
|
||||
from core.enums import ServiceStatus
|
||||
from core.utils import get_git_root
|
||||
|
||||
REPO_ROOT = get_git_root(__file__)
|
||||
CONFIG_DIR = REPO_ROOT / "config"
|
||||
SERVICE_REGISTRY_FILENAME = CONFIG_DIR / "services_registry.yml"
|
||||
|
||||
MASTER_SERVICE_DIR = REPO_ROOT / "services" / "master" / "current"
|
||||
MASTER_SERVICE_CONFIG_DIR = MASTER_SERVICE_DIR / "app" / "config"
|
||||
MASTER_HLA_NAMES_FILENAME = MASTER_SERVICE_CONFIG_DIR / "hla_names.yml"
|
||||
|
||||
IOCS_OVERVIEW_FILENAME = REPO_ROOT / "docs" / "ioc" / "user" / "ioc_overview.md"
|
||||
|
||||
SERVICE_MANAGER_UI_FILENAME = REPO_ROOT / "qt" / "A_BD_ServiceManager.ui"
|
||||
|
||||
MASTER_SERVICE_DIR = REPO_ROOT / "services" / "master" / "current"
|
||||
MASTER_IOC_SUBS_FILE = MASTER_SERVICE_DIR / "ioc" / "AGEBD-CPCL-MASTER_main.subs"
|
||||
|
||||
|
||||
class Service(BaseModel):
|
||||
@@ -60,7 +46,7 @@ class Service(BaseModel):
|
||||
|
||||
|
||||
class ServiceRegistry(BaseModel):
|
||||
config_path: ClassVar[str] = str(SERVICE_REGISTRY_FILENAME)
|
||||
config_path: ClassVar[Path] = paths.service_registry_file
|
||||
|
||||
next_available_ioc_port: int
|
||||
services: list[dict]
|
||||
@@ -101,7 +87,7 @@ class ServiceRegistry(BaseModel):
|
||||
|
||||
|
||||
class MasterHLANames(BaseModel):
|
||||
config_path: ClassVar[str] = str(MASTER_HLA_NAMES_FILENAME)
|
||||
config_path: ClassVar[Path] = paths.master_hla_names_file
|
||||
|
||||
hla_apps: list[str]
|
||||
|
||||
@@ -122,7 +108,7 @@ class MasterHLANames(BaseModel):
|
||||
|
||||
|
||||
class IocsOverview(BaseModel):
|
||||
config_path: ClassVar[str] = str(IOCS_OVERVIEW_FILENAME)
|
||||
config_path: ClassVar[Path] = paths.iocs_overview_filename
|
||||
|
||||
content: str
|
||||
|
||||
@@ -148,7 +134,7 @@ class IocsOverview(BaseModel):
|
||||
|
||||
|
||||
class MasterIocSubs(BaseModel):
|
||||
config_path: ClassVar[str] = str(MASTER_IOC_SUBS_FILE)
|
||||
config_path: ClassVar[Path] = paths.master_ioc_subs_file
|
||||
|
||||
content: str
|
||||
|
||||
@@ -193,7 +179,7 @@ class MasterIocSubs(BaseModel):
|
||||
# TODO: maybe separate models into their own files
|
||||
class ServiceManagerUI(BaseModel):
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
config_path: ClassVar[str] = str(SERVICE_MANAGER_UI_FILENAME)
|
||||
config_path: ClassVar[Path] = paths.service_manager_ui_file
|
||||
|
||||
tree: Any
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ from pathlib import Path
|
||||
import copier
|
||||
import git
|
||||
|
||||
from config.paths import paths
|
||||
from core.exceptions import UVError
|
||||
from core.git import (
|
||||
assert_clean_repo,
|
||||
@@ -30,9 +31,6 @@ SERVICE_TEMPLATES_DIR = REPO_ROOT / "templates" / "service"
|
||||
SERVICE_DEST_DIR = REPO_ROOT / "services"
|
||||
|
||||
|
||||
# TODO: lots of hardcoded paths. Create config object?
|
||||
|
||||
|
||||
class ServiceCreator:
|
||||
def __init__(self, user: str, ioc_description: str, ui_name: str, ui_filename: str) -> None:
|
||||
self.user = user
|
||||
@@ -81,12 +79,12 @@ class ServiceCreator:
|
||||
service_manager.write_to_file()
|
||||
|
||||
files_to_stage = [
|
||||
f"services/{service.dir_name}/current",
|
||||
"config/services_registry.yml",
|
||||
"services/master/current/app/config/hla_names.yml",
|
||||
"services/master/current/ioc/AGEBD-CPCL-MASTER_main.subs",
|
||||
"docs/ioc/user/ioc_overview.md",
|
||||
"qt/A_BD_ServiceManager.ui",
|
||||
paths.relative(paths.get_service_dir(service.dir_name)),
|
||||
paths.relative(paths.service_registry_file),
|
||||
paths.relative(paths.master_hla_names_file),
|
||||
paths.relative(paths.master_ioc_subs_file),
|
||||
paths.relative(paths.iocs_overview_filename),
|
||||
paths.relative(paths.service_manager_ui_file),
|
||||
]
|
||||
# TODO: can't push if branch already exists in remote
|
||||
git_push_changes(
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
from config.paths import paths
|
||||
|
||||
|
||||
def test_paths():
|
||||
"""
|
||||
Will fail when paths is imported if a path is invalid
|
||||
"""
|
||||
assert True
|
||||
@@ -0,0 +1,6 @@
|
||||
from core.models import IocsOverview
|
||||
from core.service_creator import ServiceCreator
|
||||
|
||||
|
||||
def test_add_new_service():
|
||||
pass
|
||||
Generated
+49
@@ -8,12 +8,14 @@ version = "0.1.0"
|
||||
source = { editable = "../packages/agebd" }
|
||||
dependencies = [
|
||||
{ name = "h5py" },
|
||||
{ name = "pyepics" },
|
||||
{ name = "typer" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "h5py", specifier = ">=3.16.0" },
|
||||
{ name = "pyepics", specifier = ">=3.5.10" },
|
||||
{ name = "typer", specifier = ">=0.23.2" },
|
||||
]
|
||||
|
||||
@@ -36,6 +38,7 @@ dependencies = [
|
||||
{ name = "copier" },
|
||||
{ name = "gitpython" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pydantic-settings" },
|
||||
{ name = "pyyaml" },
|
||||
{ name = "typer" },
|
||||
]
|
||||
@@ -55,6 +58,7 @@ requires-dist = [
|
||||
{ name = "copier", specifier = ">=9.10.3" },
|
||||
{ name = "gitpython", specifier = ">=3.1.50" },
|
||||
{ name = "pydantic", specifier = ">=2.13.4" },
|
||||
{ name = "pydantic-settings", specifier = ">=2.14.2" },
|
||||
{ name = "pyyaml", specifier = ">=6.0.3" },
|
||||
{ name = "typer", specifier = ">=0.23.2" },
|
||||
]
|
||||
@@ -541,6 +545,33 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/01/aa/62f082da2c91fac1c234bc9ee0066257ce83f0604abd72e4c9d5991f2d84/pydantic_core-2.46.4-cp310-cp310-win_amd64.whl", hash = "sha256:8358a950c8909158e3df31538a7e4edc2d7265a7c54b47f0864d9e5bae9dcebf", size = 2074311, upload-time = "2026-05-06T13:39:59.922Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-settings"
|
||||
version = "2.14.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pydantic" },
|
||||
{ name = "python-dotenv" },
|
||||
{ name = "typing-inspection" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5c/b5/8f48e906c3e0205276e8bd8cb7512217a87b2685304d64be27cad5b3019f/pydantic_settings-2.14.2.tar.gz", hash = "sha256:c19dd64b19097f1de80184f0cc7b0272a13ae6e170cbf240a3e27e381ed14a5f", size = 237700, upload-time = "2026-06-19T13:44:56.324Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl", hash = "sha256:a20c97b37910b6550d5ea50fbcc2d4187defe58cd57070b73863d069419c9440", size = 61715, upload-time = "2026-06-19T13:44:55.02Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyepics"
|
||||
version = "3.5.10"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "numpy" },
|
||||
{ name = "pyparsing" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/69/57/29e1e9ef11ba2a3419f489946ae1d8190025a1e4f4e1c1686758bb2b6e0a/pyepics-3.5.10.tar.gz", hash = "sha256:f390cf9be40aba757b9528888114bc14d8db01086d0c93914720b1772460375b", size = 6150481, upload-time = "2026-05-20T18:44:36.336Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/36/e517fd83bd97d6bfe4105e0c6b322070c5cc36fb56a8fab2866e319f8804/pyepics-3.5.10-py3-none-any.whl", hash = "sha256:c9fac2c54f2b595268e66fc348cf5ec24e63718e7dbd07d73d1b37d4da6bfee1", size = 5332376, upload-time = "2026-05-20T18:44:34.242Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.20.0"
|
||||
@@ -550,6 +581,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyparsing"
|
||||
version = "3.3.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyright"
|
||||
version = "1.1.411"
|
||||
@@ -593,6 +633,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/45/3c/b88167e2d6785c0e781ee5d498b07472aeb9b6765da3b19e7cc9e0813841/python_daemon-3.1.2-py3-none-any.whl", hash = "sha256:b906833cef63502994ad48e2eab213259ed9bb18d54fa8774dcba2ff7864cec6", size = 30872, upload-time = "2024-12-03T08:41:03.322Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "1.2.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyyaml"
|
||||
version = "6.0.3"
|
||||
|
||||
Reference in New Issue
Block a user