From 99adb6baaf2e7810360fc71677708c05f32bb9c9 Mon Sep 17 00:00:00 2001 From: Ollie Copping Date: Tue, 23 Sep 2025 14:58:30 +0000 Subject: [PATCH 1/8] Add initial devsta generation prototype Add epicsdbbuilder dependency --- .../b23-services/synoptic/techui.yaml | 5 + pyproject.toml | 2 + src/techui_builder/__main__.py | 1 + src/techui_builder/builder.py | 39 +++++ uv.lock | 152 ++++++++++++++++++ 5 files changed, 199 insertions(+) diff --git a/example-synoptic/b23-services/synoptic/techui.yaml b/example-synoptic/b23-services/synoptic/techui.yaml index 26ef7b1f..77f4e837 100644 --- a/example-synoptic/b23-services/synoptic/techui.yaml +++ b/example-synoptic/b23-services/synoptic/techui.yaml @@ -134,11 +134,16 @@ components: M2: prefix: FE23B-OP-MR-02 + devsta: + - FE23B-OP-MR-02:MOTORSTA M3: prefix: BL23B-OP-MR-03 extras: - BL23B-MO-PMAC-01 + devsta: + - BL23B-OP-MR-03:MOTORSTA + - BL23B-MO-PMAC-01:MOTORSTA # ----- MOD ----- diff --git a/pyproject.toml b/pyproject.toml index 0501d3f6..eb719b3b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,8 @@ dependencies = [ "typer>=0.16.0", "rich>=14.1.0", "pydantic>=2.11.7", + "softioc>=4.6.1", + "epicsdbbuilder>=1.5", ] scripts = { techui-builder = "techui_builder.__main__:app" } diff --git a/src/techui_builder/__main__.py b/src/techui_builder/__main__.py index 2867e1e1..9ed744b4 100644 --- a/src/techui_builder/__main__.py +++ b/src/techui_builder/__main__.py @@ -156,6 +156,7 @@ def main( gui.setup() gui.create_screens() + gui.write_devsta_pvs() logger_.info(f"Screens generated for {gui.conf.beamline.short_dom}.") diff --git a/src/techui_builder/builder.py b/src/techui_builder/builder.py index 6338f0f1..b0e3ffcd 100644 --- a/src/techui_builder/builder.py +++ b/src/techui_builder/builder.py @@ -7,8 +7,10 @@ from typing import Any import yaml +from epicsdbbuilder.recordbase import Record from lxml import etree, objectify from lxml.objectify import ObjectifiedElement +from softioc.builder import records from techui_builder.generate import Generator from techui_builder.models import Entity, TechUi @@ -45,6 +47,7 @@ class Builder: entities: defaultdict[str, list[Entity]] = field( default_factory=lambda: defaultdict(list), init=False ) + devsta_pvs: dict[str, Record] = field(default_factory=dict, init=False) _services_dir: Path = field(init=False, repr=False) _gui_map: dict = field(init=False, repr=False) _write_directory: Path = field(default=Path("opis"), init=False, repr=False) @@ -96,6 +99,38 @@ def clean_files(self): logger_.debug(f"Removing generated file: {file_.name}") os.remove(file_) + def _create_devsta_pv(self, prefix: str, inputs: list[str]): + # Extract all input PVs, provided a default "" if not provided + values = [(inputs[i] if i < len(inputs) else "") for i in range(12)] + inpa, inpb, inpc, inpd, inpe, inpf, inpg, inph, inpi, inpj, inpk, inpl = values + + devsta_pv = records.calc( # pyright: ignore[reportAttributeAccessIssue] + f"{prefix}:DEVSTA", + CALC="(A|B|C|D|E|F|G|H|I|J|K|L)>0?1:0", + SCAN="1 second", + ACKT="NO", + INPA=inpa, + INPB=inpb, + INPC=inpc, + INPD=inpd, + INPE=inpe, + INPF=inpf, + INPG=inpg, + INPH=inph, + INPI=inpi, + INPJ=inpj, + INPK=inpk, + INPL=inpl, + ) + + self.devsta_pvs[prefix] = devsta_pv + + def write_devsta_pvs(self): + devsta_file = self._write_directory.parent.joinpath("config/ioc.db") + with open(devsta_file, "w") as f: + for dpv in self.devsta_pvs.values(): + dpv.Print(f) + def _extract_services(self): """ Finds the services folders in the services directory @@ -154,6 +189,10 @@ def create_screens(self): # any extras defined for component_name, component in self.conf.components.items(): screen_entities: list[Entity] = [] + + if component.devsta is not None: + self._create_devsta_pv(component.prefix, component.devsta) + # ONLY IF there is a matching component and entity, generate a screen if component.prefix in self.entities.keys(): screen_entities.extend(self.entities[component.prefix]) diff --git a/uv.lock b/uv.lock index bdce5533..ab44643d 100644 --- a/uv.lock +++ b/uv.lock @@ -278,6 +278,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/36/41/04e2a649058b0713b00d6c9bd22da35618bb157289e05d068e51fddf8d7e/dunamai-1.25.0-py3-none-any.whl", hash = "sha256:7f9dc687dd3256e613b6cc978d9daabfd2bb5deb8adc541fc135ee423ffa98ab", size = 27022, upload-time = "2025-07-04T19:25:54.863Z" }, ] +[[package]] +name = "epicscorelibs" +version = "7.0.7.99.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "setuptools" }, + { name = "setuptools-dso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/80/07/d820b96a0e8d6b99742f984788d7679d5a60000f99c2ee10094ddc4baf53/epicscorelibs-7.0.7.99.1.2.tar.gz", hash = "sha256:2a74a53b438bbbbeef13c74640a4d3060d35de78ce8989f3158148f38534cd43", size = 1630005, upload-time = "2025-07-31T08:11:59.809Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/eb/44475b09aef9ffc31d3b6f5028fa3cbffd1144a3a87c3a87349a2991e6d1/epicscorelibs-7.0.7.99.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f44f67edd96a0da13d99e9fc798c8b49c4441475cc732257a00c17923e6c5b74", size = 7768865, upload-time = "2025-07-31T08:14:18.201Z" }, + { url = "https://files.pythonhosted.org/packages/50/54/5357954339fb1d722771dfc11a2ece67ffe8aeb8ec976be841bfe42752fa/epicscorelibs-7.0.7.99.1.2-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:0fe1960c2db0d6480bb0389616d2803aeca6a5836d12b1857d6c4c063f7cf709", size = 5378307, upload-time = "2025-07-31T08:12:36.774Z" }, + { url = "https://files.pythonhosted.org/packages/cb/63/4787c4a86ba45fdfdb9905da647a9b537ae80be7e7be0084a17871212ee9/epicscorelibs-7.0.7.99.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:6949d1596362deec124fbbd09a86ee3b21caeb3ac75a7e80d59addec07bb6942", size = 2502786, upload-time = "2025-07-31T08:18:21.809Z" }, + { url = "https://files.pythonhosted.org/packages/c2/67/2b7f4e76a102a66e48a25b3278df09b7547eed5df1cef73e9396ec49df3b/epicscorelibs-7.0.7.99.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4106d707c5c6a1c35155adbea03275b64fa4c77adba1e820cc8f1dbe3faf62c3", size = 7769136, upload-time = "2025-07-31T08:19:01.16Z" }, + { url = "https://files.pythonhosted.org/packages/a2/af/6bb0e1de4fb7218fa4ba95fe91ba1fd4a5661dd28a461eff6a0f609c996c/epicscorelibs-7.0.7.99.1.2-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:be8f328fe16b13fa9ca1dabf85c53561a3209b3c5df693c6b959351f6d11fabc", size = 5378303, upload-time = "2025-07-31T08:12:39.169Z" }, + { url = "https://files.pythonhosted.org/packages/46/72/fef75e967d5663359739ef23310cfc37e84149bc4190aa8f95482feaa99e/epicscorelibs-7.0.7.99.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:0cd102e3f2292d10441b675e8cf7c2fcbaf4e4b0474b9d3813ed3cdeea7a1508", size = 2502677, upload-time = "2025-07-31T08:18:33.207Z" }, +] + +[[package]] +name = "epicsdbbuilder" +version = "1.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/31/c1b5f49621934d1bcd87d306817d9d81fa5d0935476d7ba73b98181f6557/epicsdbbuilder-1.5.tar.gz", hash = "sha256:698ad5882de4a626a82086139ff95204e8de72e63d03d9f22d4418da3a6c8566", size = 19193, upload-time = "2021-12-17T14:05:58.106Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/f8/858c81f516cb9d1c1f73e8bf379be2cbec4388c93f48a4eb118c47f32d4d/epicsdbbuilder-1.5-py3-none-any.whl", hash = "sha256:ae8dc724c72478d2c6a68b08145d027a50af98702d17e4692f2d73f145818e74", size = 23682, upload-time = "2021-12-17T14:05:57.141Z" }, +] + [[package]] name = "filelock" version = "3.20.0" @@ -537,6 +565,69 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ad/b7/bc0cdbc2cc3a66fcac82c79912e135a0110b37b790a14c477f18e18d90cd/nodejs_wheel_binaries-24.11.1-py2.py3-none-win_arm64.whl", hash = "sha256:376b9ea1c4bc1207878975dfeb604f7aa5668c260c6154dcd2af9d42f7734116", size = 39026497, upload-time = "2025-11-18T18:21:54.634Z" }, ] +[[package]] +name = "numpy" +version = "2.3.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/19/95b3d357407220ed24c139018d2518fab0a61a948e68286a25f1a4d049ff/numpy-2.3.3.tar.gz", hash = "sha256:ddc7c39727ba62b80dfdbedf400d1c10ddfa8eefbd7ec8dcb118be8b56d31029", size = 20576648, upload-time = "2025-09-09T16:54:12.543Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/5d/bb7fc075b762c96329147799e1bcc9176ab07ca6375ea976c475482ad5b3/numpy-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cfdd09f9c84a1a934cde1eec2267f0a43a7cd44b2cca4ff95b7c0d14d144b0bf", size = 20957014, upload-time = "2025-09-09T15:56:29.966Z" }, + { url = "https://files.pythonhosted.org/packages/6b/0e/c6211bb92af26517acd52125a237a92afe9c3124c6a68d3b9f81b62a0568/numpy-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb32e3cf0f762aee47ad1ddc6672988f7f27045b0783c887190545baba73aa25", size = 14185220, upload-time = "2025-09-09T15:56:32.175Z" }, + { url = "https://files.pythonhosted.org/packages/22/f2/07bb754eb2ede9073f4054f7c0286b0d9d2e23982e090a80d478b26d35ca/numpy-2.3.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:396b254daeb0a57b1fe0ecb5e3cff6fa79a380fa97c8f7781a6d08cd429418fe", size = 5113918, upload-time = "2025-09-09T15:56:34.175Z" }, + { url = "https://files.pythonhosted.org/packages/81/0a/afa51697e9fb74642f231ea36aca80fa17c8fb89f7a82abd5174023c3960/numpy-2.3.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:067e3d7159a5d8f8a0b46ee11148fc35ca9b21f61e3c49fbd0a027450e65a33b", size = 6647922, upload-time = "2025-09-09T15:56:36.149Z" }, + { url = "https://files.pythonhosted.org/packages/5d/f5/122d9cdb3f51c520d150fef6e87df9279e33d19a9611a87c0d2cf78a89f4/numpy-2.3.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c02d0629d25d426585fb2e45a66154081b9fa677bc92a881ff1d216bc9919a8", size = 14281991, upload-time = "2025-09-09T15:56:40.548Z" }, + { url = "https://files.pythonhosted.org/packages/51/64/7de3c91e821a2debf77c92962ea3fe6ac2bc45d0778c1cbe15d4fce2fd94/numpy-2.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9192da52b9745f7f0766531dcfa978b7763916f158bb63bdb8a1eca0068ab20", size = 16641643, upload-time = "2025-09-09T15:56:43.343Z" }, + { url = "https://files.pythonhosted.org/packages/30/e4/961a5fa681502cd0d68907818b69f67542695b74e3ceaa513918103b7e80/numpy-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cd7de500a5b66319db419dc3c345244404a164beae0d0937283b907d8152e6ea", size = 16056787, upload-time = "2025-09-09T15:56:46.141Z" }, + { url = "https://files.pythonhosted.org/packages/99/26/92c912b966e47fbbdf2ad556cb17e3a3088e2e1292b9833be1dfa5361a1a/numpy-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:93d4962d8f82af58f0b2eb85daaf1b3ca23fe0a85d0be8f1f2b7bb46034e56d7", size = 18579598, upload-time = "2025-09-09T15:56:49.844Z" }, + { url = "https://files.pythonhosted.org/packages/17/b6/fc8f82cb3520768718834f310c37d96380d9dc61bfdaf05fe5c0b7653e01/numpy-2.3.3-cp312-cp312-win32.whl", hash = "sha256:5534ed6b92f9b7dca6c0a19d6df12d41c68b991cef051d108f6dbff3babc4ebf", size = 6320800, upload-time = "2025-09-09T15:56:52.499Z" }, + { url = "https://files.pythonhosted.org/packages/32/ee/de999f2625b80d043d6d2d628c07d0d5555a677a3cf78fdf868d409b8766/numpy-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:497d7cad08e7092dba36e3d296fe4c97708c93daf26643a1ae4b03f6294d30eb", size = 12786615, upload-time = "2025-09-09T15:56:54.422Z" }, + { url = "https://files.pythonhosted.org/packages/49/6e/b479032f8a43559c383acb20816644f5f91c88f633d9271ee84f3b3a996c/numpy-2.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:ca0309a18d4dfea6fc6262a66d06c26cfe4640c3926ceec90e57791a82b6eee5", size = 10195936, upload-time = "2025-09-09T15:56:56.541Z" }, + { url = "https://files.pythonhosted.org/packages/7d/b9/984c2b1ee61a8b803bf63582b4ac4242cf76e2dbd663efeafcb620cc0ccb/numpy-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f5415fb78995644253370985342cd03572ef8620b934da27d77377a2285955bf", size = 20949588, upload-time = "2025-09-09T15:56:59.087Z" }, + { url = "https://files.pythonhosted.org/packages/a6/e4/07970e3bed0b1384d22af1e9912527ecbeb47d3b26e9b6a3bced068b3bea/numpy-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d00de139a3324e26ed5b95870ce63be7ec7352171bc69a4cf1f157a48e3eb6b7", size = 14177802, upload-time = "2025-09-09T15:57:01.73Z" }, + { url = "https://files.pythonhosted.org/packages/35/c7/477a83887f9de61f1203bad89cf208b7c19cc9fef0cebef65d5a1a0619f2/numpy-2.3.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:9dc13c6a5829610cc07422bc74d3ac083bd8323f14e2827d992f9e52e22cd6a6", size = 5106537, upload-time = "2025-09-09T15:57:03.765Z" }, + { url = "https://files.pythonhosted.org/packages/52/47/93b953bd5866a6f6986344d045a207d3f1cfbad99db29f534ea9cee5108c/numpy-2.3.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d79715d95f1894771eb4e60fb23f065663b2298f7d22945d66877aadf33d00c7", size = 6640743, upload-time = "2025-09-09T15:57:07.921Z" }, + { url = "https://files.pythonhosted.org/packages/23/83/377f84aaeb800b64c0ef4de58b08769e782edcefa4fea712910b6f0afd3c/numpy-2.3.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:952cfd0748514ea7c3afc729a0fc639e61655ce4c55ab9acfab14bda4f402b4c", size = 14278881, upload-time = "2025-09-09T15:57:11.349Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a5/bf3db6e66c4b160d6ea10b534c381a1955dfab34cb1017ea93aa33c70ed3/numpy-2.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b83648633d46f77039c29078751f80da65aa64d5622a3cd62aaef9d835b6c93", size = 16636301, upload-time = "2025-09-09T15:57:14.245Z" }, + { url = "https://files.pythonhosted.org/packages/a2/59/1287924242eb4fa3f9b3a2c30400f2e17eb2707020d1c5e3086fe7330717/numpy-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b001bae8cea1c7dfdb2ae2b017ed0a6f2102d7a70059df1e338e307a4c78a8ae", size = 16053645, upload-time = "2025-09-09T15:57:16.534Z" }, + { url = "https://files.pythonhosted.org/packages/e6/93/b3d47ed882027c35e94ac2320c37e452a549f582a5e801f2d34b56973c97/numpy-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8e9aced64054739037d42fb84c54dd38b81ee238816c948c8f3ed134665dcd86", size = 18578179, upload-time = "2025-09-09T15:57:18.883Z" }, + { url = "https://files.pythonhosted.org/packages/20/d9/487a2bccbf7cc9d4bfc5f0f197761a5ef27ba870f1e3bbb9afc4bbe3fcc2/numpy-2.3.3-cp313-cp313-win32.whl", hash = "sha256:9591e1221db3f37751e6442850429b3aabf7026d3b05542d102944ca7f00c8a8", size = 6312250, upload-time = "2025-09-09T15:57:21.296Z" }, + { url = "https://files.pythonhosted.org/packages/1b/b5/263ebbbbcede85028f30047eab3d58028d7ebe389d6493fc95ae66c636ab/numpy-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f0dadeb302887f07431910f67a14d57209ed91130be0adea2f9793f1a4f817cf", size = 12783269, upload-time = "2025-09-09T15:57:23.034Z" }, + { url = "https://files.pythonhosted.org/packages/fa/75/67b8ca554bbeaaeb3fac2e8bce46967a5a06544c9108ec0cf5cece559b6c/numpy-2.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:3c7cf302ac6e0b76a64c4aecf1a09e51abd9b01fc7feee80f6c43e3ab1b1dbc5", size = 10195314, upload-time = "2025-09-09T15:57:25.045Z" }, + { url = "https://files.pythonhosted.org/packages/11/d0/0d1ddec56b162042ddfafeeb293bac672de9b0cfd688383590090963720a/numpy-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:eda59e44957d272846bb407aad19f89dc6f58fecf3504bd144f4c5cf81a7eacc", size = 21048025, upload-time = "2025-09-09T15:57:27.257Z" }, + { url = "https://files.pythonhosted.org/packages/36/9e/1996ca6b6d00415b6acbdd3c42f7f03ea256e2c3f158f80bd7436a8a19f3/numpy-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:823d04112bc85ef5c4fda73ba24e6096c8f869931405a80aa8b0e604510a26bc", size = 14301053, upload-time = "2025-09-09T15:57:30.077Z" }, + { url = "https://files.pythonhosted.org/packages/05/24/43da09aa764c68694b76e84b3d3f0c44cb7c18cdc1ba80e48b0ac1d2cd39/numpy-2.3.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:40051003e03db4041aa325da2a0971ba41cf65714e65d296397cc0e32de6018b", size = 5229444, upload-time = "2025-09-09T15:57:32.733Z" }, + { url = "https://files.pythonhosted.org/packages/bc/14/50ffb0f22f7218ef8af28dd089f79f68289a7a05a208db9a2c5dcbe123c1/numpy-2.3.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6ee9086235dd6ab7ae75aba5662f582a81ced49f0f1c6de4260a78d8f2d91a19", size = 6738039, upload-time = "2025-09-09T15:57:34.328Z" }, + { url = "https://files.pythonhosted.org/packages/55/52/af46ac0795e09657d45a7f4db961917314377edecf66db0e39fa7ab5c3d3/numpy-2.3.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94fcaa68757c3e2e668ddadeaa86ab05499a70725811e582b6a9858dd472fb30", size = 14352314, upload-time = "2025-09-09T15:57:36.255Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b1/dc226b4c90eb9f07a3fff95c2f0db3268e2e54e5cce97c4ac91518aee71b/numpy-2.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da1a74b90e7483d6ce5244053399a614b1d6b7bc30a60d2f570e5071f8959d3e", size = 16701722, upload-time = "2025-09-09T15:57:38.622Z" }, + { url = "https://files.pythonhosted.org/packages/9d/9d/9d8d358f2eb5eced14dba99f110d83b5cd9a4460895230f3b396ad19a323/numpy-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2990adf06d1ecee3b3dcbb4977dfab6e9f09807598d647f04d385d29e7a3c3d3", size = 16132755, upload-time = "2025-09-09T15:57:41.16Z" }, + { url = "https://files.pythonhosted.org/packages/b6/27/b3922660c45513f9377b3fb42240bec63f203c71416093476ec9aa0719dc/numpy-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ed635ff692483b8e3f0fcaa8e7eb8a75ee71aa6d975388224f70821421800cea", size = 18651560, upload-time = "2025-09-09T15:57:43.459Z" }, + { url = "https://files.pythonhosted.org/packages/5b/8e/3ab61a730bdbbc201bb245a71102aa609f0008b9ed15255500a99cd7f780/numpy-2.3.3-cp313-cp313t-win32.whl", hash = "sha256:a333b4ed33d8dc2b373cc955ca57babc00cd6f9009991d9edc5ddbc1bac36bcd", size = 6442776, upload-time = "2025-09-09T15:57:45.793Z" }, + { url = "https://files.pythonhosted.org/packages/1c/3a/e22b766b11f6030dc2decdeff5c2fb1610768055603f9f3be88b6d192fb2/numpy-2.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:4384a169c4d8f97195980815d6fcad04933a7e1ab3b530921c3fef7a1c63426d", size = 12927281, upload-time = "2025-09-09T15:57:47.492Z" }, + { url = "https://files.pythonhosted.org/packages/7b/42/c2e2bc48c5e9b2a83423f99733950fbefd86f165b468a3d85d52b30bf782/numpy-2.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:75370986cc0bc66f4ce5110ad35aae6d182cc4ce6433c40ad151f53690130bf1", size = 10265275, upload-time = "2025-09-09T15:57:49.647Z" }, + { url = "https://files.pythonhosted.org/packages/6b/01/342ad585ad82419b99bcf7cebe99e61da6bedb89e213c5fd71acc467faee/numpy-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cd052f1fa6a78dee696b58a914b7229ecfa41f0a6d96dc663c1220a55e137593", size = 20951527, upload-time = "2025-09-09T15:57:52.006Z" }, + { url = "https://files.pythonhosted.org/packages/ef/d8/204e0d73fc1b7a9ee80ab1fe1983dd33a4d64a4e30a05364b0208e9a241a/numpy-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:414a97499480067d305fcac9716c29cf4d0d76db6ebf0bf3cbce666677f12652", size = 14186159, upload-time = "2025-09-09T15:57:54.407Z" }, + { url = "https://files.pythonhosted.org/packages/22/af/f11c916d08f3a18fb8ba81ab72b5b74a6e42ead4c2846d270eb19845bf74/numpy-2.3.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:50a5fe69f135f88a2be9b6ca0481a68a136f6febe1916e4920e12f1a34e708a7", size = 5114624, upload-time = "2025-09-09T15:57:56.5Z" }, + { url = "https://files.pythonhosted.org/packages/fb/11/0ed919c8381ac9d2ffacd63fd1f0c34d27e99cab650f0eb6f110e6ae4858/numpy-2.3.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:b912f2ed2b67a129e6a601e9d93d4fa37bef67e54cac442a2f588a54afe5c67a", size = 6642627, upload-time = "2025-09-09T15:57:58.206Z" }, + { url = "https://files.pythonhosted.org/packages/ee/83/deb5f77cb0f7ba6cb52b91ed388b47f8f3c2e9930d4665c600408d9b90b9/numpy-2.3.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e318ee0596d76d4cb3d78535dc005fa60e5ea348cd131a51e99d0bdbe0b54fe", size = 14296926, upload-time = "2025-09-09T15:58:00.035Z" }, + { url = "https://files.pythonhosted.org/packages/77/cc/70e59dcb84f2b005d4f306310ff0a892518cc0c8000a33d0e6faf7ca8d80/numpy-2.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce020080e4a52426202bdb6f7691c65bb55e49f261f31a8f506c9f6bc7450421", size = 16638958, upload-time = "2025-09-09T15:58:02.738Z" }, + { url = "https://files.pythonhosted.org/packages/b6/5a/b2ab6c18b4257e099587d5b7f903317bd7115333ad8d4ec4874278eafa61/numpy-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e6687dc183aa55dae4a705b35f9c0f8cb178bcaa2f029b241ac5356221d5c021", size = 16071920, upload-time = "2025-09-09T15:58:05.029Z" }, + { url = "https://files.pythonhosted.org/packages/b8/f1/8b3fdc44324a259298520dd82147ff648979bed085feeacc1250ef1656c0/numpy-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d8f3b1080782469fdc1718c4ed1d22549b5fb12af0d57d35e992158a772a37cf", size = 18577076, upload-time = "2025-09-09T15:58:07.745Z" }, + { url = "https://files.pythonhosted.org/packages/f0/a1/b87a284fb15a42e9274e7fcea0dad259d12ddbf07c1595b26883151ca3b4/numpy-2.3.3-cp314-cp314-win32.whl", hash = "sha256:cb248499b0bc3be66ebd6578b83e5acacf1d6cb2a77f2248ce0e40fbec5a76d0", size = 6366952, upload-time = "2025-09-09T15:58:10.096Z" }, + { url = "https://files.pythonhosted.org/packages/70/5f/1816f4d08f3b8f66576d8433a66f8fa35a5acfb3bbd0bf6c31183b003f3d/numpy-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:691808c2b26b0f002a032c73255d0bd89751425f379f7bcd22d140db593a96e8", size = 12919322, upload-time = "2025-09-09T15:58:12.138Z" }, + { url = "https://files.pythonhosted.org/packages/8c/de/072420342e46a8ea41c324a555fa90fcc11637583fb8df722936aed1736d/numpy-2.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:9ad12e976ca7b10f1774b03615a2a4bab8addce37ecc77394d8e986927dc0dfe", size = 10478630, upload-time = "2025-09-09T15:58:14.64Z" }, + { url = "https://files.pythonhosted.org/packages/d5/df/ee2f1c0a9de7347f14da5dd3cd3c3b034d1b8607ccb6883d7dd5c035d631/numpy-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9cc48e09feb11e1db00b320e9d30a4151f7369afb96bd0e48d942d09da3a0d00", size = 21047987, upload-time = "2025-09-09T15:58:16.889Z" }, + { url = "https://files.pythonhosted.org/packages/d6/92/9453bdc5a4e9e69cf4358463f25e8260e2ffc126d52e10038b9077815989/numpy-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:901bf6123879b7f251d3631967fd574690734236075082078e0571977c6a8e6a", size = 14301076, upload-time = "2025-09-09T15:58:20.343Z" }, + { url = "https://files.pythonhosted.org/packages/13/77/1447b9eb500f028bb44253105bd67534af60499588a5149a94f18f2ca917/numpy-2.3.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:7f025652034199c301049296b59fa7d52c7e625017cae4c75d8662e377bf487d", size = 5229491, upload-time = "2025-09-09T15:58:22.481Z" }, + { url = "https://files.pythonhosted.org/packages/3d/f9/d72221b6ca205f9736cb4b2ce3b002f6e45cd67cd6a6d1c8af11a2f0b649/numpy-2.3.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:533ca5f6d325c80b6007d4d7fb1984c303553534191024ec6a524a4c92a5935a", size = 6737913, upload-time = "2025-09-09T15:58:24.569Z" }, + { url = "https://files.pythonhosted.org/packages/3c/5f/d12834711962ad9c46af72f79bb31e73e416ee49d17f4c797f72c96b6ca5/numpy-2.3.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0edd58682a399824633b66885d699d7de982800053acf20be1eaa46d92009c54", size = 14352811, upload-time = "2025-09-09T15:58:26.416Z" }, + { url = "https://files.pythonhosted.org/packages/a1/0d/fdbec6629d97fd1bebed56cd742884e4eead593611bbe1abc3eb40d304b2/numpy-2.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:367ad5d8fbec5d9296d18478804a530f1191e24ab4d75ab408346ae88045d25e", size = 16702689, upload-time = "2025-09-09T15:58:28.831Z" }, + { url = "https://files.pythonhosted.org/packages/9b/09/0a35196dc5575adde1eb97ddfbc3e1687a814f905377621d18ca9bc2b7dd/numpy-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8f6ac61a217437946a1fa48d24c47c91a0c4f725237871117dea264982128097", size = 16133855, upload-time = "2025-09-09T15:58:31.349Z" }, + { url = "https://files.pythonhosted.org/packages/7a/ca/c9de3ea397d576f1b6753eaa906d4cdef1bf97589a6d9825a349b4729cc2/numpy-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:179a42101b845a816d464b6fe9a845dfaf308fdfc7925387195570789bb2c970", size = 18652520, upload-time = "2025-09-09T15:58:33.762Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c2/e5ed830e08cd0196351db55db82f65bc0ab05da6ef2b72a836dcf1936d2f/numpy-2.3.3-cp314-cp314t-win32.whl", hash = "sha256:1250c5d3d2562ec4174bce2e3a1523041595f9b651065e4a4473f5f48a6bc8a5", size = 6515371, upload-time = "2025-09-09T15:58:36.04Z" }, + { url = "https://files.pythonhosted.org/packages/47/c7/b0f6b5b67f6788a0725f744496badbb604d226bf233ba716683ebb47b570/numpy-2.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b37a0b2e5935409daebe82c1e42274d30d9dd355852529eab91dab8dcca7419f", size = 13112576, upload-time = "2025-09-09T15:58:37.927Z" }, + { url = "https://files.pythonhosted.org/packages/06/b9/33bba5ff6fb679aa0b1f8a07e853f002a6b04b9394db3069a1270a7784ca/numpy-2.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:78c9f6560dc7e6b3990e32df7ea1a50bbd0e2a111e05209963f5ddcab7073b0b", size = 10545953, upload-time = "2025-09-09T15:58:40.576Z" }, +] + [[package]] name = "packaging" version = "25.0" @@ -622,6 +713,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, ] +[[package]] +name = "pvxslibs" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "epicscorelibs" }, + { name = "setuptools-dso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/30/c6ca9c4a61cab42a271d5d030a8f65cf9141979b5f0fbc2ce563b712d9e7/pvxslibs-1.4.0.tar.gz", hash = "sha256:1368cfd521edf15be2f8c4491c7ca3893b77712139f19b9578bdf39a65074a79", size = 664666, upload-time = "2025-07-31T08:40:41.559Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/b8/f4d6b3507ec8593d414c9d41932a76dca167cd04dd3585f78a9654e17e85/pvxslibs-1.4.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:8cbbd8c60d418e0c17f80612982b5546264a8477189ed732d26887abd76f9832", size = 2951643, upload-time = "2025-07-31T08:40:27.417Z" }, + { url = "https://files.pythonhosted.org/packages/e4/4c/1024cd7f4da756619cef1ca02c9b92998106b82b81e19eee428cf5efb5a1/pvxslibs-1.4.0-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:17798271ecf20160bd9c70de31e83be0e35d75c39162e28722b0a65ecaaa7dc7", size = 2658223, upload-time = "2025-07-31T08:44:48.436Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b5/a85daed16560780c99b99470177f2dcfaa95b5c68ad616683f4f6d6cae2b/pvxslibs-1.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:4571232ade601cfb9e2660d132cfc045831f7d66e72354cea6cc62beee6a2c79", size = 781156, upload-time = "2025-07-31T08:45:14.419Z" }, + { url = "https://files.pythonhosted.org/packages/79/d3/5b18121d3181aeb3a6633bfa0e072acdf760ad8943b7cec5a54c0110b45f/pvxslibs-1.4.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:eb26b8e4f7a00d463c1b0727cb3e275671835b36caedbc4ec420bd06152d500f", size = 2951602, upload-time = "2025-07-31T08:42:42.709Z" }, + { url = "https://files.pythonhosted.org/packages/b6/be/2878fe1cc695c3bf768ac2c885653660d934b9e031f513345df29cd26439/pvxslibs-1.4.0-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:4a23b14ce7c69bbbb73b9d46380aec79b353d5136db87729d62099d7256dc859", size = 2658230, upload-time = "2025-07-31T08:48:24.771Z" }, + { url = "https://files.pythonhosted.org/packages/91/c8/aaea17b4f2a3e51707998a7c49f28a5f3dfe6bc1e2b91f73ce3654eee899/pvxslibs-1.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:1587c014ec1fe753377b3199d1b561d742151c3a92db9d7481a3eea4840e6d37", size = 781213, upload-time = "2025-07-31T08:44:05.726Z" }, +] + [[package]] name = "py" version = "1.11.0" @@ -959,6 +1068,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e5/80/69756670caedcf3b9be597a6e12276a6cf6197076eb62aad0c608f8efce0/ruff-0.14.5-py3-none-win_arm64.whl", hash = "sha256:4b700459d4649e2594b31f20a9de33bc7c19976d4746d8d0798ad959621d64a4", size = 13433331, upload-time = "2025-11-13T19:58:48.434Z" }, ] +[[package]] +name = "setuptools" +version = "80.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, +] + +[[package]] +name = "setuptools-dso" +version = "2.12.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/36/ed/931a2b72f0403dc0f24180df21fef3ca773c70535249b4e3ade188b7b918/setuptools_dso-2.12.2.tar.gz", hash = "sha256:7afb76f93d13ce9da24502676d8f2d4dbc3da35c6245f95f27df9fa7445079a4", size = 21230, upload-time = "2025-03-21T16:08:34.979Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/36/c101788fad13e8ea65c5b3d3dee8ff996500800cd554ae6ff72143690247/setuptools_dso-2.12.2-py2.py3-none-any.whl", hash = "sha256:deb786b1cfac92f252a82df38e5129b1d9341b36885a01f64543bf3500734a21", size = 23756, upload-time = "2025-03-21T16:08:34.006Z" }, +] + [[package]] name = "shellingham" version = "1.5.4" @@ -968,6 +1098,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, ] +[[package]] +name = "softioc" +version = "4.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "epicscorelibs" }, + { name = "epicsdbbuilder" }, + { name = "numpy" }, + { name = "pvxslibs" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/b9/23cd1b4df0fe853b8099d6f1b4c963b273eb492e7e330f4ff2135e888be7/softioc-4.6.1.tar.gz", hash = "sha256:6e3fb7c205b70d53f9c20e250404ae413339239285842107fbc4fa3881579af5", size = 90822, upload-time = "2025-04-22T10:38:38.094Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/28/a49cbc0f34da8bc219c9e8c2ca0b31e6444689255812719a406371e93c99/softioc-4.6.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4cfc8db83c05b62cac90e934f4b4e25abb0a8030a67169b77f9c9e8bc9f42dfa", size = 113094, upload-time = "2025-04-22T10:38:25.175Z" }, + { url = "https://files.pythonhosted.org/packages/12/f7/9b4b430ac33759c0f225f84e265b197f936b993c4cfc85eb27d245a7cde0/softioc-4.6.1-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:b35cc163340b30df9159ddead11fc0babdf30b7e8d757c3ef1bea4fba08cfa29", size = 118619, upload-time = "2025-04-22T10:38:26.542Z" }, + { url = "https://files.pythonhosted.org/packages/5e/46/2bb58c5452c38f9dede53abf45fe51d23f775e022b79af3de60e946a1870/softioc-4.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:0e73422ae04e568b325c9887292ca3b04e29cb56f159b2a9693c68540e5f1b7f", size = 112523, upload-time = "2025-04-22T10:38:27.869Z" }, +] + [[package]] name = "soupsieve" version = "2.8" @@ -981,11 +1129,13 @@ wheels = [ name = "techui-builder" source = { editable = "." } dependencies = [ + { name = "epicsdbbuilder" }, { name = "lxml" }, { name = "phoebusgen" }, { name = "pydantic" }, { name = "pyyaml" }, { name = "rich" }, + { name = "softioc" }, { name = "typer" }, ] @@ -1011,11 +1161,13 @@ dev = [ [package.metadata] requires-dist = [ + { name = "epicsdbbuilder", specifier = ">=1.5" }, { name = "lxml", specifier = ">=5.4.0" }, { name = "phoebusgen", specifier = ">=3.0.0" }, { name = "pydantic", specifier = ">=2.11.7" }, { name = "pyyaml", specifier = ">=6.0.2" }, { name = "rich", specifier = ">=14.1.0" }, + { name = "softioc", specifier = ">=4.6.1" }, { name = "typer", specifier = ">=0.16.0" }, ] From a15c51c59a5286675472fbd74b8451da9e954e6d Mon Sep 17 00:00:00 2001 From: Ollie Copping Date: Tue, 23 Sep 2025 15:01:11 +0000 Subject: [PATCH 2/8] Make sure config dir exists for ioc.db Also added config dir to gitignore --- src/techui_builder/builder.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/techui_builder/builder.py b/src/techui_builder/builder.py index b0e3ffcd..74b1997d 100644 --- a/src/techui_builder/builder.py +++ b/src/techui_builder/builder.py @@ -126,8 +126,10 @@ def _create_devsta_pv(self, prefix: str, inputs: list[str]): self.devsta_pvs[prefix] = devsta_pv def write_devsta_pvs(self): - devsta_file = self._write_directory.parent.joinpath("config/ioc.db") - with open(devsta_file, "w") as f: + conf_dir = self._write_directory.parent.joinpath("config") + if not conf_dir.exists(): + os.mkdir(conf_dir) + with open(conf_dir.joinpath("ioc.db"), "w") as f: for dpv in self.devsta_pvs.values(): dpv.Print(f) From c9143cfc454a46bad6e3eefe22a717cda3f2abe1 Mon Sep 17 00:00:00 2001 From: Ollie Copping Date: Wed, 24 Sep 2025 07:40:14 +0000 Subject: [PATCH 3/8] Add file header note for autogeneration and add comments --- src/techui_builder/builder.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/techui_builder/builder.py b/src/techui_builder/builder.py index 74b1997d..87265eb4 100644 --- a/src/techui_builder/builder.py +++ b/src/techui_builder/builder.py @@ -127,9 +127,23 @@ def _create_devsta_pv(self, prefix: str, inputs: list[str]): def write_devsta_pvs(self): conf_dir = self._write_directory.parent.joinpath("config") + + # Create the config/ dir if it doesn't exist if not conf_dir.exists(): os.mkdir(conf_dir) + with open(conf_dir.joinpath("ioc.db"), "w") as f: + # Add a header explaining the file is autogenerated + f.write("#" * 51 + "\n") + f.write( + "#" * 2 + + " THIS FILE HAS BEEN AUTOGENERATED; DO NOT EDIT " + + "#" * 2 + + "\n" + ) + f.write("#" * 51 + "\n") + + # Write the devsta PVs for dpv in self.devsta_pvs.values(): dpv.Print(f) From 1fc9ca5e48ae2842d1cbd8e44562a7264c9d7384 Mon Sep 17 00:00:00 2001 From: Ollie Copping Date: Wed, 7 Jan 2026 09:40:35 +0000 Subject: [PATCH 4/8] Add logic to allow for database link flags in devsta PV generation --- src/techui_builder/models.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/techui_builder/models.py b/src/techui_builder/models.py index dc1a4f5c..c1ab03ee 100644 --- a/src/techui_builder/models.py +++ b/src/techui_builder/models.py @@ -44,6 +44,11 @@ """, re.VERBOSE, ) +# Checks for database link flags, e.g. NPP MS, at the end +_DATABASE_FLAGS_RE = re.compile( + r"(?:PP|NPP)?" + r"(?:[ ]+(?:MS|NMS|MSS|MSI))?$", + re.VERBOSE, +) _LONG_DOM_RE = re.compile(r"^[a-zA-Z]{2}\d{2}[a-zA-Z]$") _SHORT_DOM_RE = re.compile(r"^[a-zA-Z]{1}\d{2}(-[0-9]{1})?$") _OPIS_URL_RE = re.compile(r"^(https:\/\/)?([a-z0-9]{3}-(?:[0-9]-)?opis(?:.[a-z0-9]*)*)") @@ -99,6 +104,7 @@ class Component(BaseModel): desc: str | None = None extras: list[str] | None = None file: str | None = None + devsta: list[str] | None = None model_config = ConfigDict(extra="forbid") @field_validator("prefix") @@ -119,6 +125,26 @@ def _check_extras(cls, v: list[str]) -> list[str]: raise ValueError("extras must contain unique items") return v + @field_validator("devsta") + @classmethod + def _check_devsta(cls, v: list[str]) -> list[str]: + for p in v: + prefix, flags = p.split(" ", 1) + + if not _DLS_PREFIX_RE.match(prefix): + raise ValueError( + f"devsta item '{p}' does not match extended DLS prefix pattern" + ) + if not _DATABASE_FLAGS_RE.match(flags): + raise ValueError( + f"devsta item '{p}' does have valid database link flags" + ) + + # ensure unique (schema enforces too) + if len(set(v)) != len(v): + raise ValueError("devsta must contain unique items") + return v + @computed_field @property def P(self) -> str | None: # noqa: N802 From bcd426c674e874b166fe8be46209a8ade0cbcd5f Mon Sep 17 00:00:00 2001 From: Ollie Copping Date: Wed, 7 Jan 2026 09:46:52 +0000 Subject: [PATCH 5/8] Update b23-services example with DEVSTA for M3 (Includes updates to screens that haven't been re-generated in a while) --- example-synoptic/b23-services/config/ioc.db | 22 +++ .../b23-services/synoptic/IMG1.bob | 3 +- .../b23-services/synoptic/IMG11.bob | 3 +- .../b23-services/synoptic/IMG12.bob | 3 +- .../b23-services/synoptic/IONP1.bob | 3 +- .../b23-services/synoptic/IONP11.bob | 3 +- .../b23-services/synoptic/IONP12.bob | 3 +- .../b23-services/synoptic/IONP21.bob | 3 +- .../b23-services/synoptic/JsonMap.json | 136 +++++++++--------- example-synoptic/b23-services/synoptic/M3.bob | 21 +-- .../b23-services/synoptic/MOD1.bob | 45 +++--- .../b23-services/synoptic/MOD2.bob | 45 +++--- .../b23-services/synoptic/PIRG1.bob | 3 +- .../b23-services/synoptic/PIRG11.bob | 3 +- .../b23-services/synoptic/PIRG12.bob | 3 +- .../b23-services/synoptic/SPACE11.bob | 18 ++- .../b23-services/synoptic/techui.yaml | 10 +- 17 files changed, 182 insertions(+), 145 deletions(-) create mode 100644 example-synoptic/b23-services/config/ioc.db diff --git a/example-synoptic/b23-services/config/ioc.db b/example-synoptic/b23-services/config/ioc.db new file mode 100644 index 00000000..cc907c7a --- /dev/null +++ b/example-synoptic/b23-services/config/ioc.db @@ -0,0 +1,22 @@ +################################################### +## THIS FILE HAS BEEN AUTOGENERATED; DO NOT EDIT ## +################################################### + +record(calc, "BL23B-OP-MR-03:DEVSTA") +{ + field(ACKT, "NO") + field(CALC, "(A|B|C|D|E|F|G|H|I|J|K|L)>0?1:0") + field(INPA, "BL23B-OP-MR-03:MP:BUSY NPP NMS") + field(INPB, "BL23B-OP-MR-03:MP:DMOV.SEVR NPP MS") + field(INPC, "BL23B-OP-MR-03:MP:SELECT.SEVR NPP MS") + field(INPD, "BL23B-OP-MR-03:PITCH.MOVN NPP MS") + field(INPE, "BL23B-OP-MR-03:YAW.MOVN NPP MS") + field(INPF, "") + field(INPG, "") + field(INPH, "") + field(INPI, "") + field(INPJ, "") + field(INPK, "") + field(INPL, "") + field(SCAN, "1 second") +} diff --git a/example-synoptic/b23-services/synoptic/IMG1.bob b/example-synoptic/b23-services/synoptic/IMG1.bob index ba360623..65b3372c 100644 --- a/example-synoptic/b23-services/synoptic/IMG1.bob +++ b/example-synoptic/b23-services/synoptic/IMG1.bob @@ -8,12 +8,13 @@ 351 432 - mks937a.mks937aImg + BL23B-VA-IMG-01 301 382 techui-support/bob/mks937a/mks937aImg.bob

