diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 123447ae1..658562e09 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -24,28 +24,16 @@ repos:
hooks:
- id: check-github-workflows
- - repo: https://github.com/nbQA-dev/nbQA
- rev: 1.8.5
- hooks:
- - id: nbqa-pyupgrade
- args: [--py38-plus]
- - id: nbqa-isort
- args: [--profile=black]
- - id: nbqa-ruff
- # suppress E402
- args: [--ignore=E402]
-
- repo: https://github.com/kynan/nbstripout
rev: 0.7.1
hooks:
- id: nbstripout
- repo: https://github.com/astral-sh/ruff-pre-commit
- # Ruff version.
- rev: v0.5.0
+ rev: v0.5.5
hooks:
- # Run the linter.
- id: ruff
+ types_or: [python, pyi, jupyter]
args: [--fix]
- # Run the formatter.
- id: ruff-format
+ types_or: [python, pyi, jupyter]
diff --git a/delete.ipynb b/delete.ipynb
index 374c73a0f..670a6561f 100644
--- a/delete.ipynb
+++ b/delete.ipynb
@@ -18,18 +18,19 @@
"import urllib.parse as urlparse\n",
"\n",
"import ipywidgets as widgets\n",
+ "from IPython.display import Markdown, display\n",
+ "\n",
"from aiida import load_profile\n",
"from aiida.orm import load_node\n",
"from aiida.tools import delete_nodes\n",
- "from IPython.display import Markdown, display\n",
"\n",
"# Load AiiDA profile\n",
"load_profile()\n",
"\n",
"# Parse the primary key from the Jupyter notebook URL\n",
- "url = urlparse.urlsplit(jupyter_notebook_url) # noqa F821\n",
+ "url = urlparse.urlsplit(jupyter_notebook_url) # noqa F821\n",
"query = urlparse.parse_qs(url.query)\n",
- "pk = int(query['pk'][0])\n",
+ "pk = int(query[\"pk\"][0])\n",
"\n",
"\n",
"def display_node_details(pk):\n",
@@ -41,7 +42,7 @@
" print(f\"Description: {node.description}\")\n",
" print(f\"Creation Time: {node.ctime}\")\n",
" except Exception as e:\n",
- " print(f\"Error loading node: {str(e)}\")\n",
+ " print(f\"Error loading node: {e!s}\")\n",
" return False\n",
" return True\n",
"\n",
@@ -50,31 +51,36 @@
" if dry_run:\n",
" _, was_deleted = delete_nodes([pk], dry_run=True)\n",
" if was_deleted:\n",
- " print(f'Dry run: Node {pk} can be deleted.')\n",
+ " print(f\"Dry run: Node {pk} can be deleted.\")\n",
" return\n",
- " \n",
+ "\n",
" _, was_deleted = delete_nodes([pk], dry_run=False)\n",
" if was_deleted:\n",
- " print(f'Node {pk} deleted successfully.')\n",
+ " print(f\"Node {pk} deleted successfully.\")\n",
"\n",
"\n",
- "def confirm_deletion(b):\n",
- " if delete_confirmation.value.lower() in ['y', 'yes']:\n",
+ "def confirm_deletion(_):\n",
+ " if delete_confirmation.value.lower() in (\"y\", \"yes\"):\n",
" delete_node(pk, dry_run=False)\n",
" else:\n",
- " print('Deletion aborted.')\n",
+ " print(\"Deletion aborted.\")\n",
"\n",
"\n",
- "def find_linked_qeapp_jobs(root_node_pk, process_label='QeAppWorkChain'):\n",
+ "def find_linked_qeapp_jobs(root_node_pk, process_label=\"QeAppWorkChain\"):\n",
" \"\"\"Query all linked node with process_label = QeAppWorkChain.\"\"\"\n",
" from aiida.orm import Node, QueryBuilder\n",
" from aiida.orm.nodes.process.workflow.workchain import WorkChainNode\n",
+ "\n",
" qb = QueryBuilder()\n",
- " qb.append(WorkChainNode, filters={'id': root_node_pk}, tag='root')\n",
- " qb.append(Node, with_incoming='root', tag='calcjob')\n",
+ " qb.append(WorkChainNode, filters={\"id\": root_node_pk}, tag=\"root\")\n",
+ " qb.append(Node, with_incoming=\"root\", tag=\"calcjob\")\n",
" # There are seems a bug with `with_ancestors` in the QueryBuilder, so we have to use `with_incoming` instead.\n",
- " # For the moment, it's safe to use `with_incoming` since we check it very time we delete a QEApp \n",
- " qb.append(WorkChainNode, filters={'attributes.process_label': 'QeAppWorkChain'}, with_incoming='calcjob')\n",
+ " # For the moment, it's safe to use `with_incoming` since we check it very time we delete a QEApp\n",
+ " qb.append(\n",
+ " WorkChainNode,\n",
+ " filters={\"attributes.process_label\": process_label},\n",
+ " with_incoming=\"calcjob\",\n",
+ " )\n",
" results = qb.all()\n",
" if len(results) == 0:\n",
" return None\n",
@@ -96,12 +102,16 @@
" else:\n",
" # Ask for confirmation\n",
" nodes, _ = delete_nodes([pk], dry_run=True)\n",
- " display(Markdown(f'**YOU ARE ABOUT TO DELETE `{len(nodes)}` NODES! THIS CANNOT BE UNDONE!**'))\n",
+ " display(\n",
+ " Markdown(\n",
+ " f\"**YOU ARE ABOUT TO DELETE `{len(nodes)}` NODES! THIS CANNOT BE UNDONE!**\"\n",
+ " )\n",
+ " )\n",
" delete_confirmation = widgets.Text(\n",
- " value='',\n",
+ " value=\"\",\n",
" placeholder='Type \"yes\" to confirm',\n",
- " description='Confirm:',\n",
- " disabled=False\n",
+ " description=\"Confirm:\",\n",
+ " disabled=False,\n",
" )\n",
" confirm_button = widgets.Button(description=\"Delete Node\")\n",
" confirm_button.on_click(confirm_deletion)\n",
diff --git a/docs/source/conf.py b/docs/source/conf.py
index fc0719077..8f39260d7 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -9,13 +9,8 @@
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
-#
-# import os
-# import sys
import time
-# sys.path.insert(0, os.path.abspath('.'))
-
# -- Project information -----------------------------------------------------
version = "v24.10.0a1"
@@ -30,9 +25,7 @@
if current_year == copyright_first_year
else f"{copyright_first_year}-{current_year}"
)
-copyright = "{}, {}. All rights reserved".format(
- copyright_year_string, copyright_owners
-)
+copyright = f"{copyright_year_string}, {copyright_owners}. All rights reserved" # noqa: A001
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
diff --git a/plugin_list.ipynb b/plugin_list.ipynb
index 72741f3c5..30c17bc48 100644
--- a/plugin_list.ipynb
+++ b/plugin_list.ipynb
@@ -29,12 +29,12 @@
"# Get the current working directory\n",
"cwd = Path.cwd()\n",
"# Define a relative path\n",
- "relative_path = 'plugins.yaml'\n",
+ "relative_path = \"plugins.yaml\"\n",
"# Resolve the relative path to an absolute path\n",
"yaml_file = cwd / relative_path\n",
"\n",
"# Load the YAML content\n",
- "with yaml_file.open('r') as file:\n",
+ "with yaml_file.open(\"r\") as file:\n",
" data = yaml.safe_load(file)"
]
},
@@ -54,28 +54,34 @@
"\n",
"def is_package_installed(package_name):\n",
" import importlib\n",
- " package_name = package_name.replace('-', '_')\n",
+ "\n",
+ " package_name = package_name.replace(\"-\", \"_\")\n",
" try:\n",
" importlib.import_module(package_name)\n",
- " return True\n",
" except ImportError:\n",
" return False\n",
+ " else:\n",
+ " return True\n",
"\n",
"\n",
"def stream_output(process, output_widget):\n",
" \"\"\"Reads output from the process and forwards it to the output widget.\"\"\"\n",
" while True:\n",
" output = process.stdout.readline()\n",
- " if process.poll() is not None and output == '':\n",
+ " if process.poll() is not None and output == \"\":\n",
" break\n",
" if output:\n",
" output_widget.value += f\"\"\"
{output}
\"\"\"\n",
"\n",
"\n",
- "def execute_command_with_output(command, output_widget, install_btn, remove_btn, action=\"install\"):\n",
+ "def execute_command_with_output(\n",
+ " command, output_widget, install_btn, remove_btn, action=\"install\"\n",
+ "):\n",
" \"\"\"Execute a command and stream its output to the given output widget.\"\"\"\n",
" output_widget.value = \"\" # Clear the widget\n",
- " process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1)\n",
+ " process = subprocess.Popen(\n",
+ " command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1\n",
+ " )\n",
" # Create a thread to read the output stream and write it to the output widget\n",
" thread = Thread(target=stream_output, args=(process, output_widget))\n",
" thread.start()\n",
@@ -94,63 +100,120 @@
" return False\n",
"\n",
"\n",
- "def install_package(package_name, pip, github, post_install, output_container, message_container, install_btn, remove_btn, accordion, index):\n",
+ "def install_package(\n",
+ " package_name,\n",
+ " pip,\n",
+ " github,\n",
+ " post_install,\n",
+ " output_container,\n",
+ " message_container,\n",
+ " install_btn,\n",
+ " remove_btn,\n",
+ " accordion,\n",
+ " index,\n",
+ "):\n",
" if pip:\n",
" command = [\"pip\", \"install\", pip, \"--user\"]\n",
" else:\n",
" command = [\"pip\", \"install\", \"git+\" + github, \"--user\"]\n",
- " message_container.value = f\"\"\"Installing {package_name}...
\"\"\"\n",
- " result = execute_command_with_output(command, output_container, install_btn, remove_btn)\n",
+ " message_container.value = (\n",
+ " f\"\"\"Installing {package_name}...
\"\"\"\n",
+ " )\n",
+ " result = execute_command_with_output(\n",
+ " command, output_container, install_btn, remove_btn\n",
+ " )\n",
" # Execute post install if defined in the plugin.yaml:\n",
- " if post_install: \n",
- " message_container.value += \"\"\"Post installation step...
\"\"\"\n",
- " command = [sys.executable, '-m', package_name.replace('-','_'), post_install]\n",
+ " if post_install:\n",
+ " message_container.value += (\n",
+ " \"\"\"Post installation step...
\"\"\"\n",
+ " )\n",
+ " command = [sys.executable, \"-m\", package_name.replace(\"-\", \"_\"), post_install]\n",
" # Execute the command\n",
- " result = subprocess.run(command, capture_output=True, text=True)\n",
+ " result = subprocess.run(command, capture_output=True, text=True, check=False)\n",
" # if the package was installed successfully\n",
" if result:\n",
" message_container.value += \"\"\"Initiating test to load the plugin...
\"\"\"\n",
" # Test plugin functionality\n",
- " command = [sys.executable, '-m', 'aiidalab_qe', 'test-plugin', package_name]\n",
+ " command = [sys.executable, \"-m\", \"aiidalab_qe\", \"test-plugin\", package_name]\n",
" # Execute the command\n",
- " result = subprocess.run(command, capture_output=True, text=True)\n",
+ " result = subprocess.run(command, capture_output=True, text=True, check=False)\n",
" if result.returncode == 0:\n",
" # restart daemon\n",
- " message_container.value = \"\"\"Loading plugin test passed.
\"\"\"\n",
- " message_container.value += \"\"\"Plugin installed successfully.
\"\"\"\n",
+ " message_container.value = (\n",
+ " \"\"\"Loading plugin test passed.
\"\"\"\n",
+ " )\n",
+ " message_container.value += (\n",
+ " \"\"\"Plugin installed successfully.
\"\"\"\n",
+ " )\n",
" accordion.set_title(index, f\"{accordion.get_title(index)[:-2]} ✅\")\n",
" command = [\"verdi\", \"daemon\", \"restart\"]\n",
- " subprocess.run(command, capture_output=True, shell=False)\n",
+ " subprocess.run(command, capture_output=True, shell=False, check=False)\n",
" else:\n",
" # uninstall the package\n",
" message_container.value = f\"\"\"The plugin '{package_name}' was installed successfully but plugin functionality test failed: {result.stderr}.
\"\"\"\n",
" message_container.value += \"\"\"This may be due to compatibility issues with the current AiiDAlab QEApp version. Please contact the plugin author for further assistance.
\"\"\"\n",
" message_container.value += \"\"\"To prevent potential issues, the plugin will now be uninstalled.
\"\"\"\n",
- " remove_package(package_name, output_container, message_container, install_btn, remove_btn, accordion, index)\n",
+ " remove_package(\n",
+ " package_name,\n",
+ " output_container,\n",
+ " message_container,\n",
+ " install_btn,\n",
+ " remove_btn,\n",
+ " accordion,\n",
+ " index,\n",
+ " )\n",
"\n",
"\n",
- "def remove_package(package_name, output_container, message_container, install_btn, remove_btn, accordion, index):\n",
- " message_container.value += f\"\"\"Removing {package_name}...
\"\"\"\n",
- " package_name = package_name.replace('-', '_')\n",
+ "def remove_package(\n",
+ " package_name,\n",
+ " output_container,\n",
+ " message_container,\n",
+ " install_btn,\n",
+ " remove_btn,\n",
+ " accordion,\n",
+ " index,\n",
+ "):\n",
+ " message_container.value += (\n",
+ " f\"\"\"Removing {package_name}...
\"\"\"\n",
+ " )\n",
+ " package_name = package_name.replace(\"-\", \"_\")\n",
" command = [\"pip\", \"uninstall\", \"-y\", package_name]\n",
- " result = execute_command_with_output(command, output_container, install_btn, remove_btn, action=\"remove\")\n",
+ " result = execute_command_with_output(\n",
+ " command, output_container, install_btn, remove_btn, action=\"remove\"\n",
+ " )\n",
" if result:\n",
" message_container.value += f\"\"\"{package_name} removed successfully.
\"\"\"\n",
" accordion.set_title(index, f\"{accordion.get_title(index)[:-2]} ☐\")\n",
" command = [\"verdi\", \"daemon\", \"restart\"]\n",
- " subprocess.run(command, capture_output=True, shell=False)\n",
+ " subprocess.run(command, capture_output=True, shell=False, check=False)\n",
"\n",
"\n",
- "def run_remove_button(package_name, output_container, message_container, install_btn, remove_btn, accordion, index):\n",
+ "def run_remove_button(\n",
+ " package_name,\n",
+ " output_container,\n",
+ " message_container,\n",
+ " install_btn,\n",
+ " remove_btn,\n",
+ " accordion,\n",
+ " index,\n",
+ "):\n",
" message_container.value = \"\"\n",
- " remove_package(package_name, output_container, message_container, install_btn, remove_btn, accordion, index)\n",
+ " remove_package(\n",
+ " package_name,\n",
+ " output_container,\n",
+ " message_container,\n",
+ " install_btn,\n",
+ " remove_btn,\n",
+ " accordion,\n",
+ " index,\n",
+ " )\n",
"\n",
"\n",
"accordion = ipw.Accordion()\n",
"\n",
"for i, (plugin_name, plugin_data) in enumerate(data.items()):\n",
" installed = is_package_installed(plugin_name)\n",
- " \n",
+ "\n",
" # Output container with customized styling\n",
" output_container = ipw.HTML(\n",
" value=\"\"\"\n",
@@ -158,10 +221,8 @@
" \n",
" \"\"\",\n",
" layout=ipw.Layout(\n",
- " max_height='250px', \n",
- " overflow='auto',\n",
- " border='2px solid #CCCCCC'\n",
- " )\n",
+ " max_height=\"250px\", overflow=\"auto\", border=\"2px solid #CCCCCC\"\n",
+ " ),\n",
" )\n",
" # Output container with customized styling\n",
" message_container = ipw.HTML(\n",
@@ -170,35 +231,64 @@
" \n",
" \"\"\",\n",
" layout=ipw.Layout(\n",
- " max_height='250px', \n",
- " overflow='auto',\n",
- " border='2px solid #CCCCCC'\n",
- " )\n",
+ " max_height=\"250px\", overflow=\"auto\", border=\"2px solid #CCCCCC\"\n",
+ " ),\n",
" )\n",
- " \n",
- " details = f\"Author: {plugin_data.get('author', 'N/A')}
\" \\\n",
- " f\"Description: {plugin_data.get('description', 'No description available')}
\"\n",
- " if 'documentation' in plugin_data:\n",
+ "\n",
+ " details = (\n",
+ " f\"Author: {plugin_data.get('author', 'N/A')}
\"\n",
+ " f\"Description: {plugin_data.get('description', 'No description available')}
\"\n",
+ " )\n",
+ " if \"documentation\" in plugin_data:\n",
" details += f\"Documentation: Visit
\"\n",
- " if 'github' in plugin_data:\n",
- " details += f\"Github: Visit\"\n",
+ " if \"github\" in plugin_data:\n",
+ " details += (\n",
+ " f\"Github: Visit\"\n",
+ " )\n",
"\n",
- " install_btn = ipw.Button(description=\"Install\", button_style='success', disabled=installed)\n",
- " remove_btn = ipw.Button(description=\"Remove\", button_style='danger', disabled=not installed)\n",
+ " install_btn = ipw.Button(\n",
+ " description=\"Install\", button_style=\"success\", disabled=installed\n",
+ " )\n",
+ " remove_btn = ipw.Button(\n",
+ " description=\"Remove\", button_style=\"danger\", disabled=not installed\n",
+ " )\n",
"\n",
- " install_btn.on_click(lambda btn, pn=plugin_name, pip=plugin_data.get('pip', None), github=plugin_data.get('github', ''), post = plugin_data.get('post_install', None), oc=output_container, mc=message_container, ib=install_btn, rb=remove_btn, ac=accordion, index=i: install_package(pn, pip, github, post, oc, mc, ib, rb, ac, index))\n",
- " remove_btn.on_click(lambda btn, pn=plugin_name, oc=output_container, mc=message_container, ib=install_btn, rb=remove_btn, ac=accordion, index=i: run_remove_button(pn, oc, mc, ib, rb, ac, index))\n",
+ " install_btn.on_click(\n",
+ " lambda _btn,\n",
+ " pn=plugin_name,\n",
+ " pip=plugin_data.get(\"pip\", None), # noqa: B008\n",
+ " github=plugin_data.get(\"github\", \"\"), # noqa: B008\n",
+ " post=plugin_data.get(\"post_install\", None), # noqa: B008\n",
+ " oc=output_container,\n",
+ " mc=message_container,\n",
+ " ib=install_btn,\n",
+ " rb=remove_btn,\n",
+ " ac=accordion,\n",
+ " index=i: install_package(pn, pip, github, post, oc, mc, ib, rb, ac, index)\n",
+ " )\n",
+ " remove_btn.on_click(\n",
+ " lambda _btn,\n",
+ " pn=plugin_name,\n",
+ " oc=output_container,\n",
+ " mc=message_container,\n",
+ " ib=install_btn,\n",
+ " rb=remove_btn,\n",
+ " ac=accordion,\n",
+ " index=i: run_remove_button(pn, oc, mc, ib, rb, ac, index)\n",
+ " )\n",
"\n",
- " box = ipw.VBox([\n",
- " ipw.HTML(details),\n",
- " ipw.HBox([install_btn, remove_btn]),\n",
- " message_container,\n",
- " output_container,\n",
- " ])\n",
+ " box = ipw.VBox(\n",
+ " [\n",
+ " ipw.HTML(details),\n",
+ " ipw.HBox([install_btn, remove_btn]),\n",
+ " message_container,\n",
+ " output_container,\n",
+ " ]\n",
+ " )\n",
"\n",
" title_with_icon = f\"{plugin_name} {'✅' if installed else '☐'}\"\n",
" accordion.set_title(i, title_with_icon)\n",
- " accordion.children = list(accordion.children) + [box]\n",
+ " accordion.children = [*accordion.children, box]\n",
"\n",
"display(accordion)"
]
diff --git a/pyproject.toml b/pyproject.toml
index 1eb0ca77d..dd0525383 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,3 +4,36 @@ requires = [
"wheel"
]
build-backend = "setuptools.build_meta"
+
+[tool.ruff]
+line-length = 88
+show-fixes = true
+output-format = "full"
+target-version = "py39"
+extend-include = ["*.ipynb"]
+
+[tool.ruff.lint]
+ignore = ["E501", "E402", "TRY003", "RUF012", "N806"]
+select = [
+ "A", # flake8-builtins
+ "ARG", # flake8-unused-arguments
+ "B", # flake8-bugbear
+ "C4", # flake8-comprehensions
+ "E", # pycodestyle
+ "F", # pyflakes
+ "I", # isort
+ "N", # pep8-naming
+ "PLE", # pylint error rules
+ "PLW", # pylint warning rules
+ "PLC", # pylint convention rules
+ "RUF", # ruff-specific rules
+ "TRY", # Tryceratops
+ "UP" # pyupgrade
+]
+
+[tool.ruff.lint.isort]
+known-first-party = ["aiida", "aiidalab_widgets_base", "aiida_quantumespresso"]
+
+[tool.ruff.lint.per-file-ignores]
+"tests/*" = ["ARG001"]
+"tests_integration/*" = ["ARG001"]
diff --git a/qe.ipynb b/qe.ipynb
index 269e49674..cac6b0014 100644
--- a/qe.ipynb
+++ b/qe.ipynb
@@ -21,7 +21,7 @@
"source": [
"from aiida import load_profile\n",
"\n",
- "load_profile(); # noqa: E402"
+ "load_profile();"
]
},
{
@@ -42,15 +42,15 @@
"from datetime import datetime\n",
"\n",
"import ipywidgets as ipw\n",
- "from aiidalab_widgets_base.bug_report import (\n",
- " install_create_github_issue_exception_handler,\n",
- ")\n",
+ "from aiidalab_qe.app import App, static\n",
+ "from aiidalab_qe.version import __version__\n",
"from importlib_resources import files\n",
"from IPython.display import display\n",
"from jinja2 import Environment\n",
"\n",
- "from aiidalab_qe.app import App, static\n",
- "from aiidalab_qe.version import __version__"
+ "from aiidalab_widgets_base.bug_report import (\n",
+ " install_create_github_issue_exception_handler,\n",
+ ")"
]
},
{
@@ -69,14 +69,14 @@
" f'Copyright (c) {current_year} AiiDAlab team Version: {__version__}
'\n",
")\n",
"\n",
- "url = urlparse.urlsplit(jupyter_notebook_url) # noqa F821\n",
+ "url = urlparse.urlsplit(jupyter_notebook_url) # noqa F821\n",
"query = urlparse.parse_qs(url.query)\n",
"\n",
"\n",
"app_with_work_chain_selector = App(qe_auto_setup=True)\n",
"# if a pk is provided in the query string, set it as the value of the work_chain_selector\n",
- "if 'pk' in query:\n",
- " pk = int(query['pk'][0])\n",
+ "if \"pk\" in query:\n",
+ " pk = int(query[\"pk\"][0])\n",
" app_with_work_chain_selector.work_chain_selector.value = pk\n",
"\n",
"output = ipw.Output()\n",
diff --git a/src/aiidalab_qe/__main__.py b/src/aiidalab_qe/__main__.py
index 7ea58f39d..667b011c2 100644
--- a/src/aiidalab_qe/__main__.py
+++ b/src/aiidalab_qe/__main__.py
@@ -1,10 +1,11 @@
"""For running the app from the command line used for post_install script."""
-from pathlib import Path
import sys
+from pathlib import Path
+
import click
-from aiida import load_profile
+from aiida import load_profile
from aiidalab_qe.common.setup_codes import codes_are_setup
from aiidalab_qe.common.setup_codes import install as install_qe_codes
@@ -28,7 +29,7 @@ def install_qe(force, profile):
assert codes_are_setup()
click.secho("Codes are setup!", fg="green")
except Exception as error:
- raise click.ClickException(f"Failed to set up QE failed: {error}")
+ raise click.ClickException(f"Failed to set up QE failed: {error}") from error
@cli.command()
@@ -53,7 +54,9 @@ def install_pseudos(profile, source):
click.echo(msg)
click.secho("Pseudopotentials are installed!", fg="green")
except Exception as error:
- raise click.ClickException(f"Failed to set up pseudo potentials: {error}")
+ raise click.ClickException(
+ f"Failed to set up pseudo potentials: {error}"
+ ) from error
@cli.command()
@@ -75,7 +78,9 @@ def download_pseudos(dest):
click.secho("Pseudopotentials are downloaded!", fg="green")
except Exception as error:
- raise click.ClickException(f"Failed to download pseudo potentials: {error}")
+ raise click.ClickException(
+ f"Failed to download pseudo potentials: {error}"
+ ) from error
@cli.command()
diff --git a/src/aiidalab_qe/app/configuration/__init__.py b/src/aiidalab_qe/app/configuration/__init__.py
index ff28a9402..adebd3898 100644
--- a/src/aiidalab_qe/app/configuration/__init__.py
+++ b/src/aiidalab_qe/app/configuration/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
"""Widgets for the submission of bands work chains.
Authors: AiiDAlab team
@@ -8,10 +7,10 @@
import ipywidgets as ipw
import traitlets as tl
-from aiida import orm
-from aiidalab_widgets_base import WizardAppWidgetStep
+from aiida import orm
from aiidalab_qe.app.utils import get_entry_items
+from aiidalab_widgets_base import WizardAppWidgetStep
from .advanced import AdvancedSettings
from .workflow import WorkChainSettings
@@ -111,7 +110,7 @@ def __init__(self, **kwargs):
)
@tl.observe("previous_step_state")
- def _observe_previous_step_state(self, change):
+ def _observe_previous_step_state(self, _change):
self._update_state()
def get_configuration_parameters(self):
diff --git a/src/aiidalab_qe/app/configuration/advanced.py b/src/aiidalab_qe/app/configuration/advanced.py
index bc5e51faf..65a416960 100644
--- a/src/aiidalab_qe/app/configuration/advanced.py
+++ b/src/aiidalab_qe/app/configuration/advanced.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
"""Widgets for the submission of bands work chains.
Authors: AiiDAlab team
@@ -7,20 +6,21 @@
import os
import ipywidgets as ipw
+import numpy as np
import traitlets as tl
+from IPython.display import clear_output, display
+
from aiida import orm
-import numpy as np
from aiida_quantumespresso.calculations.functions.create_kpoints_from_distance import (
create_kpoints_from_distance,
)
+from aiida_quantumespresso.data.hubbard_structure import HubbardStructureData
from aiida_quantumespresso.workflows.pw.base import PwBaseWorkChain
-from IPython.display import clear_output, display
-
from aiidalab_qe.app.parameters import DEFAULT_PARAMETERS
from aiidalab_qe.common.panel import Panel
from aiidalab_qe.common.setup_pseudos import PseudoFamily
from aiidalab_qe.common.widgets import HubbardWidget
-from aiida_quantumespresso.data.hubbard_structure import HubbardStructureData
+
from .pseudos import PseudoFamilySelector, PseudoSetter
diff --git a/src/aiidalab_qe/app/configuration/pseudos.py b/src/aiidalab_qe/app/configuration/pseudos.py
index 912041c20..2a46a9bce 100644
--- a/src/aiidalab_qe/app/configuration/pseudos.py
+++ b/src/aiidalab_qe/app/configuration/pseudos.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
from __future__ import annotations
import io
@@ -6,18 +5,18 @@
import ipywidgets as ipw
import traitlets as tl
+
from aiida import orm
from aiida.common import exceptions
from aiida.plugins import DataFactory, GroupFactory
from aiida_quantumespresso.workflows.pw.base import PwBaseWorkChain
-from aiidalab_widgets_base.utils import StatusHTML
-
from aiidalab_qe.app.parameters import DEFAULT_PARAMETERS
from aiidalab_qe.common.setup_pseudos import (
PSEUDODOJO_VERSION,
SSSP_VERSION,
PseudoFamily,
)
+from aiidalab_widgets_base.utils import StatusHTML
UpfData = DataFactory("pseudo.upf")
SsspFamily = GroupFactory("pseudo.family.sssp")
@@ -128,6 +127,7 @@ def __init__(self, **kwargs):
self.pseudo_family_help,
],
layout=ipw.Layout(max_width="60%"),
+ **kwargs,
)
ipw.dlink((self.show_ui, "value"), (self.library_selection, "disabled"))
ipw.dlink((self.show_ui, "value"), (self.dft_functional, "disabled"))
@@ -338,7 +338,7 @@ def _reset_traitlets(self):
"""Reset the traitlets to the initial state"""
self.ecutwfc = 0
self.ecutrho = 0
- self.pseudos = dict()
+ self.pseudos = {}
def _reset(self):
"""Reset the pseudo setting widgets according to the structure
@@ -377,7 +377,7 @@ def _reset(self):
pseudo_family = self._get_pseudos_family(self.pseudo_family)
except exceptions.NotExistent as exception:
self._status_message.message = (
- f""" ERROR: {str(exception)}
"""
+ f""" ERROR: {exception!s}
"""
)
return
diff --git a/src/aiidalab_qe/app/configuration/workflow.py b/src/aiidalab_qe/app/configuration/workflow.py
index 9fc2f0159..47db49cc0 100644
--- a/src/aiidalab_qe/app/configuration/workflow.py
+++ b/src/aiidalab_qe/app/configuration/workflow.py
@@ -1,12 +1,11 @@
-# -*- coding: utf-8 -*-
"""Widgets for the submission of bands work chains.
Authors: AiiDAlab team
"""
import ipywidgets as ipw
-from aiida_quantumespresso.common.types import RelaxType
+from aiida_quantumespresso.common.types import RelaxType
from aiidalab_qe.app.parameters import DEFAULT_PARAMETERS
from aiidalab_qe.app.utils import get_entry_items
from aiidalab_qe.common.panel import Panel
diff --git a/src/aiidalab_qe/app/main.py b/src/aiidalab_qe/app/main.py
index deed96509..b02d4feb3 100644
--- a/src/aiidalab_qe/app/main.py
+++ b/src/aiidalab_qe/app/main.py
@@ -1,18 +1,17 @@
-# -*- coding: utf-8 -*-
"""The main widget that shows the application in the Jupyter notebook.
Authors: AiiDAlab team
"""
import ipywidgets as ipw
-from aiida.orm import load_node
-from aiidalab_widgets_base import WizardAppWidget, WizardAppWidgetStep
+from aiida.orm import load_node
from aiidalab_qe.app.configuration import ConfigureQeAppWorkChainStep
from aiidalab_qe.app.result import ViewQeAppWorkChainStatusAndResultsStep
from aiidalab_qe.app.structure import StructureSelectionStep
from aiidalab_qe.app.submission import SubmitQeAppWorkChainStep
from aiidalab_qe.common import QeAppWorkChainSelector
+from aiidalab_widgets_base import WizardAppWidget, WizardAppWidgetStep
class App(ipw.VBox):
diff --git a/src/aiidalab_qe/app/result/__init__.py b/src/aiidalab_qe/app/result/__init__.py
index 7a3d2640a..9451a28ac 100644
--- a/src/aiidalab_qe/app/result/__init__.py
+++ b/src/aiidalab_qe/app/result/__init__.py
@@ -1,5 +1,6 @@
import ipywidgets as ipw
import traitlets as tl
+
from aiida import orm
from aiida.engine import ProcessState
from aiida.engine.processes import control
diff --git a/src/aiidalab_qe/app/result/summary_viewer.py b/src/aiidalab_qe/app/result/summary_viewer.py
index 0bc1b728a..9524ebe27 100644
--- a/src/aiidalab_qe/app/result/summary_viewer.py
+++ b/src/aiidalab_qe/app/result/summary_viewer.py
@@ -1,4 +1,5 @@
import ipywidgets as ipw
+
from aiida_quantumespresso.workflows.pw.bands import PwBandsWorkChain
FUNCTIONAL_LINK_MAP = {
diff --git a/src/aiidalab_qe/app/result/workchain_viewer.py b/src/aiidalab_qe/app/result/workchain_viewer.py
index b90d76586..34ed75dc9 100644
--- a/src/aiidalab_qe/app/result/workchain_viewer.py
+++ b/src/aiidalab_qe/app/result/workchain_viewer.py
@@ -6,18 +6,18 @@
import ipywidgets as ipw
import traitlets as tl
-from aiida import orm
-from aiida.cmdline.utils.common import get_workchain_report
-from aiida.common import LinkType
-from aiida.orm.utils.serialize import deserialize_unsafe
-from aiidalab_widgets_base import ProcessMonitor, register_viewer_widget
-from aiidalab_widgets_base.viewers import StructureDataViewer
from filelock import FileLock, Timeout
from IPython.display import HTML, display
from jinja2 import Environment
+from aiida import orm
+from aiida.cmdline.utils.common import get_workchain_report
+from aiida.common import LinkType
+from aiida.orm.utils.serialize import deserialize_unsafe
from aiidalab_qe.app import static
from aiidalab_qe.app.utils import get_entry_items
+from aiidalab_widgets_base import ProcessMonitor, register_viewer_widget
+from aiidalab_widgets_base.viewers import StructureDataViewer
from .summary_viewer import SummaryView
@@ -147,7 +147,9 @@ class WorkChainOutputs(ipw.VBox):
_busy = tl.Bool(read_only=True)
def __init__(self, node, export_dir=None, **kwargs):
- self.export_dir = Path.cwd().joinpath("exports")
+ if export_dir is None:
+ export_dir = Path.cwd().joinpath("exports")
+ self.export_dir = export_dir
if node.process_label != "QeAppWorkChain":
raise KeyError(str(node.node_type))
@@ -233,7 +235,7 @@ def _download_archive(self, _):
finally:
self.set_trait("_busy", False)
- id = f"dl_{self.node.uuid}"
+ link_id = f"dl_{self.node.uuid}"
display(
HTML(
@@ -241,7 +243,7 @@ def _download_archive(self, _):
diff --git a/src/aiidalab_qe/app/structure/__init__.py b/src/aiidalab_qe/app/structure/__init__.py
index 276f29c22..3a9652878 100644
--- a/src/aiidalab_qe/app/structure/__init__.py
+++ b/src/aiidalab_qe/app/structure/__init__.py
@@ -5,9 +5,13 @@
import pathlib
-import aiida
import ipywidgets as ipw
import traitlets as tl
+
+import aiida
+from aiida_quantumespresso.data.hubbard_structure import HubbardStructureData
+from aiidalab_qe.app.utils import get_entry_items
+from aiidalab_qe.common import AddingTagsEditor
from aiidalab_widgets_base import (
BasicCellEditor,
BasicStructureEditor,
@@ -19,10 +23,6 @@
WizardAppWidgetStep,
)
-from aiidalab_qe.app.utils import get_entry_items
-from aiidalab_qe.common import AddingTagsEditor
-from aiida_quantumespresso.data.hubbard_structure import HubbardStructureData
-
# The Examples list of (name, file) tuple curretly passed to
# StructureExamplesWidget.
file_path = pathlib.Path(__file__).parent
diff --git a/src/aiidalab_qe/app/submission/__init__.py b/src/aiidalab_qe/app/submission/__init__.py
index d5032e6a1..93c5e27af 100644
--- a/src/aiidalab_qe/app/submission/__init__.py
+++ b/src/aiidalab_qe/app/submission/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
"""Widgets for the submission of bands work chains.
Authors: AiiDAlab team
@@ -8,12 +7,11 @@
import ipywidgets as ipw
import traitlets as tl
+from IPython.display import display
+
from aiida import orm
from aiida.common import NotExistent
from aiida.engine import ProcessBuilderNamespace, submit
-from aiidalab_widgets_base import WizardAppWidgetStep
-from IPython.display import display
-
from aiidalab_qe.app.parameters import DEFAULT_PARAMETERS
from aiidalab_qe.app.utils import get_entry_items
from aiidalab_qe.common.setup_codes import QESetupWidget
@@ -23,6 +21,7 @@
QEAppComputationalResourcesWidget,
)
from aiidalab_qe.workflows import QeAppWorkChain
+from aiidalab_widgets_base import WizardAppWidgetStep
class SubmitQeAppWorkChainStep(ipw.VBox, WizardAppWidgetStep):
@@ -138,7 +137,8 @@ def __init__(self, qe_auto_setup=True, **kwargs):
self.process_label,
self.process_description,
self.submit_button,
- ]
+ ],
+ **kwargs,
)
# set default codes
self.set_selected_codes(DEFAULT_PARAMETERS["codes"])
@@ -148,7 +148,7 @@ def _observe_submission_blockers(self, _change):
"""Observe the submission blockers and update the message area."""
blockers = self.internal_submission_blockers + self.external_submission_blockers
if any(blockers):
- fmt_list = "\n".join((f"{item}" for item in sorted(blockers)))
+ fmt_list = "\n".join(f"{item}" for item in sorted(blockers))
self._submission_blocker_messages.value = f"""
The submission is blocked, due to the following reason(s):
@@ -379,7 +379,7 @@ def _update_process_label(self) -> dict:
else:
properties_info = f", properties on {', '.join(properties)}"
- label = "{} {} {}".format(formula, relax_info, properties_info)
+ label = f"{formula} {relax_info} {properties_info}"
self.process_label.value = label
def _create_builder(self) -> ProcessBuilderNamespace:
diff --git a/src/aiidalab_qe/app/utils/search_jobs.py b/src/aiidalab_qe/app/utils/search_jobs.py
index bf3d81f84..d13271010 100644
--- a/src/aiidalab_qe/app/utils/search_jobs.py
+++ b/src/aiidalab_qe/app/utils/search_jobs.py
@@ -1,8 +1,9 @@
import ipywidgets as ipw
import pandas as pd
+from IPython.display import display
+
from aiida.orm import QueryBuilder
from aiidalab_qe.workflows import QeAppWorkChain
-from IPython.display import display
class QueryInterface:
diff --git a/src/aiidalab_qe/common/bandpdoswidget.py b/src/aiidalab_qe/common/bandpdoswidget.py
index 0550c93a1..d8494577e 100644
--- a/src/aiidalab_qe/common/bandpdoswidget.py
+++ b/src/aiidalab_qe/common/bandpdoswidget.py
@@ -1,14 +1,15 @@
import base64
import json
+import re
import ipywidgets as ipw
import numpy as np
import plotly.graph_objects as go
-from aiida.orm import ProjectionData
-from aiidalab_widgets_base.utils import string_range_to_list, StatusHTML
from IPython.display import clear_output, display
from plotly.subplots import make_subplots
-import re
+
+from aiida.orm import ProjectionData
+from aiidalab_widgets_base.utils import StatusHTML, string_range_to_list
class BandPdosPlotly:
@@ -110,7 +111,7 @@ def _band_yaxis(self):
return None
bandyaxis = go.layout.YAxis(
- title=dict(text="Electronic Bands (eV)", standoff=1),
+ title={"text": "Electronic Bands (eV)", "standoff": 1},
side="left",
showgrid=True,
showline=True,
@@ -185,7 +186,7 @@ def _get_bandspdos_plot(self):
for label in band_labels[1]:
fig.add_vline(
x=label,
- line=dict(color=self.SETTINGS["vertical_linecolor"], width=1),
+ line={"color": self.SETTINGS["vertical_linecolor"], "width": 1},
)
if self.project_bands:
@@ -196,9 +197,11 @@ def _get_bandspdos_plot(self):
if self.plot_type == "pdos":
fig.add_vline(
x=0,
- line=dict(
- color=self.SETTINGS["vertical_linecolor"], width=1, dash="dot"
- ),
+ line={
+ "color": self.SETTINGS["vertical_linecolor"],
+ "width": 1,
+ "dash": "dot",
+ },
)
if self.plot_type == "combined":
@@ -274,11 +277,11 @@ def _add_band_traces(self, fig):
x=x_bands_comb,
y=y_bands_comb - fermi_energy,
mode="lines",
- line=dict(
- color=colors[(spin_polarized, spin)],
- shape="spline",
- smoothing=1.3,
- ),
+ line={
+ "color": colors[(spin_polarized, spin)],
+ "shape": "spline",
+ "smoothing": 1.3,
+ },
showlegend=False,
)
)
@@ -319,7 +322,11 @@ def _add_pdos_traces(self, fig):
y=y_data,
fill=fill,
name=trace["label"],
- line=dict(color=trace["borderColor"], shape="spline", smoothing=1.0),
+ line={
+ "color": trace["borderColor"],
+ "shape": "spline",
+ "smoothing": 1.0,
+ },
legendgroup=trace["label"],
)
@@ -350,7 +357,7 @@ def _add_projection_traces(self, fig):
fill="toself",
legendgroup=proj_bands["label"],
mode="lines",
- line=dict(width=0, color=proj_bands["color"]),
+ line={"width": 0, "color": proj_bands["color"]},
name=proj_bands["label"],
# If PDOS is present, use those legend entries
showlegend=True if self.plot_type == "bands" else False,
@@ -363,7 +370,7 @@ def _customize_combined_layout(self, fig):
self._customize_layout(fig, self._bands_xaxis, self._bands_yaxis)
self._customize_layout(fig, self._pdos_xaxis, self._pdos_yaxis, col=2)
fig.update_layout(
- legend=dict(xanchor="left", x=1.06),
+ legend={"xanchor": "left", "x": 1.06},
height=self.SETTINGS["combined_plot_height"],
width=self.SETTINGS["combined_plot_width"],
plot_bgcolor="white",
@@ -374,7 +381,11 @@ def _customize_layout(self, fig, xaxis, yaxis, row=1, col=1):
fig.update_yaxes(patch=yaxis, row=row, col=col, showticklabels=True)
fig.add_hline(
y=0,
- line=dict(color=self.SETTINGS["horizontal_linecolor"], width=1, dash="dot"),
+ line={
+ "color": self.SETTINGS["horizontal_linecolor"],
+ "width": 1,
+ "dash": "dot",
+ },
row=row,
col=col,
)
@@ -543,14 +554,14 @@ def _download(payload, filename):
from IPython.display import Javascript
javas = Javascript(
- """
+ f"""
var link = document.createElement('a');
link.href = 'data:text/json;charset=utf-8;base64,{payload}'
link.download = "{filename}"
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
- """.format(payload=payload, filename=filename)
+ """
)
display(javas)
@@ -903,13 +914,9 @@ def _curate_orbitals(orbital):
qn_j = orbital_data["total_angular_momentum"]
qn_l = orbital_data["angular_momentum"]
qn_m_j = orbital_data["magnetic_number"]
- orbital_name = "j {j} l {l} m_j{m_j}".format(j=qn_j, l=qn_l, m_j=qn_m_j)
- orbital_name_plotly = "j={j}
l={l} m
j={m_j}".format(
- j=HTML_TAGS.get(qn_j, qn_j),
- l=qn_l,
- m_j=HTML_TAGS.get(qn_m_j, qn_m_j),
- )
- orbital_angular_momentum = "l {l} ".format(l=qn_l)
+ orbital_name = f"j {qn_j} l {qn_l} m_j{qn_m_j}"
+ orbital_name_plotly = f"j={HTML_TAGS.get(qn_j, qn_j)}
l={qn_l} m
j={HTML_TAGS.get(qn_m_j, qn_m_j)}"
+ orbital_angular_momentum = f"l {qn_l} "
return orbital_name_plotly, orbital_angular_momentum, kind_name, atom_position
@@ -982,7 +989,7 @@ def _projections_curated_options(
curated_proj = []
for label, (energy, proj_pdos) in _proj_pdos.items():
- label += SPIN_LABELS[spin_type]
+ label += SPIN_LABELS[spin_type] # noqa: PLW2901
if projections_pdos == "pdos":
orbital_proj_pdos = {
"label": label,
@@ -1054,4 +1061,4 @@ def cmap(label: str) -> str:
ascn = sum([ord(c) for c in label])
random.seed(ascn)
- return "#%06x" % random.randint(0, 0xFFFFFF)
+ return f"#{random.randint(0, 0xFFFFFF):06x}"
diff --git a/src/aiidalab_qe/common/node_view.py b/src/aiidalab_qe/common/node_view.py
index 764652ef9..3b8d49661 100644
--- a/src/aiidalab_qe/common/node_view.py
+++ b/src/aiidalab_qe/common/node_view.py
@@ -6,9 +6,10 @@
import ipywidgets as ipw
import nglview
import traitlets as tl
+from ase import Atoms
+
from aiida import orm
from aiidalab_widgets_base import register_viewer_widget
-from ase import Atoms
from .widgets import CalcJobOutputFollower, LogOutputWidget
@@ -29,10 +30,10 @@ def __init__(self, structure, *args, **kwargs):
self.structure = structure
super().__init__(
+ *args,
children=[
self._viewer,
],
- *args,
**kwargs,
)
@@ -45,7 +46,7 @@ def _default_supercell(self):
return [1, 1, 1]
@tl.validate("structure")
- def _valid_structure(self, change): # pylint: disable=no-self-use
+ def _valid_structure(self, change):
"""Update structure."""
structure = change["value"]
@@ -74,9 +75,9 @@ def _update_displayed_structure(self, change):
def _update_structure_viewer(self, change):
"""Update the view if displayed_structure trait was modified."""
with self.hold_trait_notifications():
- for comp_id in self._viewer._ngl_component_ids: # pylint: disable=protected-access
+ for comp_id in self._viewer._ngl_component_ids:
self._viewer.remove_component(comp_id)
- self.selection = list()
+ self.selection = []
if change["new"] is not None:
self._viewer.add_component(nglview.ASEStructure(change["new"]))
self._viewer.clear()
@@ -87,7 +88,7 @@ def _update_structure_viewer(self, change):
class VBoxWithCaption(ipw.VBox):
def __init__(self, caption, body, *args, **kwargs):
- super().__init__(children=[ipw.HTML(caption), body], *args, **kwargs)
+ super().__init__(*args, children=[ipw.HTML(caption), body], **kwargs)
@register_viewer_widget("process.calculation.calcjob.CalcJobNode.")
diff --git a/src/aiidalab_qe/common/panel.py b/src/aiidalab_qe/common/panel.py
index bd6fdcfdc..40a7f98a8 100644
--- a/src/aiidalab_qe/common/panel.py
+++ b/src/aiidalab_qe/common/panel.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
"""Class to .
Authors:
diff --git a/src/aiidalab_qe/common/process.py b/src/aiidalab_qe/common/process.py
index b1c2ea34a..799de74bc 100644
--- a/src/aiidalab_qe/common/process.py
+++ b/src/aiidalab_qe/common/process.py
@@ -4,6 +4,7 @@
import ipywidgets as ipw
import traitlets as tl
+
from aiida.tools.query.calculation import CalculationQueryBuilder
@@ -87,9 +88,9 @@ def __init__(self, process_label, **kwargs):
self.refresh_work_chains()
# the following is needed to disable the button.
- def parse_extra_info(self, pk: int) -> dict:
+ def parse_extra_info(self, _pk: int) -> dict:
"""Parse extra information about the work chain."""
- return dict()
+ return {}
def find_work_chains(self):
builder = CalculationQueryBuilder()
diff --git a/src/aiidalab_qe/common/setup_codes.py b/src/aiidalab_qe/common/setup_codes.py
index 11ee58d1a..0da53b237 100644
--- a/src/aiidalab_qe/common/setup_codes.py
+++ b/src/aiidalab_qe/common/setup_codes.py
@@ -5,10 +5,10 @@
import ipywidgets as ipw
import traitlets
-from aiida.common.exceptions import NotExistent
-from aiida.orm import load_code
from filelock import FileLock, Timeout
+from aiida.common.exceptions import NotExistent
+from aiida.orm import load_code
from aiidalab_qe.common.widgets import ProgressBar
__all__ = [
@@ -99,11 +99,11 @@ def _generate_header_to_setup_code():
def _generate_string_to_setup_code(code_name, computer_name="localhost"):
"""Generate the Python string to setup an AiiDA code for a given computer.
+
Tries to load an existing code and if not existent,
generates Python code to create and store a new code setup."""
try:
load_code(f"{code_name}-{QE_VERSION}@{computer_name}")
- return ""
except NotExistent:
label = f"{code_name}-{QE_VERSION}"
description = f"{code_name}.x ({QE_VERSION}) setup by AiiDAlab."
@@ -130,6 +130,9 @@ def _generate_string_to_setup_code(code_name, computer_name="localhost"):
prepend_text,
)
return python_code
+ else:
+ # the code already exists
+ return ""
def setup_codes():
diff --git a/src/aiidalab_qe/common/setup_pseudos.py b/src/aiidalab_qe/common/setup_pseudos.py
index f367dccfd..4285456e4 100644
--- a/src/aiidalab_qe/common/setup_pseudos.py
+++ b/src/aiidalab_qe/common/setup_pseudos.py
@@ -1,19 +1,18 @@
-# -*- coding: utf-8 -*-
from __future__ import annotations
import os
+from collections.abc import Iterable
from dataclasses import dataclass, field
from pathlib import Path
from subprocess import run
from threading import Thread
-from typing import Iterable
import ipywidgets as ipw
import traitlets
-from aiida.orm import QueryBuilder
from aiida_pseudo.groups.family import PseudoPotentialFamily
from filelock import FileLock, Timeout
+from aiida.orm import QueryBuilder
from aiidalab_qe.common.widgets import ProgressBar
SSSP_VERSION = "1.3"
@@ -225,7 +224,7 @@ def install(
if len(pseudos_to_install()) > 0:
raise RuntimeError(
"Installation process did not finish in the expected time."
- )
+ ) from None
class PseudosInstallWidget(ProgressBar):
@@ -287,7 +286,7 @@ def _default_error(self):
@traitlets.observe("busy")
@traitlets.observe("error")
@traitlets.observe("installed")
- def _update(self, change):
+ def _update(self, _change):
with self.hold_trait_notifications():
if self.hide_by_default:
self.layout.visibility = (
diff --git a/src/aiidalab_qe/common/widgets.py b/src/aiidalab_qe/common/widgets.py
index b15165883..0d07650a2 100644
--- a/src/aiidalab_qe/common/widgets.py
+++ b/src/aiidalab_qe/common/widgets.py
@@ -15,19 +15,18 @@
import ipywidgets as ipw
import numpy as np
import traitlets
-from aiida.orm import CalcJobNode
+from IPython.display import HTML, Javascript, clear_output, display
+from pymatgen.core.periodic_table import Element
+
+from aiida.orm import CalcJobNode, load_code, load_node
from aiida.orm import Data as orm_Data
-from aiida.orm import load_code, load_node
+from aiida_quantumespresso.data.hubbard_structure import HubbardStructureData
from aiidalab_widgets_base import ComputationalResourcesWidget
from aiidalab_widgets_base.utils import (
StatusHTML,
list_to_string_range,
string_range_to_list,
)
-from IPython.display import HTML, Javascript, clear_output, display
-from pymatgen.core.periodic_table import Element
-from aiida_quantumespresso.data.hubbard_structure import HubbardStructureData
-
__all__ = [
"CalcJobOutputFollower",
@@ -43,7 +42,7 @@ class RollingOutput(ipw.VBox):
value = traitlets.Unicode()
auto_scroll = traitlets.Bool()
- def __init__(self, num_min_lines=10, max_output_height="200px", **kwargs):
+ def __init__(self, num_min_lines=10, max_output_height="200px", **kwargs): # noqa: ARG002
self._num_min_lines = num_min_lines
self._output = ipw.HTML(layout=ipw.Layout(min_width="50em"))
self._refresh_output()
@@ -121,14 +120,14 @@ def __on_click(self, _):
digest = hashlib.md5(self.payload).hexdigest() # bypass browser cache
payload = base64.b64encode(self.payload).decode()
- id = f"dl_{digest}"
+ link_id = f"dl_{digest}"
display(
HTML(
f"""
-
+
-
-
- """
- )
+ return
+
+ contents: bytes = self.contents().encode("utf-8")
+ b64 = base64.b64encode(contents)
+ payload = b64.decode()
+ digest = hashlib.md5(contents).hexdigest() # bypass browser cache
+ link_id = f"dl_{digest}"
+
+ display(
+ HTML(
+ f"""
+
+
+
+
+
+
+
+ """
)
+ )
def write_csv(dataset):
@@ -276,9 +276,9 @@ def _update_view(self):
Select spectrum to plot
"""
)
final_spectra, equivalent_sites_data = export_xas_data(self.outputs)
- xas_wc = [
+ xas_wc = next(
n for n in self.node.called if n.process_label == "XspectraCrystalWorkChain"
- ][0]
+ )
core_wcs = {
n.get_metadata_inputs()["metadata"]["call_link_label"]: n
for n in xas_wc.called
@@ -310,7 +310,7 @@ def _update_view(self):
min=0.0,
max=5,
step=0.1,
- description="$\Gamma_{hole}$", # noqa: W605
+ description="$\Gamma_{hole}$",
disabled=False,
continuous_update=False,
orientation="horizontal",
@@ -323,7 +323,7 @@ def _update_view(self):
max=10,
step=0.5,
continuous_update=False,
- description="$\Gamma_{max}$", # noqa: W605
+ description="$\Gamma_{max}$",
disabled=True,
orientation="horizontal",
readout=True,
@@ -350,7 +350,7 @@ def _update_view(self):
# # init figure
g = go.FigureWidget(
layout=go.Layout(
- title=dict(text="XAS"),
+ title={"text": "XAS"},
barmode="overlay",
)
)
@@ -394,7 +394,7 @@ def _update_download_selection(dataset, element):
download_data.contents = lambda: write_csv(dataset)
download_data.filename = f"{element}_XAS_Spectra.csv"
- def response(change):
+ def response(_change):
chosen_spectrum = spectrum_select.value
chosen_spectrum_label = f"{chosen_spectrum}_xas"
element_sites = [
diff --git a/src/aiidalab_qe/plugins/xas/setting.py b/src/aiidalab_qe/plugins/xas/setting.py
index 2d9b52535..165143295 100644
--- a/src/aiidalab_qe/plugins/xas/setting.py
+++ b/src/aiidalab_qe/plugins/xas/setting.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
"""Panel for XAS plugin."""
import os
@@ -10,8 +9,8 @@
import requests
import traitlets as tl
import yaml
-from aiida import orm
+from aiida import orm
from aiidalab_qe.common.panel import Panel
from aiidalab_qe.plugins import xas as xas_folder
@@ -46,10 +45,10 @@ def _load_or_import_nodes_from_filenames(in_dict, path, core_wfc_data=False):
def _download_extract_pseudo_archive(func):
- dir = f"{head_path}/{dir_header}/{func}"
+ target_dir = f"{head_path}/{dir_header}/{func}"
archive_filename = f"{func}_ch_pseudos.tgz"
remote_archive_filename = f"{base_url}/{func}/{archive_filename}"
- local_archive_filename = f"{dir}/{archive_filename}"
+ local_archive_filename = f"{target_dir}/{archive_filename}"
env = os.environ.copy()
env["PATH"] = f"{env['PATH']}:{Path.home() / '.local' / 'lib'}"
@@ -62,16 +61,16 @@ def _download_extract_pseudo_archive(func):
response.close()
with tarfile.open(local_archive_filename, "r:gz") as tarfil:
- tarfil.extractall(dir)
+ tarfil.extractall(target_dir)
url = f"{base_url}"
for func in functionals:
- dir = f"{head_path}/{dir_header}/{func}"
- os.makedirs(dir, exist_ok=True)
+ target_dir = f"{head_path}/{dir_header}/{func}"
+ os.makedirs(target_dir, exist_ok=True)
archive_filename = f"{func}_ch_pseudos.tgz"
archive_found = False
- for entry in os.listdir(dir):
+ for entry in os.listdir(target_dir):
if entry == archive_filename:
archive_found = True
if not archive_found:
@@ -273,7 +272,7 @@ def _update_element_select_panel(self):
]
ch_pseudos = self.core_hole_pseudos
structure = self.input_structure
- available_elements = [k for k in ch_pseudos]
+ available_elements = list(ch_pseudos)
elements_to_select = sorted(
[
kind.symbol
diff --git a/src/aiidalab_qe/plugins/xas/workchain.py b/src/aiidalab_qe/plugins/xas/workchain.py
index d5b3cf000..07f51bfda 100644
--- a/src/aiidalab_qe/plugins/xas/workchain.py
+++ b/src/aiidalab_qe/plugins/xas/workchain.py
@@ -1,12 +1,12 @@
from importlib import resources
import yaml
+
from aiida import orm
from aiida.plugins import WorkflowFactory
from aiida_quantumespresso.common.types import ElectronicType, SpinType
-from aiidalab_qe.plugins.utils import set_component_resources
-
from aiidalab_qe.plugins import xas as xas_folder
+from aiidalab_qe.plugins.utils import set_component_resources
XspectraCrystalWorkChain = WorkflowFactory("quantumespresso.xspectra.crystal")
PSEUDO_TOC = yaml.safe_load(resources.read_text(xas_folder, "pseudo_toc.yaml"))
diff --git a/src/aiidalab_qe/plugins/xps/result.py b/src/aiidalab_qe/plugins/xps/result.py
index 3c0016c99..57789f555 100644
--- a/src/aiidalab_qe/plugins/xps/result.py
+++ b/src/aiidalab_qe/plugins/xps/result.py
@@ -29,7 +29,7 @@ def export_xps_data(outputs):
def xps_spectra_broadening(
- points, equivalent_sites_data, gamma=0.3, sigma=0.3, label="", intensity=1.0
+ points, equivalent_sites_data, gamma=0.3, sigma=0.3, _label="", intensity=1.0
):
"""Broadening the XPS spectra with Voigt function and return the spectra data"""
@@ -169,7 +169,7 @@ def _update_view(self):
# init figure
self.g = go.FigureWidget(
layout=go.Layout(
- title=dict(text="XPS"),
+ title={"text": "XPS"},
barmode="overlay",
)
)
@@ -189,7 +189,7 @@ def _update_view(self):
x=d[0], y=d[1], fill="tozeroy", name=site.replace("_", " ")
)
- def response(change):
+ def response(_change):
data = []
if spectra_type.value == "chemical_shift":
points = chemical_shifts
diff --git a/src/aiidalab_qe/plugins/xps/setting.py b/src/aiidalab_qe/plugins/xps/setting.py
index 0f2077244..ecb1b4c9e 100644
--- a/src/aiidalab_qe/plugins/xps/setting.py
+++ b/src/aiidalab_qe/plugins/xps/setting.py
@@ -1,10 +1,9 @@
-# -*- coding: utf-8 -*-
"""Panel for XPS plugin."""
import ipywidgets as ipw
import traitlets as tl
-from aiida.orm import Group, QueryBuilder, StructureData
+from aiida.orm import Group, QueryBuilder, StructureData
from aiidalab_qe.common.panel import Panel
base_url = "https://github.com/superstar54/xps-data/raw/main/pseudo_demo/"
diff --git a/src/aiidalab_qe/plugins/xps/workchain.py b/src/aiidalab_qe/plugins/xps/workchain.py
index f707ebd5e..f0a63a2ac 100644
--- a/src/aiidalab_qe/plugins/xps/workchain.py
+++ b/src/aiidalab_qe/plugins/xps/workchain.py
@@ -37,14 +37,14 @@ def get_builder(codes, structure, parameters, **kwargs):
for label in core_level_list:
element = label.split("_")[0]
pseudos[element] = {
- "core_hole": [
+ "core_hole": next(
pseudo for pseudo in pseudo_group.nodes if pseudo.label == label
- ][0],
- "gipaw": [
+ ),
+ "gipaw": next(
pseudo
for pseudo in pseudo_group.nodes
if pseudo.label == f"{element}_gs"
- ][0],
+ ),
}
correction_energies[element] = (
all_correction_energies[label]["core"]
diff --git a/src/aiidalab_qe/version.py b/src/aiidalab_qe/version.py
index 6d4128302..5ceb56539 100644
--- a/src/aiidalab_qe/version.py
+++ b/src/aiidalab_qe/version.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
"""This module contains project version information for both the app and the workflow."""
diff --git a/src/aiidalab_qe/workflows/__init__.py b/src/aiidalab_qe/workflows/__init__.py
index 04ebc0486..6fc798afc 100644
--- a/src/aiidalab_qe/workflows/__init__.py
+++ b/src/aiidalab_qe/workflows/__init__.py
@@ -1,10 +1,9 @@
# AiiDA imports.
+# AiiDA Quantum ESPRESSO plugin inputs.
from aiida import orm
from aiida.common import AttributeDict
from aiida.engine import ToContext, WorkChain, if_
from aiida.plugins import DataFactory
-
-# AiiDA Quantum ESPRESSO plugin inputs.
from aiida_quantumespresso.common.types import ElectronicType, RelaxType, SpinType
from aiida_quantumespresso.data.hubbard_structure import HubbardStructureData
from aiida_quantumespresso.utils.mapping import prepare_process_inputs
diff --git a/start.py b/start.py
index a43a898df..7d25ecf3e 100644
--- a/start.py
+++ b/start.py
@@ -1,7 +1,7 @@
import ipywidgets as ipw
-def get_start_widget(appbase, jupbase, notebase):
+def get_start_widget(appbase, jupbase, notebase): # noqa: ARG001
return ipw.HTML(
f"""
diff --git a/tests/configuration/test_advanced.py b/tests/configuration/test_advanced.py
index 4dee1caa9..800436bd7 100644
--- a/tests/configuration/test_advanced.py
+++ b/tests/configuration/test_advanced.py
@@ -120,10 +120,10 @@ def test_advanced_tot_charge_settings():
def test_advanced_kpoints_mesh():
"""Test Mesh Grid HTML widget."""
- from aiida import orm
-
from aiidalab_qe.app.configuration.advanced import AdvancedSettings
+ from aiida import orm
+
w = AdvancedSettings()
# Create a StructureData for AdvancedSettings (Silicon)
diff --git a/tests/conftest.py b/tests/conftest.py
index 100ebdcfd..b7c83a187 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -5,10 +5,10 @@
import tempfile
import pytest
-from aiida import orm
-
from aiidalab_qe.common.setup_pseudos import SSSP_VERSION
+from aiida import orm
+
pytest_plugins = ["aiida.manage.tests.pytest_fixtures"]
@@ -107,10 +107,6 @@ def _generate_xy_data(xvals=None, yvals=None, xlabel=None, ylabel=None):
"""
from aiida.orm import XyData
- xvals = xvals
- yvals = yvals
- xlabel = xlabel
- ylabel = ylabel
xunits = "n/a"
yunits = ["n/a"] * len(ylabel)
@@ -130,6 +126,7 @@ def generate_bands_data():
def _generate_bands_data():
"""Return a `BandsData` instance with some basic `kpoints` and `bands` arrays."""
import numpy as np
+
from aiida.plugins import DataFactory
BandsData = DataFactory("core.array.bands")
@@ -153,6 +150,7 @@ def generate_projection_data(generate_bands_data):
def _generate_projection_data():
"""Return an ``ProjectionData`` node."""
import numpy as np
+
from aiida.plugins import DataFactory, OrbitalFactory
ProjectionData = DataFactory("core.array.projection")
@@ -197,33 +195,34 @@ def sssp(aiida_profile, generate_upf_data):
cutoffs = {}
stringency = "standard"
- with tempfile.TemporaryDirectory() as dirpath:
+ actinides = (
+ "Ac",
+ "Th",
+ "Pa",
+ "U",
+ "Np",
+ "Pu",
+ "Am",
+ "Cm",
+ "Bk",
+ "Cf",
+ "Es",
+ "Fm",
+ "Md",
+ "No",
+ "Lr",
+ )
+
+ with tempfile.TemporaryDirectory() as d:
+ dirpath = pathlib.Path(d)
+
for values in elements.values():
element = values["symbol"]
- actinides = (
- "Ac",
- "Th",
- "Pa",
- "U",
- "Np",
- "Pu",
- "Am",
- "Cm",
- "Bk",
- "Cf",
- "Es",
- "Fm",
- "Md",
- "No",
- "Lr",
- )
-
if element in actinides:
continue
upf = generate_upf_data(element)
- dirpath = pathlib.Path(dirpath)
filename = dirpath / f"{element}.upf"
with open(filename, "w+b") as handle:
@@ -443,6 +442,7 @@ def generate_pdos_workchain(
def _generate_pdos_workchain(structure, spin_type="none"):
import numpy as np
+
from aiida import engine
from aiida.orm import Dict, FolderData, RemoteData
from aiida_quantumespresso.workflows.pdos import PdosWorkChain
@@ -630,12 +630,12 @@ def _generate_qeapp_workchain(
):
from copy import deepcopy
- from aiida.orm.utils.serialize import serialize
-
from aiidalab_qe.app.configuration import ConfigureQeAppWorkChainStep
from aiidalab_qe.app.submission import SubmitQeAppWorkChainStep
from aiidalab_qe.workflows import QeAppWorkChain
+ from aiida.orm.utils.serialize import serialize
+
# Step 1: select structure from example
s1 = app.structure_step
if structure is None:
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 53c334307..91bb0668f 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -1,9 +1,9 @@
import time
-import aiida
+import aiidalab_qe.__main__ as cli
from click.testing import CliRunner, Result
-import aiidalab_qe.__main__ as cli
+import aiida
# To learn more about testing click applications, see: https://click.palletsprojects.com/en/8.1.x/testing/
diff --git a/tests/test_plugins_bands.py b/tests/test_plugins_bands.py
index 27533eec0..b3c2a9dc8 100644
--- a/tests/test_plugins_bands.py
+++ b/tests/test_plugins_bands.py
@@ -3,8 +3,8 @@
@pytest.mark.usefixtures("sssp")
def test_result(generate_qeapp_workchain):
- from aiidalab_qe.common.bandpdoswidget import BandPdosWidget
import plotly.graph_objects as go
+ from aiidalab_qe.common.bandpdoswidget import BandPdosWidget
from aiidalab_qe.plugins.bands.result import Result
wkchain = generate_qeapp_workchain()
diff --git a/tests/test_plugins_electronic_structure.py b/tests/test_plugins_electronic_structure.py
index c2c0203d3..271adfd1b 100644
--- a/tests/test_plugins_electronic_structure.py
+++ b/tests/test_plugins_electronic_structure.py
@@ -1,12 +1,12 @@
def test_electronic_structure(generate_qeapp_workchain):
"""Test the electronic structure tab."""
- from aiida import engine
-
+ import plotly.graph_objects as go
from aiidalab_qe.app.result.workchain_viewer import WorkChainViewer
from aiidalab_qe.common.bandpdoswidget import BandPdosWidget
- import plotly.graph_objects as go
from aiidalab_qe.plugins.electronic_structure.result import Result
+ from aiida import engine
+
wkchain = generate_qeapp_workchain()
wkchain.node.set_exit_status(0)
wkchain.node.set_process_state(engine.ProcessState.FINISHED)
@@ -14,11 +14,11 @@ def test_electronic_structure(generate_qeapp_workchain):
# find the tab with the identifier "electronic_structure"
# the built-in summary and structure tabs is not a plugin panel,
# thus don't have identifiers
- tab = [
+ tab = next(
tab
for tab in wcv.result_tabs.children
if getattr(tab, "identifier", "") == "electronic_structure"
- ][0]
+ )
# It should have one children: the _bands_plot_view
assert len(tab.children) == 1
diff --git a/tests/test_plugins_pdos.py b/tests/test_plugins_pdos.py
index 6d02a140e..426393694 100644
--- a/tests/test_plugins_pdos.py
+++ b/tests/test_plugins_pdos.py
@@ -3,8 +3,8 @@
@pytest.mark.usefixtures("sssp")
def test_result(generate_qeapp_workchain):
- from aiidalab_qe.common.bandpdoswidget import BandPdosWidget
import plotly.graph_objects as go
+ from aiidalab_qe.common.bandpdoswidget import BandPdosWidget
from aiidalab_qe.plugins.pdos.result import Result
wkchain = generate_qeapp_workchain()
diff --git a/tests/test_plugins_xps.py b/tests/test_plugins_xps.py
index 6bc0d9af3..8f15c3b80 100644
--- a/tests/test_plugins_xps.py
+++ b/tests/test_plugins_xps.py
@@ -7,6 +7,7 @@ def test_settings():
from aiidalab_qe.app.configuration import ConfigureQeAppWorkChainStep
from ase.build import molecule
+
from aiida.orm import StructureData
configure_step = ConfigureQeAppWorkChainStep()
diff --git a/tests/test_pseudo.py b/tests/test_pseudo.py
index 2412b63bd..a85c34e86 100644
--- a/tests/test_pseudo.py
+++ b/tests/test_pseudo.py
@@ -1,6 +1,4 @@
import pytest
-from aiida import orm
-
from aiidalab_qe.common.setup_pseudos import (
PSEUDODOJO_VERSION,
SSSP_VERSION,
@@ -9,6 +7,8 @@
pseudos_to_install,
)
+from aiida import orm
+
def test_setup_pseudos_cmd(tmp_path):
"""Test _construct_cmd function in setup_pseudos.py."""
@@ -96,7 +96,7 @@ def test_setup_pseudos_cmd(tmp_path):
"--pseudo-format",
"upf",
"--from-download",
- f"{str(tmp_path)}/PseudoDojo_{PSEUDODOJO_VERSION}_PBEsol_SR_standard_upf.aiida_pseudo",
+ f"{tmp_path!s}/PseudoDojo_{PSEUDODOJO_VERSION}_PBEsol_SR_standard_upf.aiida_pseudo",
]
@@ -111,7 +111,7 @@ def test_pseudos_installation():
}
# Install the pseudos
- [_ for _ in _install_pseudos(EXPECTED_PSEUDOS)]
+ list(_install_pseudos(EXPECTED_PSEUDOS))
# Two pseudos are installed
assert len(pseudos_to_install()) == 10
@@ -127,13 +127,13 @@ def test_download_and_install_pseudo_from_file(tmp_path):
}
# Download the pseudos to the tmp_path but not install
- [_ for _ in _install_pseudos(EXPECTED_PSEUDOS, download_only=True, cwd=tmp_path)]
+ list(_install_pseudos(EXPECTED_PSEUDOS, download_only=True, cwd=tmp_path))
assert len(pseudos_to_install()) == 12
assert len(list(tmp_path.iterdir())) == 2
# Install the pseudos from the tmp_path
- [_ for _ in _install_pseudos(EXPECTED_PSEUDOS, cwd=tmp_path)]
+ list(_install_pseudos(EXPECTED_PSEUDOS, cwd=tmp_path))
# Two pseudos are installed
assert len(pseudos_to_install()) == 10
diff --git a/tests/test_result.py b/tests/test_result.py
index c6e087d17..9deb51f0a 100644
--- a/tests/test_result.py
+++ b/tests/test_result.py
@@ -43,9 +43,8 @@ def test_summary_report_advanced_settings(data_regression, generate_qeapp_workch
def test_summary_view(generate_qeapp_workchain):
"""Test the report html can be properly generated."""
- from bs4 import BeautifulSoup
-
from aiidalab_qe.app.result.summary_viewer import SummaryView
+ from bs4 import BeautifulSoup
wkchain = generate_qeapp_workchain()
viewer = SummaryView(wkchain.node)
diff --git a/tests_integration/test_app.py b/tests_integration/test_app.py
index d847e7ff0..e1475282b 100755
--- a/tests_integration/test_app.py
+++ b/tests_integration/test_app.py
@@ -1,7 +1,7 @@
import time
from pathlib import Path
-import selenium.webdriver.support.expected_conditions as EC
+import selenium.webdriver.support.expected_conditions as EC # noqa: N812
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait