aiidalab-chemshell 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. aiidalab_chemshell-0.0.1/LICENSE +28 -0
  2. aiidalab_chemshell-0.0.1/PKG-INFO +32 -0
  3. aiidalab_chemshell-0.0.1/README.md +124 -0
  4. aiidalab_chemshell-0.0.1/pyproject.toml +31 -0
  5. aiidalab_chemshell-0.0.1/setup.cfg +55 -0
  6. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/__init__.py +5 -0
  7. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/common/__init__.py +1 -0
  8. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/common/chemshell.py +53 -0
  9. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/common/database.py +170 -0
  10. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/common/file_handling.py +89 -0
  11. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/common/navigation.py +81 -0
  12. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/common/node_viewers.py +166 -0
  13. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/history.py +124 -0
  14. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/main.py +70 -0
  15. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/models/__init__.py +1 -0
  16. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/models/process.py +38 -0
  17. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/models/resources.py +35 -0
  18. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/models/results.py +11 -0
  19. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/models/structure.py +34 -0
  20. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/models/workflow.py +31 -0
  21. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/process.py +141 -0
  22. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/utils.py +106 -0
  23. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/wizards/__init__.py +1 -0
  24. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/wizards/main_app.py +70 -0
  25. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/wizards/resources.py +173 -0
  26. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/wizards/results.py +84 -0
  27. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/wizards/structure.py +138 -0
  28. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/wizards/workflows/__init__.py +5 -0
  29. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/wizards/workflows/geometry_optimisation.py +153 -0
  30. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/wizards/workflows/main_view.py +127 -0
  31. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell/wizards/workflows/neb.py +1 -0
  32. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell.egg-info/PKG-INFO +32 -0
  33. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell.egg-info/SOURCES.txt +36 -0
  34. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell.egg-info/dependency_links.txt +1 -0
  35. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell.egg-info/requires.txt +15 -0
  36. aiidalab_chemshell-0.0.1/src/aiidalab_chemshell.egg-info/top_level.txt +1 -0
  37. aiidalab_chemshell-0.0.1/tests/test_base.py +8 -0
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2025, UKRI Science and Technology Facilities Council
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,32 @@
1
+ Metadata-Version: 2.4
2
+ Name: aiidalab-chemshell
3
+ Version: 0.0.1
4
+ Summary: AiiDAlab application for ChemShell based workflows
5
+ Home-page: https://github.com/stfc/aiidalab-chemshell
6
+ Author: Dr. Benjamin T. Speake
7
+ Author-email: benjamin.speake@stfc.ac.uk
8
+ Project-URL: Logo, https://raw.githubusercontent.com/stfc/aiidalab-chemshell/refs/heads/main/images/alc-100.webp
9
+ Project-URL: Source, https://github.com/stfc/aiidalab-chemshell
10
+ Project-URL: Bug Tracker, https://github.com/stfc/aiidalab-chemshell/issues
11
+ Project-URL: Documentation, https://stfc.github.io/aiidalab-chemshell
12
+ Classifier: Framework :: AiiDA
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Development Status :: 4 - Beta
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: aiida-core
20
+ Requires-Dist: aiidalab-widgets-base
21
+ Requires-Dist: aiida-chemshell>=0.1.5
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest>=8.0; extra == "dev"
24
+ Requires-Dist: pytest-cov>=6.0; extra == "dev"
25
+ Requires-Dist: ruff>=0.11.0; extra == "dev"
26
+ Requires-Dist: pre-commit; extra == "dev"
27
+ Provides-Extra: docs
28
+ Requires-Dist: sphinx>=8.0.2; extra == "docs"
29
+ Requires-Dist: piccolo-theme>=0.14.0; extra == "docs"
30
+ Requires-Dist: sphinx-toolbox; extra == "docs"
31
+ Requires-Dist: numpydoc; extra == "docs"
32
+ Dynamic: license-file
@@ -0,0 +1,124 @@
1
+ # AiiDAlab ChemShell Plugin
2
+
3
+ ![Release](https://img.shields.io/badge/Release-none-red)
4
+ [![PyPI Version](https://img.shields.io/badge/PyPI-none-red)](https://pypi.org/)
5
+
6
+ [![Pipeline Status](https://github.com/stfc/aiidalab-chemshell/actions/workflows/ci-testing.yml/badge.svg?branch=main)](https://github.com/stfc/aiidalab-chemshell/actions)
7
+ [![Docs status](https://github.com/stfc/aiidalab-chemshell/actions/workflows/ci-docs.yml/badge.svg?branch=main)](https://stfc.github.io/aiidalab-chemshell/)
8
+ <!-- [![Coverage Status]( https://coveralls.io/repos/github/stfc/aiidalab-chemshell/badge.svg?branch=main)](https://coveralls.io/github/stfc/aiidalab-chemshell?branch=main) -->
9
+
10
+ [![DOI](badge)](https://zenodo.org/)
11
+
12
+ This is an AiiDAlab application plugin for ChemShell based scientific workflows, maintained by the [Ada Lovelace Center](https://adalovelacecentre.ac.uk/) (ALC).
13
+ The app is still in early development stage and any input/contributions are welcome.
14
+ Full documentation can be found here: [https://stfc.github.io/aiidalab-chemshell/](https://stfc.github.io/aiidalab-chemshell/).
15
+
16
+ ## Usage
17
+
18
+ This plugin is hosted on the AiiDAlab plugin registry and therefore can be installed via the AiiDAlab plugin
19
+ management UI page from within the AiiDAlab application interface. Instructions for how to run AiiDAlab
20
+ itself can be found in its [documentation](https://aiidalab.readthedocs.io/en/latest/usage/access/index.html)
21
+ and are also included in the documentation associated with this project
22
+ [https://stfc.github.io/aiidalab-chemshell/](https://stfc.github.io/aiidalab-chemshell/).
23
+ It is generally recommended to run AiiDAlab through a container engine such as Docker or Apptainer, both of
24
+ which are discussed in more detail in the documentation provided. In general the core docker image applicable
25
+ to most use cases is [aiidalab/full-stack:latest](https://hub.docker.com/r/aiidalab/full-stack) however, many
26
+ other options exist for more tailored startup environments.
27
+
28
+ ## ChemShell Containers
29
+
30
+ Multiple docker images are provided with this repository which build on the core foundation of the images
31
+ provided by AiiDAlab bundling various components of the ChemShell workflows on-top of the core AiiDAlab
32
+ application. At present two images are available; [base](https://github.com/stfc/aiidalab-chemshell/pkgs/container/aiidalab-chemshell%2Fbase) includes the AiiDAlab ChemShell plugin pre-installed including all
33
+ required dependencies,
34
+ [full](https://github.com/stfc/aiidalab-chemshell/pkgs/container/aiidalab-chemshell%2Ffull) builds upon
35
+ the base package including a working installation of ChemShell (version 25) configured with DL_POLY, NWChem
36
+ and PySCF as available backends.
37
+
38
+ To run one of the provided containers, first install and setup your desired container engine, then run the
39
+ image as follows,
40
+
41
+ ``` sh
42
+ docker run -it --rm -p 8888:8888 -v $HOME:/home/jovyan ghcr.io/stfc/aiidalab-chemshell/base:latest
43
+ ```
44
+
45
+ The additional run parameters will run the container interactively (``-it``), delete it when it is finished
46
+ (``--rm``), expose the required port for the jupyter notebook instance (``-p 8888:8888``) and the final flag
47
+ (``-v``) binds the home directory into the containers home directory so data can be made available and will
48
+ persist beyond the container instance. For more information on how to configure containers for AiiDAlab
49
+ see [https://stfc.github.io/alc-ux](https://stfc.github.io/alc-ux).
50
+
51
+ ## For Developers
52
+
53
+ ### Style Checking
54
+
55
+ This package uses pre-commit hooks to check for style consistency, to use these the ``pre-commit`` tool is required.
56
+ This can be installed alongside the base package by running,
57
+
58
+ ``` sh
59
+ pip install .[dev]
60
+ ```
61
+
62
+ or separately via,
63
+
64
+ ``` sh
65
+ pip install pre-commit
66
+ ```
67
+
68
+ Once installed run,
69
+
70
+ ``` sh
71
+ pre-commit install
72
+ ```
73
+
74
+ in the base repository to enable the pre-commit hooks.
75
+ This will now run style and formatting checks on every commit.
76
+
77
+ ### Testing
78
+
79
+ This package uses [pytest](https://docs.pytest.org/en/stable/)
80
+ to run all unit tests which is included in the ```[dev]``` optional
81
+ package dependencies. Once installed it can be run from the project root directory.
82
+ The CI workflows are configured to ensure all tests pass
83
+ before a pull request can be accepted into the main repository.
84
+ It is important that any new additions to the code base are accompanied
85
+ by appropriate testing, maintaining a high code coverage. The coverage
86
+ can be checked via,
87
+
88
+ ``` sh
89
+ pytest --cov=aiidalab_alc
90
+ ```
91
+
92
+ ### Documentation
93
+
94
+ The documentation, including a User Guide, Developer Guide and an API reference,
95
+ is built using [sphinx](https://www.sphinx-doc.org/). The source
96
+ for which is contained in the ```docs/``` directory. At present
97
+ only the html generator has been fully tested. All required packages can
98
+ be installed alongside the core package via,
99
+
100
+ ``` sh
101
+ pip install .[docs]
102
+ ```
103
+
104
+ and then the documentation can be built using sphinx-build,
105
+
106
+ ``` sh
107
+ sphinx-build -b html docs/source/ docs/build/html
108
+ ```
109
+
110
+ from the root directory.
111
+
112
+ ## License
113
+
114
+ [BSD 3-Clause License](LICENSE)
115
+
116
+ ## Funding
117
+
118
+ Contributors to this project were funded by
119
+
120
+ <div align="center">
121
+ <a href="https://adalovelacecentre.ac.uk/">
122
+ <img src="images/alc.svg" alt="ALC Logo" style="width: 30%">
123
+ </a>
124
+ </div>
@@ -0,0 +1,31 @@
1
+ [build-system]
2
+ requires = ["setuptools>=62.6"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+
6
+ [tool.ruff]
7
+ target-version = "py310"
8
+ exclude = ["conf.py",]
9
+
10
+ [tool.ruff.lint]
11
+ select = [
12
+ # flake8-bugbear
13
+ "B",
14
+ # pylint
15
+ "C", "R",
16
+ # pydocstyle
17
+ "D",
18
+ # pycodestyle
19
+ "E", "W",
20
+ # Pyflakes
21
+ "F", "FA",
22
+ # isort
23
+ "I",
24
+ # pep8-naming
25
+ "N",
26
+ # pyupgrade
27
+ "UP",
28
+ ]
29
+
30
+ [tool.ruff.lint.pydocstyle]
31
+ convention = "numpy"
@@ -0,0 +1,55 @@
1
+ [aiidalab]
2
+ title = AiiDAlab ChemShell
3
+ categories =
4
+ Classical
5
+ Quantum
6
+
7
+ [metadata]
8
+ name = aiidalab-chemshell
9
+ version = 0.0.1
10
+ author = Dr. Benjamin T. Speake
11
+ author_email = benjamin.speake@stfc.ac.uk
12
+ description = AiiDAlab application for ChemShell based workflows
13
+ long_description = file: README
14
+ long_description_content_type = text/markdown
15
+ url = https://github.com/stfc/aiidalab-chemshell
16
+ project_urls =
17
+ Logo = https://raw.githubusercontent.com/stfc/aiidalab-chemshell/refs/heads/main/images/alc-100.webp
18
+ Source = https://github.com/stfc/aiidalab-chemshell
19
+ Bug Tracker = https://github.com/stfc/aiidalab-chemshell/issues
20
+ Documentation = https://stfc.github.io/aiidalab-chemshell
21
+ classifiers =
22
+ Framework :: AiiDA
23
+ Operating System :: OS Independent
24
+ Programming Language :: Python :: 3
25
+ Development Status :: 4 - Beta
26
+
27
+ [options]
28
+ package_dir =
29
+ = src
30
+ packages = find:
31
+ install_requires =
32
+ aiida-core
33
+ aiidalab-widgets-base
34
+ aiida-chemshell>=0.1.5
35
+ python_requires = >=3.9
36
+
37
+ [options.packages.find]
38
+ where = src
39
+
40
+ [options.extras_require]
41
+ dev =
42
+ pytest>=8.0
43
+ pytest-cov>=6.0
44
+ ruff>=0.11.0
45
+ pre-commit
46
+ docs =
47
+ sphinx>=8.0.2
48
+ piccolo-theme>=0.14.0
49
+ sphinx-toolbox
50
+ numpydoc
51
+
52
+ [egg_info]
53
+ tag_build =
54
+ tag_date = 0
55
+
@@ -0,0 +1,5 @@
1
+ """The main AiiDAlab ChemShell python package."""
2
+
3
+ from importlib.metadata import version
4
+
5
+ __version__ = version("aiidalab-chemshell")
@@ -0,0 +1 @@
1
+ """Package for general common components."""
@@ -0,0 +1,53 @@
1
+ """Module containing common settings for configuring ChemShell."""
2
+
3
+ from enum import Enum, auto
4
+
5
+
6
+ class BasisSetOptions(Enum):
7
+ """Pre-defined basis set levels for simplified ChemShell inputs."""
8
+
9
+ FAST = 0
10
+ BALANCED = auto()
11
+ QUALITY = auto()
12
+
13
+ @property
14
+ def label(self) -> str:
15
+ """Convert enum value to a string representation for ChemShell input."""
16
+ match self:
17
+ case BasisSetOptions.FAST:
18
+ return "3-21G"
19
+ case BasisSetOptions.BALANCED:
20
+ return "cc-pvdz"
21
+ case BasisSetOptions.QUALITY:
22
+ return "aug-cc-pvtz"
23
+ case "":
24
+ return ""
25
+
26
+
27
+ class WorkflowOptions(Enum):
28
+ """Enum defining the available ChemShell based AiiDA workflows."""
29
+
30
+ GEOMETRY = 0
31
+ NEB = auto()
32
+
33
+ @property
34
+ def label(self) -> str:
35
+ """Convert enum value into a more human readable string."""
36
+ match self:
37
+ case WorkflowOptions.GEOMETRY:
38
+ return "Geometry Optimisation"
39
+ case WorkflowOptions.NEB:
40
+ return "Nudged Elastic Band"
41
+ case _:
42
+ return ""
43
+
44
+ @property
45
+ def tab_label(self) -> str:
46
+ """Create a tab title for the given enum option."""
47
+ match self:
48
+ case WorkflowOptions.GEOMETRY:
49
+ return "Optimisation"
50
+ case WorkflowOptions.NEB:
51
+ return "NEB"
52
+ case _:
53
+ return "ChemShell"
@@ -0,0 +1,170 @@
1
+ """Module for components relating to AiiDA database management."""
2
+
3
+ import datetime
4
+
5
+ import ipywidgets as ipw
6
+ import traitlets as tl
7
+ from aiida.orm import (
8
+ CalcFunctionNode,
9
+ CalcJobNode,
10
+ Node,
11
+ QueryBuilder,
12
+ WorkChainNode,
13
+ )
14
+
15
+
16
+ class AiiDADatabaseWidget(ipw.VBox, tl.HasTraits):
17
+ """Widget for AiiDA database querying."""
18
+
19
+ data_object = tl.Instance(Node, allow_none=True)
20
+
21
+ def __init__(self, title: str = "", query: list | None = None):
22
+ if query is None:
23
+ query = []
24
+ self.title = title
25
+ self.query_type = tuple(query)
26
+
27
+ qbuilder = QueryBuilder().append((CalcJobNode, WorkChainNode), project="label")
28
+
29
+ self.drop_down = ipw.Dropdown(
30
+ options=sorted({"All"}.union({i[0] for i in qbuilder.iterall() if i[0]})),
31
+ value="All",
32
+ description="Process Label",
33
+ disabled=True,
34
+ style={"description_width": "120px"},
35
+ layout={"width": "50%"},
36
+ )
37
+ self.drop_down.observe(self.search, names="value")
38
+
39
+ # Disable process labels selection if we are not looking for the calculated
40
+ # structures.
41
+ def disable_drop_down(change):
42
+ self.drop_down.disabled = not change["new"] == "calculated"
43
+
44
+ # Select structures kind.
45
+ self.mode = ipw.RadioButtons(
46
+ options=["all", "uploaded", "calculated"], layout={"width": "25%"}
47
+ )
48
+ self.mode.observe(self.search, names="value")
49
+ self.mode.observe(disable_drop_down, names="value")
50
+
51
+ # Date range.
52
+ # Note: there is Date picker widget, but it currently does not work in Safari:
53
+ # https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20List.html#Date-picker
54
+ date_text = ipw.HTML(value="<p>Select the date range:</p>")
55
+ self.start_date_widget = ipw.Text(
56
+ value="", description="From: ", style={"description_width": "120px"}
57
+ )
58
+ self.end_date_widget = ipw.Text(value="", description="To: ")
59
+
60
+ # Search button.
61
+ btn_search = ipw.Button(
62
+ description="Search",
63
+ button_style="info",
64
+ layout={"width": "initial", "margin": "2px 0 0 2em"},
65
+ )
66
+ btn_search.on_click(self.search)
67
+
68
+ age_selection = ipw.VBox(
69
+ [
70
+ date_text,
71
+ ipw.HBox([self.start_date_widget, self.end_date_widget, btn_search]),
72
+ ],
73
+ layout={"border": "1px solid #fafafa", "padding": "1em"},
74
+ )
75
+
76
+ h_line = ipw.HTML("<hr>")
77
+ box = ipw.VBox([age_selection, h_line, ipw.HBox([self.mode, self.drop_down])])
78
+
79
+ self.results = ipw.Dropdown(layout={"width": "900px"})
80
+ self.results.observe(self._on_select_structure, names="value")
81
+ self.search()
82
+ super().__init__([box, h_line, self.results])
83
+
84
+ def search(self, _=None) -> None:
85
+ """Search structures in the AiiDA database."""
86
+ qbuild = QueryBuilder()
87
+
88
+ # If the date range is valid, use it for the search
89
+ try:
90
+ start_date = datetime.datetime.strptime(
91
+ self.start_date_widget.value, "%Y-%m-%d"
92
+ )
93
+ end_date = datetime.datetime.strptime(
94
+ self.end_date_widget.value, "%Y-%m-%d"
95
+ ) + datetime.timedelta(hours=24)
96
+
97
+ # Otherwise revert to the standard (i.e. last 7 days)
98
+ except ValueError:
99
+ start_date = datetime.datetime.now() - datetime.timedelta(days=7)
100
+ end_date = datetime.datetime.now() + datetime.timedelta(hours=24)
101
+
102
+ self.start_date_widget.value = start_date.strftime("%Y-%m-%d")
103
+ self.end_date_widget.value = end_date.strftime("%Y-%m-%d")
104
+
105
+ filters = {}
106
+ filters["ctime"] = {"and": [{">": start_date}, {"<=": end_date}]}
107
+
108
+ if self.mode.value == "uploaded":
109
+ qbuild2 = (
110
+ QueryBuilder()
111
+ .append(self.query_type, project=["id"], tag="structures")
112
+ .append(Node, with_outgoing="structures")
113
+ )
114
+ processed_nodes = [n[0] for n in qbuild2.all()]
115
+ if processed_nodes:
116
+ filters["id"] = {"!in": processed_nodes}
117
+ qbuild.append(self.query_type, filters=filters)
118
+
119
+ elif self.mode.value == "calculated":
120
+ if self.drop_down.value == "All":
121
+ qbuild.append((CalcJobNode, WorkChainNode), tag="calcjobworkchain")
122
+ else:
123
+ qbuild.append(
124
+ (CalcJobNode, WorkChainNode),
125
+ filters={"label": self.drop_down.value},
126
+ tag="calcjobworkchain",
127
+ )
128
+ qbuild.append(
129
+ self.query_type,
130
+ with_incoming="calcjobworkchain",
131
+ filters=filters,
132
+ )
133
+
134
+ elif self.mode.value == "edited":
135
+ qbuild.append(CalcFunctionNode)
136
+ qbuild.append(
137
+ self.query_type,
138
+ with_incoming=CalcFunctionNode,
139
+ filters=filters,
140
+ )
141
+
142
+ elif self.mode.value == "all":
143
+ qbuild.append(self.query_type, filters=filters)
144
+
145
+ qbuild.order_by({self.query_type: {"ctime": "desc"}})
146
+ matches = {n[0] for n in qbuild.iterall()}
147
+ matches = sorted(matches, reverse=True, key=lambda n: n.ctime)
148
+
149
+ options = [(f"Select a Node ({len(matches)} found)", False)]
150
+ for mch in matches:
151
+ label = f"PK: {mch.pk}"
152
+ label += " | " + mch.ctime.strftime("%Y-%m-%d %H:%M")
153
+ label += " | " + mch.base.extras.get("formula", "")
154
+ label += " | " + mch.node_type.split(".")[-2]
155
+ label += " | " + mch.label
156
+ label += " | " + mch.description
157
+ options.append((label, mch))
158
+
159
+ self.results.options = options
160
+ return
161
+
162
+ def _on_select_structure(self, _) -> None:
163
+ self.data_object = self.results.value or None
164
+ return
165
+
166
+ def disable(self, val: bool) -> None:
167
+ """Disable the widget."""
168
+ self.results.disabled = True
169
+ # self.
170
+ return
@@ -0,0 +1,89 @@
1
+ """Module for providing functionality to deal with files."""
2
+
3
+ from io import BytesIO
4
+
5
+ import traitlets as tl
6
+ from aiida.orm import SinglefileData
7
+ from ipywidgets import FileUpload, HBox, Text
8
+
9
+
10
+ class FileUploadWidget(HBox, tl.HasTraits):
11
+ """A widget for uploading files."""
12
+
13
+ file = tl.Instance(SinglefileData, allow_none=True)
14
+
15
+ def __init__(self, description: str = "File: ", **kwargs):
16
+ """
17
+ FileUploadWidget constructor.
18
+
19
+ Parameters
20
+ ----------
21
+ **kwargs :
22
+ Keyword arguments passed to the parent class's constructor.
23
+ """
24
+ super().__init__(**kwargs)
25
+ self.file_dict = None
26
+
27
+ self.file_upload = FileUpload(
28
+ accept="",
29
+ multiple=False,
30
+ description="Upload",
31
+ layout={"width": "20%"},
32
+ )
33
+ self.file_handle = Text(
34
+ value="",
35
+ placeholder="",
36
+ description=description,
37
+ disabled=True,
38
+ layout={"width": "70%"},
39
+ )
40
+ self.children = [self.file_handle, self.file_upload]
41
+
42
+ self.file_upload.observe(self._on_file_upload, names="value")
43
+
44
+ return
45
+
46
+ @property
47
+ def has_file(self) -> bool:
48
+ """True if a file has been uploaded."""
49
+ return self.file is not None
50
+
51
+ def _on_file_upload(self, _):
52
+ """Handle file upload events."""
53
+ if self.file_upload.value:
54
+ self.file_dict = self.file_upload.value[
55
+ list(self.file_upload.value.keys())[0]
56
+ ]
57
+ self.file_handle.value = self.file_dict["metadata"]["name"]
58
+ self.file = self.get_aiida_file_object()
59
+ else:
60
+ self.file_handle.value = ""
61
+ return
62
+
63
+ def get_file_contents(self) -> BytesIO | None:
64
+ """Get the contents of the uploaded file as a BytesIO object."""
65
+ if self.file_dict is not None:
66
+ return BytesIO(self.file_dict["content"])
67
+ return None
68
+
69
+ def filename(self) -> str:
70
+ """Get the name of the uploaded file."""
71
+ if self.file_dict is not None:
72
+ return self.file_dict["metadata"]["name"]
73
+ return ""
74
+
75
+ def get_aiida_file_object(self):
76
+ """Get the uploaded file as an AiiDA SinglefileData object."""
77
+ if self.file_dict is not None:
78
+ return SinglefileData(
79
+ file=self.get_file_contents(),
80
+ filename=self.filename(),
81
+ label=self.filename(),
82
+ description=self.file_handle.description,
83
+ )
84
+ return None
85
+
86
+ def disable(self, val: bool) -> None:
87
+ """Disable the file upload widget."""
88
+ self.file_upload.disabled = val
89
+ return
@@ -0,0 +1,81 @@
1
+ """Module handling navigation controls within the app."""
2
+
3
+ from functools import partial
4
+
5
+ import ipywidgets as ipw
6
+
7
+ from aiidalab_chemshell.utils import open_link_in_new_tab
8
+
9
+ _APPS_DIRECTORY = "/apps/apps/"
10
+
11
+
12
+ class QuickAccessButtons(ipw.HBox):
13
+ """Quick access buttons present in the apps header and start banner."""
14
+
15
+ def __init__(self, **kwargs):
16
+ """
17
+ QuickAccessButtons constructor.
18
+
19
+ Parameters
20
+ ----------
21
+ **kwargs :
22
+ Keyword arguments passed to the `ipywidgets.HBox.__init__()`.
23
+ """
24
+ self.new_calc_link = ipw.Button(
25
+ description="New Calculation",
26
+ disabled=False,
27
+ button_style="success",
28
+ tooltip="Start a new calculation",
29
+ icon="plus",
30
+ )
31
+ self.new_calc_link.on_click(
32
+ partial(
33
+ open_link_in_new_tab,
34
+ _APPS_DIRECTORY + "aiidalab-chemshell/notebooks/main.ipynb",
35
+ )
36
+ )
37
+
38
+ self.history_link = ipw.Button(
39
+ description="History",
40
+ disabled=False,
41
+ button_style="primary",
42
+ tooltip="View Calculation History",
43
+ icon="history",
44
+ )
45
+ self.history_link.on_click(
46
+ partial(
47
+ open_link_in_new_tab,
48
+ _APPS_DIRECTORY + "aiidalab-chemshell/notebooks/history.ipynb",
49
+ )
50
+ )
51
+
52
+ self.resource_setup_link = ipw.Button(
53
+ description="Setup Resources",
54
+ disabled=False,
55
+ button_style="primary",
56
+ tooltip="Configure Computational Resources",
57
+ icon="cogs",
58
+ )
59
+ self.resource_setup_link.on_click(
60
+ partial(open_link_in_new_tab, _APPS_DIRECTORY + "home/code_setup.ipynb")
61
+ )
62
+
63
+ self.docs_link = ipw.Button(
64
+ description="Documentation",
65
+ disabled=False,
66
+ button_style="info",
67
+ tooltip="Open Documentation",
68
+ icon="book",
69
+ )
70
+ self.docs_link.on_click(
71
+ partial(open_link_in_new_tab, "https://github.com/stfc/aiidalab-chemshell")
72
+ )
73
+
74
+ children = [
75
+ self.new_calc_link,
76
+ self.history_link,
77
+ self.resource_setup_link,
78
+ self.docs_link,
79
+ ]
80
+ super().__init__(children=children, layout={"margin": "auto"}, **kwargs)
81
+ return