BL23B-VA-IMG-01

+ https://b23-opis.diamond.ac.uk/bl23b-va-img-01
0 0 diff --git a/example-synoptic/b23-services/synoptic/IMG11.bob b/example-synoptic/b23-services/synoptic/IMG11.bob index c7a5d42e..e29f6eb2 100644 --- a/example-synoptic/b23-services/synoptic/IMG11.bob +++ b/example-synoptic/b23-services/synoptic/IMG11.bob @@ -8,12 +8,13 @@ 351 432 - mks937a.mks937aImg + BL23B-VA-IMG-11 301 382 techui-support/bob/mks937a/mks937aImg.bob

BL23B-VA-IMG-11

+ https://b23-opis.diamond.ac.uk/bl23b-va-img-11
0 0 diff --git a/example-synoptic/b23-services/synoptic/IMG12.bob b/example-synoptic/b23-services/synoptic/IMG12.bob index 2ac84dd5..c078d23b 100644 --- a/example-synoptic/b23-services/synoptic/IMG12.bob +++ b/example-synoptic/b23-services/synoptic/IMG12.bob @@ -8,12 +8,13 @@ 351 432 - mks937a.mks937aImg + BL23B-VA-IMG-12 301 382 techui-support/bob/mks937a/mks937aImg.bob

