Loading dockerfiles/Dockerfile +2 −1 Original line number Diff line number Diff line FROM --platform=amd64 regproxy.ornl.gov/hub_proxy/python:3.10-slim AS source # make sure image can run as non-root user RUN apt-get update && apt-get install -y qt6-base-dev ENV QT_QPA_PLATFORM=offscreen ENV POETRY_CACHE_DIR=/poetry/.cache ENV POETRY_CONFIG_DIR=/poetry/.config Loading poetry.lock +46 −9 Original line number Diff line number Diff line # This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" Loading Loading @@ -111,13 +111,13 @@ speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] [[package]] name = "aiosignal" version = "1.3.1" version = "1.3.2" description = "aiosignal: a list of registered asynchronous callbacks" optional = false python-versions = ">=3.7" python-versions = ">=3.9" files = [ {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, {file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"}, {file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"}, ] [package.dependencies] Loading Loading @@ -1978,7 +1978,7 @@ files = [ name = "pyqt6" version = "6.8.0" description = "Python bindings for the Qt cross platform application toolkit" optional = true optional = false python-versions = ">=3.9" files = [ {file = "PyQt6-6.8.0-cp39-abi3-macosx_10_14_universal2.whl", hash = "sha256:8c5c05f5fdff31a5887dbc29b27615b09df467631238d7b449283809ffca6228"}, Loading @@ -1997,7 +1997,7 @@ PyQt6-sip = ">=13.8,<14" name = "pyqt6-qt6" version = "6.8.1" description = "The subset of a Qt installation needed by PyQt6." optional = true optional = false python-versions = "*" files = [ {file = "PyQt6_Qt6-6.8.1-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:1eb8460a1fdb38d0b2458c2974c01d471c1e59e4eb19ea63fc447aaba3ad530e"}, Loading @@ -2012,7 +2012,7 @@ files = [ name = "pyqt6-sip" version = "13.9.1" description = "The sip module support for PyQt6" optional = true optional = false python-versions = ">=3.9" files = [ {file = "PyQt6_sip-13.9.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e996d320744ca8342cad6f9454345330d4f06bce129812d032bda3bad6967c5c"}, Loading Loading @@ -2063,6 +2063,43 @@ tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" version = "0.25.0" description = "Pytest support for asyncio" optional = false python-versions = ">=3.9" files = [ {file = "pytest_asyncio-0.25.0-py3-none-any.whl", hash = "sha256:db5432d18eac6b7e28b46dcd9b69921b55c3b1086e85febfe04e70b18d9e81b3"}, {file = "pytest_asyncio-0.25.0.tar.gz", hash = "sha256:8c0610303c9e0442a5db8604505fc0f545456ba1528824842b37b4a626cbf609"}, ] [package.dependencies] pytest = ">=8.2,<9" [package.extras] docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)"] testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] [[package]] name = "pytest-qt" version = "4.4.0" description = "pytest support for PyQt and PySide applications" optional = false python-versions = ">=3.8" files = [ {file = "pytest-qt-4.4.0.tar.gz", hash = "sha256:76896142a940a4285339008d6928a36d4be74afec7e634577e842c9cc5c56844"}, {file = "pytest_qt-4.4.0-py3-none-any.whl", hash = "sha256:001ed2f8641764b394cf286dc8a4203e40eaf9fff75bf0bfe5103f7f8d0c591d"}, ] [package.dependencies] pluggy = ">=1.1" pytest = "*" [package.extras] dev = ["pre-commit", "tox"] doc = ["sphinx", "sphinx-rtd-theme"] [[package]] name = "python-dateutil" version = "2.9.0.post0" Loading Loading @@ -2812,4 +2849,4 @@ pyqt6 = ["pyqt6"] [metadata] lock-version = "2.0" python-versions = "^3.10" content-hash = "a5fbcd9b153f684f5e069207cd5280f65e72736d0be34b3cdfc4c16db4adaa69" content-hash = "a7235000afca64c90adb74750db9b26211b35384c6c8bcd9a14322c3213d1cc7" pyproject.toml +6 −0 Original line number Diff line number Diff line Loading @@ -19,11 +19,16 @@ pyqt6 = { version = "^6.7.0", optional = true } panel = { version = "^1.4.4", optional = true } deepdiff = "^8.0.1" pytest-asyncio = "^0.25.0" [tool.poetry.extras] pyqt5 = ["pyqt5"] pyqt6 = ["pyqt6"] panel = ["panel"] [tool.poetry.group.dev.dependencies] pytest-qt = "^4.4.0" pyqt6 = "^6.8.0" [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" Loading Loading @@ -94,5 +99,6 @@ sphinx-rtd-theme = "*" sphinxcontrib-napoleon ="*" tomli = "^2.0.2" [tool.poetry.scripts] app = "nova.mvvm:main" src/nova/mvvm/_internal/utils.py +28 −1 Original line number Diff line number Diff line """Internal common functions tp be used within the package.""" import re from typing import Any from typing import Any, Dict def normalize_field_name(field: str) -> str: Loading Loading @@ -60,3 +60,30 @@ def rsetattr(obj: Any, attr: str, val: Any) -> Any: obj = obj[index] else: setattr(obj, post, val) def rsetdictvalue(obj: Dict[str, Any], field: str, val: Any) -> Any: keys = field.split(".") current = obj for key in keys[:-1]: if "[" in key: base = field.split("[")[0] indices = re.findall(r"\[(\d+)\]", field) indices = [int(num) for num in indices] for i in indices: current = current[base][i] else: current = current[key] current[keys[-1]] = val def rgetdictvalue(obj: Dict[str, Any], field: str) -> Any: fields = field.split(".") for f in fields: base = f.split("[")[0] obj = obj[base] indices = re.findall(r"\[(\d+)\]", f) indices = [int(num) for num in indices] for index in indices: obj = obj[index] return obj src/nova/mvvm/interface.py +4 −2 Original line number Diff line number Diff line """Abstract interfaces and type definitions.""" from abc import ABC, abstractmethod from typing import Any, Callable, Dict, Optional, Union from typing import Any, Callable, Coroutine, Optional, Union LinkedObjectType = Optional[Any] LinkedObjectAttributesType = Optional[list[str]] CallbackAfterUpdateType = Optional[Callable[[Dict[str, Any]], None]] ConnectCallbackType = Union[None, Callable[[Any, Optional[str]], None]] CallbackAfterUpdateType = Union[ None, Callable[[dict[str, Any]], None], Callable[[dict[str, Any]], Coroutine[Any, Any, None]] ] class Communicator(ABC): Loading Loading
dockerfiles/Dockerfile +2 −1 Original line number Diff line number Diff line FROM --platform=amd64 regproxy.ornl.gov/hub_proxy/python:3.10-slim AS source # make sure image can run as non-root user RUN apt-get update && apt-get install -y qt6-base-dev ENV QT_QPA_PLATFORM=offscreen ENV POETRY_CACHE_DIR=/poetry/.cache ENV POETRY_CONFIG_DIR=/poetry/.config Loading
poetry.lock +46 −9 Original line number Diff line number Diff line # This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" Loading Loading @@ -111,13 +111,13 @@ speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] [[package]] name = "aiosignal" version = "1.3.1" version = "1.3.2" description = "aiosignal: a list of registered asynchronous callbacks" optional = false python-versions = ">=3.7" python-versions = ">=3.9" files = [ {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, {file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"}, {file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"}, ] [package.dependencies] Loading Loading @@ -1978,7 +1978,7 @@ files = [ name = "pyqt6" version = "6.8.0" description = "Python bindings for the Qt cross platform application toolkit" optional = true optional = false python-versions = ">=3.9" files = [ {file = "PyQt6-6.8.0-cp39-abi3-macosx_10_14_universal2.whl", hash = "sha256:8c5c05f5fdff31a5887dbc29b27615b09df467631238d7b449283809ffca6228"}, Loading @@ -1997,7 +1997,7 @@ PyQt6-sip = ">=13.8,<14" name = "pyqt6-qt6" version = "6.8.1" description = "The subset of a Qt installation needed by PyQt6." optional = true optional = false python-versions = "*" files = [ {file = "PyQt6_Qt6-6.8.1-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:1eb8460a1fdb38d0b2458c2974c01d471c1e59e4eb19ea63fc447aaba3ad530e"}, Loading @@ -2012,7 +2012,7 @@ files = [ name = "pyqt6-sip" version = "13.9.1" description = "The sip module support for PyQt6" optional = true optional = false python-versions = ">=3.9" files = [ {file = "PyQt6_sip-13.9.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e996d320744ca8342cad6f9454345330d4f06bce129812d032bda3bad6967c5c"}, Loading Loading @@ -2063,6 +2063,43 @@ tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" version = "0.25.0" description = "Pytest support for asyncio" optional = false python-versions = ">=3.9" files = [ {file = "pytest_asyncio-0.25.0-py3-none-any.whl", hash = "sha256:db5432d18eac6b7e28b46dcd9b69921b55c3b1086e85febfe04e70b18d9e81b3"}, {file = "pytest_asyncio-0.25.0.tar.gz", hash = "sha256:8c0610303c9e0442a5db8604505fc0f545456ba1528824842b37b4a626cbf609"}, ] [package.dependencies] pytest = ">=8.2,<9" [package.extras] docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)"] testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] [[package]] name = "pytest-qt" version = "4.4.0" description = "pytest support for PyQt and PySide applications" optional = false python-versions = ">=3.8" files = [ {file = "pytest-qt-4.4.0.tar.gz", hash = "sha256:76896142a940a4285339008d6928a36d4be74afec7e634577e842c9cc5c56844"}, {file = "pytest_qt-4.4.0-py3-none-any.whl", hash = "sha256:001ed2f8641764b394cf286dc8a4203e40eaf9fff75bf0bfe5103f7f8d0c591d"}, ] [package.dependencies] pluggy = ">=1.1" pytest = "*" [package.extras] dev = ["pre-commit", "tox"] doc = ["sphinx", "sphinx-rtd-theme"] [[package]] name = "python-dateutil" version = "2.9.0.post0" Loading Loading @@ -2812,4 +2849,4 @@ pyqt6 = ["pyqt6"] [metadata] lock-version = "2.0" python-versions = "^3.10" content-hash = "a5fbcd9b153f684f5e069207cd5280f65e72736d0be34b3cdfc4c16db4adaa69" content-hash = "a7235000afca64c90adb74750db9b26211b35384c6c8bcd9a14322c3213d1cc7"
pyproject.toml +6 −0 Original line number Diff line number Diff line Loading @@ -19,11 +19,16 @@ pyqt6 = { version = "^6.7.0", optional = true } panel = { version = "^1.4.4", optional = true } deepdiff = "^8.0.1" pytest-asyncio = "^0.25.0" [tool.poetry.extras] pyqt5 = ["pyqt5"] pyqt6 = ["pyqt6"] panel = ["panel"] [tool.poetry.group.dev.dependencies] pytest-qt = "^4.4.0" pyqt6 = "^6.8.0" [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" Loading Loading @@ -94,5 +99,6 @@ sphinx-rtd-theme = "*" sphinxcontrib-napoleon ="*" tomli = "^2.0.2" [tool.poetry.scripts] app = "nova.mvvm:main"
src/nova/mvvm/_internal/utils.py +28 −1 Original line number Diff line number Diff line """Internal common functions tp be used within the package.""" import re from typing import Any from typing import Any, Dict def normalize_field_name(field: str) -> str: Loading Loading @@ -60,3 +60,30 @@ def rsetattr(obj: Any, attr: str, val: Any) -> Any: obj = obj[index] else: setattr(obj, post, val) def rsetdictvalue(obj: Dict[str, Any], field: str, val: Any) -> Any: keys = field.split(".") current = obj for key in keys[:-1]: if "[" in key: base = field.split("[")[0] indices = re.findall(r"\[(\d+)\]", field) indices = [int(num) for num in indices] for i in indices: current = current[base][i] else: current = current[key] current[keys[-1]] = val def rgetdictvalue(obj: Dict[str, Any], field: str) -> Any: fields = field.split(".") for f in fields: base = f.split("[")[0] obj = obj[base] indices = re.findall(r"\[(\d+)\]", f) indices = [int(num) for num in indices] for index in indices: obj = obj[index] return obj
src/nova/mvvm/interface.py +4 −2 Original line number Diff line number Diff line """Abstract interfaces and type definitions.""" from abc import ABC, abstractmethod from typing import Any, Callable, Dict, Optional, Union from typing import Any, Callable, Coroutine, Optional, Union LinkedObjectType = Optional[Any] LinkedObjectAttributesType = Optional[list[str]] CallbackAfterUpdateType = Optional[Callable[[Dict[str, Any]], None]] ConnectCallbackType = Union[None, Callable[[Any, Optional[str]], None]] CallbackAfterUpdateType = Union[ None, Callable[[dict[str, Any]], None], Callable[[dict[str, Any]], Coroutine[Any, Any, None]] ] class Communicator(ABC): Loading