BL23B-VA-IMG-12

+ https://b23-opis.diamond.ac.uk/bl23b-va-img-12
0 0 diff --git a/example-synoptic/b23-services/synoptic/IONP1.bob b/example-synoptic/b23-services/synoptic/IONP1.bob index 8f547f45..1495f482 100644 --- a/example-synoptic/b23-services/synoptic/IONP1.bob +++ b/example-synoptic/b23-services/synoptic/IONP1.bob @@ -8,12 +8,13 @@ 351 293 - digitelMpc.digitelMpcIonp + BL23B-VA-IONP-01 301 243 techui-support/bob/digitelMpc/digitelMpcIonp.bob

BL23B-VA-IONP-01

+ https://b23-opis.diamond.ac.uk/bl23b-va-ionp-01
0 0 diff --git a/example-synoptic/b23-services/synoptic/IONP11.bob b/example-synoptic/b23-services/synoptic/IONP11.bob index a77ee59d..ca4dc003 100644 --- a/example-synoptic/b23-services/synoptic/IONP11.bob +++ b/example-synoptic/b23-services/synoptic/IONP11.bob @@ -8,12 +8,13 @@ 351 293 - digitelMpc.digitelMpcIonp + BL23B-VA-IONP-11 301 243 techui-support/bob/digitelMpc/digitelMpcIonp.bob

BL23B-VA-IONP-11

+ https://b23-opis.diamond.ac.uk/bl23b-va-ionp-11
0 0 diff --git a/example-synoptic/b23-services/synoptic/IONP12.bob b/example-synoptic/b23-services/synoptic/IONP12.bob index ac88312c..de2f2b8c 100644 --- a/example-synoptic/b23-services/synoptic/IONP12.bob +++ b/example-synoptic/b23-services/synoptic/IONP12.bob @@ -8,12 +8,13 @@ 351 293 - digitelMpc.digitelMpcIonp + BL23B-VA-IONP-12 301 243 techui-support/bob/digitelMpc/digitelMpcIonp.bob

BL23B-VA-IONP-12

+ https://b23-opis.diamond.ac.uk/bl23b-va-ionp-12
0 0 diff --git a/example-synoptic/b23-services/synoptic/IONP21.bob b/example-synoptic/b23-services/synoptic/IONP21.bob index 2a24aac8..75a645e1 100644 --- a/example-synoptic/b23-services/synoptic/IONP21.bob +++ b/example-synoptic/b23-services/synoptic/IONP21.bob @@ -8,12 +8,13 @@ 351 293 - digitelMpc.digitelMpcIonp + BL23B-VA-IONP-21 301 243 techui-support/bob/digitelMpc/digitelMpcIonp.bob

BL23B-VA-IONP-21

+ https://b23-opis.diamond.ac.uk/bl23b-va-ionp-21
0 0 diff --git a/example-synoptic/b23-services/synoptic/JsonMap.json b/example-synoptic/b23-services/synoptic/JsonMap.json index 2a7a88b6..aaa76425 100644 --- a/example-synoptic/b23-services/synoptic/JsonMap.json +++ b/example-synoptic/b23-services/synoptic/JsonMap.json @@ -317,76 +317,6 @@ "name": "PIRG2" } }, - { - "file": "MOD2.bob", - "children": [ - { - "file": "techui-support/bob/ADAravis/ADAravis_detail.bob", - "macros": { - "P": "BL23B-DI-MOD-02", - "R": ":CAM:" - } - }, - { - "file": "techui-support/bob/ADAravis/NDPluginROI.pvi.bob", - "macros": { - "P": "BL23B-DI-MOD-02", - "R": ":ROI:" - } - }, - { - "file": "techui-support/bob/ADAravis/NDPluginStats.pvi.bob", - "macros": { - "P": "BL23B-DI-MOD-02", - "R": ":STAT:" - } - }, - { - "file": "techui-support/bob/ADAravis/NDFileHDF5.pvi.bob", - "macros": { - "P": "BL23B-DI-MOD-02", - "R": ":HDF5:" - } - } - ] - }, - { - "file": "MOD1.bob", - "children": [ - { - "file": "techui-support/bob/ADAravis/ADAravis_detail.bob", - "duplicate": true, - "macros": { - "P": "BL23B-DI-MOD-01", - "R": ":CAM:" - } - }, - { - "file": "techui-support/bob/ADAravis/NDPluginROI.pvi.bob", - "duplicate": true, - "macros": { - "P": "BL23B-DI-MOD-01", - "R": ":ROI:" - } - }, - { - "file": "techui-support/bob/ADAravis/NDPluginStats.pvi.bob", - "duplicate": true, - "macros": { - "P": "BL23B-DI-MOD-01", - "R": ":STAT:" - } - }, - { - "file": "techui-support/bob/ADAravis/NDFileHDF5.pvi.bob", - "duplicate": true, - "macros": { - "P": "BL23B-DI-MOD-01", - "R": ":HDF5:" - } - } - ] - }, { "file": "IMG11.bob", "macros": { @@ -501,11 +431,73 @@ }, { "file": "MOD1.bob", - "duplicate": true + "children": [ + { + "file": "techui-support/bob/ADAravis/ADAravis_detail.bob", + "macros": { + "P": "BL23B-DI-MOD-01", + "R": ":CAM:" + } + }, + { + "file": "techui-support/bob/ADAravis/NDPluginROI.pvi.bob", + "macros": { + "P": "BL23B-DI-MOD-01", + "R": ":ROI:" + } + }, + { + "file": "techui-support/bob/ADAravis/NDPluginStats.pvi.bob", + "macros": { + "P": "BL23B-DI-MOD-01", + "R": ":STAT:" + } + }, + { + "file": "techui-support/bob/ADAravis/NDFileHDF5.pvi.bob", + "macros": { + "P": "BL23B-DI-MOD-01", + "R": ":HDF5:" + } + } + ] }, { "file": "MOD2.bob", - "duplicate": true + "children": [ + { + "file": "techui-support/bob/ADAravis/ADAravis_detail.bob", + "duplicate": true, + "macros": { + "P": "BL23B-DI-MOD-02", + "R": ":CAM:" + } + }, + { + "file": "techui-support/bob/ADAravis/NDPluginROI.pvi.bob", + "duplicate": true, + "macros": { + "P": "BL23B-DI-MOD-02", + "R": ":ROI:" + } + }, + { + "file": "techui-support/bob/ADAravis/NDPluginStats.pvi.bob", + "duplicate": true, + "macros": { + "P": "BL23B-DI-MOD-02", + "R": ":STAT:" + } + }, + { + "file": "techui-support/bob/ADAravis/NDFileHDF5.pvi.bob", + "duplicate": true, + "macros": { + "P": "BL23B-DI-MOD-02", + "R": ":HDF5:" + } + } + ] } ] } diff --git a/example-synoptic/b23-services/synoptic/M3.bob b/example-synoptic/b23-services/synoptic/M3.bob index 7a83e8c3..c1e1dce5 100644 --- a/example-synoptic/b23-services/synoptic/M3.bob +++ b/example-synoptic/b23-services/synoptic/M3.bob @@ -8,47 +8,50 @@ 255 540 - :Y + Y 205 120 techui-support/bob/pmac/motor_embed.bob

BL23B-OP-MR-03

- :Y + Y + https://b23-opis.diamond.ac.uk/bl23b-op-mr-03
0 0
- :YAW + YAW 205 120 techui-support/bob/pmac/motor_embed.bob

BL23B-OP-MR-03

- :YAW + YAW + https://b23-opis.diamond.ac.uk/bl23b-op-mr-03
0 150
- :PITCH + PITCH 205 120 techui-support/bob/pmac/motor_embed.bob

BL23B-OP-MR-03

- :PITCH + PITCH + https://b23-opis.diamond.ac.uk/bl23b-op-mr-03
0 300
- pmac.GeoBrick + BL23B-MO-PMAC-01 100 40 - BL23B-MO-PMAC-01 - pmac.GeoBrick + + BL23B-MO-PMAC-01 Open Display diff --git a/example-synoptic/b23-services/synoptic/MOD1.bob b/example-synoptic/b23-services/synoptic/MOD1.bob index 12a39348..069c3842 100644 --- a/example-synoptic/b23-services/synoptic/MOD1.bob +++ b/example-synoptic/b23-services/synoptic/MOD1.bob @@ -5,26 +5,27 @@ MOD1 0 0 - 1040 - 690 + 910 + 570 - :CAM: - 990 - 570 + CAM + 860 + 450 techui-support/bob/ADAravis/ADAravis_summary.bob

BL23B-DI-MOD-01

- :CAM: + CAM + https://b23-opis.diamond.ac.uk/bl23b-di-mod-01
0 0
- :CAM: + CAM 100 40 - BL23B-DI-MOD-01:CAM: - :CAM: + + CAM Open Display @@ -37,14 +38,14 @@ 0 - 600 + 480 - :ROI: + ROI 100 40 - BL23B-DI-MOD-01:ROI: - :ROI: + + ROI Open Display @@ -57,14 +58,14 @@ 120 - 600 + 480 - :STAT: + STAT 100 40 - BL23B-DI-MOD-01:STAT: - :STAT: + + STAT Open Display @@ -77,14 +78,14 @@ 240 - 600 + 480 - :HDF5: + HDF5 100 40 - BL23B-DI-MOD-01:HDF5: - :HDF5: + + HDF5 Open Display @@ -97,7 +98,7 @@ 360 - 600 + 480
diff --git a/example-synoptic/b23-services/synoptic/MOD2.bob b/example-synoptic/b23-services/synoptic/MOD2.bob index 6d9e02a9..6b1c798b 100644 --- a/example-synoptic/b23-services/synoptic/MOD2.bob +++ b/example-synoptic/b23-services/synoptic/MOD2.bob @@ -5,26 +5,27 @@ MOD2 0 0 - 1040 - 690 + 910 + 570 - :CAM: - 990 - 570 + CAM + 860 + 450 techui-support/bob/ADAravis/ADAravis_summary.bob

BL23B-DI-MOD-02

- :CAM: + CAM + https://b23-opis.diamond.ac.uk/bl23b-di-mod-02
0 0
- :CAM: + CAM 100 40 - BL23B-DI-MOD-02:CAM: - :CAM: + + CAM Open Display @@ -37,14 +38,14 @@ 0 - 600 + 480 - :ROI: + ROI 100 40 - BL23B-DI-MOD-02:ROI: - :ROI: + + ROI Open Display @@ -57,14 +58,14 @@ 120 - 600 + 480 - :STAT: + STAT 100 40 - BL23B-DI-MOD-02:STAT: - :STAT: + + STAT Open Display @@ -77,14 +78,14 @@ 240 - 600 + 480 - :HDF5: + HDF5 100 40 - BL23B-DI-MOD-02:HDF5: - :HDF5: + + HDF5 Open Display @@ -97,7 +98,7 @@ 360 - 600 + 480
diff --git a/example-synoptic/b23-services/synoptic/PIRG1.bob b/example-synoptic/b23-services/synoptic/PIRG1.bob index eb79980d..548bf040 100644 --- a/example-synoptic/b23-services/synoptic/PIRG1.bob +++ b/example-synoptic/b23-services/synoptic/PIRG1.bob @@ -8,12 +8,13 @@ 351 406 - mks937a.mks937aPirg + BL23B-VA-PIRG-01 301 356 techui-support/bob/mks937a/mks937aPirg.bob

BL23B-VA-PIRG-01

+ https://b23-opis.diamond.ac.uk/bl23b-va-pirg-01
0 0 diff --git a/example-synoptic/b23-services/synoptic/PIRG11.bob b/example-synoptic/b23-services/synoptic/PIRG11.bob index 25ab0a2e..0d8a5d16 100644 --- a/example-synoptic/b23-services/synoptic/PIRG11.bob +++ b/example-synoptic/b23-services/synoptic/PIRG11.bob @@ -8,12 +8,13 @@ 351 406 - mks937a.mks937aPirg + BL23B-VA-PIRG-11 301 356 techui-support/bob/mks937a/mks937aPirg.bob

BL23B-VA-PIRG-11

+ https://b23-opis.diamond.ac.uk/bl23b-va-pirg-11
0 0 diff --git a/example-synoptic/b23-services/synoptic/PIRG12.bob b/example-synoptic/b23-services/synoptic/PIRG12.bob index fb8765d4..b99119c9 100644 --- a/example-synoptic/b23-services/synoptic/PIRG12.bob +++ b/example-synoptic/b23-services/synoptic/PIRG12.bob @@ -8,12 +8,13 @@ 351 406 - mks937a.mks937aPirg + BL23B-VA-PIRG-12 301 356 techui-support/bob/mks937a/mks937aPirg.bob

BL23B-VA-PIRG-12

+ https://b23-opis.diamond.ac.uk/bl23b-va-pirg-12
0 0 diff --git a/example-synoptic/b23-services/synoptic/SPACE11.bob b/example-synoptic/b23-services/synoptic/SPACE11.bob index d195aece..2eddfb53 100644 --- a/example-synoptic/b23-services/synoptic/SPACE11.bob +++ b/example-synoptic/b23-services/synoptic/SPACE11.bob @@ -8,67 +8,73 @@ 1013 844 - mks937a.mks937aImg + BL23B-VA-IMG-11 301 382 techui-support/bob/mks937a/mks937aImg.bob

BL23B-VA-IMG-11

+ https://b23-opis.diamond.ac.uk/bl23b-va-img-11
0 0
- mks937a.mks937aImg + BL23B-VA-IMG-12 301 382 techui-support/bob/mks937a/mks937aImg.bob

BL23B-VA-IMG-12

+ https://b23-opis.diamond.ac.uk/bl23b-va-img-12
0 412
- mks937a.mks937aPirg + BL23B-VA-PIRG-11 301 356 techui-support/bob/mks937a/mks937aPirg.bob

BL23B-VA-PIRG-11

+ https://b23-opis.diamond.ac.uk/bl23b-va-pirg-11
331 0
- mks937a.mks937aPirg + BL23B-VA-PIRG-12 301 356 techui-support/bob/mks937a/mks937aPirg.bob

BL23B-VA-PIRG-12

+ https://b23-opis.diamond.ac.uk/bl23b-va-pirg-12
331 386
- digitelMpc.digitelMpcIonp + BL23B-VA-IONP-11 301 243 techui-support/bob/digitelMpc/digitelMpcIonp.bob

BL23B-VA-IONP-11

+ https://b23-opis.diamond.ac.uk/bl23b-va-ionp-11
662 0
- digitelMpc.digitelMpcIonp + BL23B-VA-IONP-12 301 243 techui-support/bob/digitelMpc/digitelMpcIonp.bob

BL23B-VA-IONP-12

+ https://b23-opis.diamond.ac.uk/bl23b-va-ionp-12
662 273 diff --git a/example-synoptic/b23-services/synoptic/techui.yaml b/example-synoptic/b23-services/synoptic/techui.yaml index 77f4e837..24eaec34 100644 --- a/example-synoptic/b23-services/synoptic/techui.yaml +++ b/example-synoptic/b23-services/synoptic/techui.yaml @@ -3,6 +3,7 @@ beamline: short_dom: B23 long_dom: BL23B desc: B23 Beamline + url: b23-opis.diamond.ac.uk components: # ----- VACUUM ----- @@ -134,16 +135,17 @@ components: M2: prefix: FE23B-OP-MR-02 - devsta: - - FE23B-OP-MR-02:MOTORSTA M3: prefix: BL23B-OP-MR-03 extras: - BL23B-MO-PMAC-01 devsta: - - BL23B-OP-MR-03:MOTORSTA - - BL23B-MO-PMAC-01:MOTORSTA + - BL23B-OP-MR-03:MP:BUSY NPP NMS + - BL23B-OP-MR-03:MP:DMOV.SEVR NPP MS + - BL23B-OP-MR-03:MP:SELECT.SEVR NPP MS + - BL23B-OP-MR-03:PITCH.MOVN NPP MS + - BL23B-OP-MR-03:YAW.MOVN NPP MS # ----- MOD ----- From b20aead972072ce89d3e7134615302a4dd98fa04 Mon Sep 17 00:00:00 2001 From: Ollie Copping Date: Wed, 7 Jan 2026 09:51:28 +0000 Subject: [PATCH 6/8] Update tests --- tests/test_models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_models.py b/tests/test_models.py index e2691b06..f5c5e81c 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -44,13 +44,14 @@ def test_component_object(component: Component): assert component.P == "BL01T-EA-TEST-02" assert component.R is None assert component.attribute is None + assert component.devsta is None def test_component_repr(component: Component): assert ( str(component) == "prefix='BL01T-EA-TEST-02' desc='Test Device' extras=None\ - file=None P='BL01T-EA-TEST-02' R=None attribute=None" + file=None devsta=None P='BL01T-EA-TEST-02' R=None attribute=None" ) From 731abe3cf4ccc51802a0f2f06fc6d5b3564abdb2 Mon Sep 17 00:00:00 2001 From: Ollie Copping Date: Wed, 7 Jan 2026 14:02:46 +0000 Subject: [PATCH 7/8] Rename ioc.db to devsta.db to differentiate from ibek runtime ioc.db --- example-synoptic/b23-services/config/{ioc.db => devsta.db} | 0 src/techui_builder/builder.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename example-synoptic/b23-services/config/{ioc.db => devsta.db} (100%) diff --git a/example-synoptic/b23-services/config/ioc.db b/example-synoptic/b23-services/config/devsta.db similarity index 100% rename from example-synoptic/b23-services/config/ioc.db rename to example-synoptic/b23-services/config/devsta.db diff --git a/src/techui_builder/builder.py b/src/techui_builder/builder.py index 87265eb4..4efa78dd 100644 --- a/src/techui_builder/builder.py +++ b/src/techui_builder/builder.py @@ -132,7 +132,7 @@ def write_devsta_pvs(self): if not conf_dir.exists(): os.mkdir(conf_dir) - with open(conf_dir.joinpath("ioc.db"), "w") as f: + with open(conf_dir.joinpath("devsta.db"), "w") as f: # Add a header explaining the file is autogenerated f.write("#" * 51 + "\n") f.write( From 94ce4c6ceb357db3b40453cdcc2c8be056d3e10f Mon Sep 17 00:00:00 2001 From: Ollie Copping Date: Wed, 7 Jan 2026 14:52:10 +0000 Subject: [PATCH 8/8] TEST --- .github/workflows/_test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index 9ba36e48..65c8cfad 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -33,6 +33,8 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v7 + - name: List packages + run: uv run --locked uv pip freeze - name: Run tests run: uv run --locked tox -e tests