diff --git a/.cruft.json b/.cruft.json new file mode 100644 index 0000000..b9d3fbe --- /dev/null +++ b/.cruft.json @@ -0,0 +1,27 @@ +{ + "template": "https://github.com/FAIRmat-NFDI/cookiecutter-nomad-plugin", + "commit": "e759475d3f8905df4354ca83d8ce6cd632ffce99", + "checkout": null, + "context": { + "cookiecutter": { + "full_name": "Jose Pizarro", + "email": "jose.pizarro@physik.hu-berlin.de", + "github_username": "FAIRmat-NFDI", + "plugin_name": "nomad-parser-vasp", + "module_name": "nomad_parser_vasp", + "short_description": "A NOMAD parser plugin for VASP input/output files.", + "version": "0.1.0", + "license": "Apache Software License 2.0", + "include_schema_package": true, + "include_normalizer": false, + "include_parser": true, + "include_app": false, + "include_example_uploads": false, + "_copy_without_render": [ + "*.html" + ], + "_template": "https://github.com/FAIRmat-NFDI/cookiecutter-nomad-plugin" + } + }, + "directory": null +} diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml new file mode 100644 index 0000000..0c2b24d --- /dev/null +++ b/.github/workflows/actions.yml @@ -0,0 +1,71 @@ +name: install-and-test +on: [push] + +# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs +# `contents` is for permission to the contents of the repository. +# `pull-requests` is for permission to pull request +permissions: + contents: write + checks: write + pull-requests: write + +env: + UV_SYSTEM_PYTHON: true + +jobs: + install-and-test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python_version: ["3.9", "3.10", "3.11"] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{matrix.python_version}} + uses: actions/setup-python@v5 + with: + python-version: ${{matrix.python_version}} + - name: Install uv + run: | + curl -LsSf https://astral.sh/uv/install.sh | sh + - name: Install dependencies + run: | + pip install --upgrade pip + uv pip install -e '.[dev]' + - name: mypy + run: | + python -m mypy --ignore-missing-imports --follow-imports=silent --no-strict-optional src/nomad_parser_vasp/schema_packages src/nomad_parser_vasp/parsers tests + - name: Test with pytest + run: | + python -m pytest -sv tests + build-and-install: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: 3.11 + - name: Build the package + run: | + pip install uv + uv pip install --upgrade pip --system + uv pip install build --system + python -m build --sdist + - name: Install the package + run: | + uv pip install dist/*.tar.gz --index-url https://gitlab.mpcdf.mpg.de/api/v4/projects/2187/packages/pypi/simple --system + ruff-linting: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: chartboost/ruff-action@v1 + with: + args: "check ." + ruff-formatting: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: chartboost/ruff-action@v1 + with: + args: "format . --check --verbose" diff --git a/.github/workflows/coveralls.yml b/.github/workflows/coveralls.yml new file mode 100644 index 0000000..3698481 --- /dev/null +++ b/.github/workflows/coveralls.yml @@ -0,0 +1,44 @@ +name: Testing with coveralls Report +on: [push] + +# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs +# `contents` is for permission to the contents of the repository. +# `pull-requests` is for permission to pull request +permissions: + contents: write + checks: write + pull-requests: write + +env: + UV_SYSTEM_PYTHON: true + +jobs: + coveralls-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: 3.11 + - name: Install uv + run: | + curl -LsSf https://astral.sh/uv/install.sh | sh + - name: Install dependencies + run: | + uv pip install -e '.[dev]' + uv pip install coveralls + - name: Build coverage file + run: | + pytest --junitxml=pytest.xml --cov-report=term-missing:skip-covered --cov=src tests | tee pytest-coverage.txt + - name: Pytest coverage comment + uses: MishaKav/pytest-coverage-comment@main + with: + pytest-coverage-path: pytest-coverage.txt + junitxml-path: pytest.xml + - name: Submit to coveralls + continue-on-error: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + coveralls --service=github diff --git a/.github/workflows/mkdocs-deploy.yml b/.github/workflows/mkdocs-deploy.yml new file mode 100644 index 0000000..c46ff23 --- /dev/null +++ b/.github/workflows/mkdocs-deploy.yml @@ -0,0 +1,24 @@ +name: Deploy MkDocs Site + +on: + push: + branches: + - main # Triggers deployment on push to the main branch + +permissions: + contents: write + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Deploy docs + uses: mhausenblas/mkdocs-deploy-gh-pages@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CONFIG_FILE: mkdocs.yml + REQUIREMENTS: requirements_docs.txt diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..b4dca46 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,43 @@ +# This workflow will upload a Python Package using Twine when a release is created +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Build and Publish Python Package + +on: + release: + types: [published] + +permissions: + contents: read + +env: + UV_SYSTEM_PYTHON: true + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: 3.11 + - name: Install uv + run: | + curl -LsSf https://astral.sh/uv/install.sh | sh + - name: Install dependencies + run: | + pip install --upgrade pip + uv pip install build + - name: Build package + run: python -m build + - name: Publish package to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b1619d4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,130 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ +.pyenv + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0c8648f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,21 @@ +{ + "editor.rulers": [ + 90 + ], + "editor.renderWhitespace": "all", + "editor.tabSize": 4, + "files.trimTrailingWhitespace": true, + "[python]": { + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll": "explicit", + "source.organizeImports": "explicit" + }, + "editor.defaultFormatter": "charliermarsh.ruff" + }, + "python.testing.pytestArgs": [ + "tests" + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true +} diff --git a/LICENSE b/LICENSE index 261eeb9..427417b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,4 @@ + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -178,7 +179,7 @@ APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" + boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a @@ -186,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index fcf513e..a2befef 100644 --- a/README.md +++ b/README.md @@ -1,84 +1,173 @@ -# nomad-plugin-template -A template repository for creating a repository with a NOMAD plugin package. +[![NOMAD](https://img.shields.io/badge/Open%20NOMAD-lightgray?logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI3LjUuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAxNTAwIDE1MDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDE1MDAgMTUwMDsiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoJLnN0MHtmaWxsOiMxOTJFODY7c3Ryb2tlOiMxOTJFODY7c3Ryb2tlLXdpZHRoOjE0MS4zMjI3O3N0cm9rZS1taXRlcmxpbWl0OjEwO30KCS5zdDF7ZmlsbDojMkE0Q0RGO3N0cm9rZTojMkE0Q0RGO3N0cm9rZS13aWR0aDoxNDEuMzIyNztzdHJva2UtbWl0ZXJsaW1pdDoxMDt9Cjwvc3R5bGU+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xMTM2LjQsNjM2LjVjMTUwLjgsMCwyNzMuMS0xMjEuOSwyNzMuMS0yNzIuMlMxMjg3LjIsOTIuMSwxMTM2LjQsOTIuMWMtMTUwLjgsMC0yNzMuMSwxMjEuOS0yNzMuMSwyNzIuMgoJUzk4NS42LDYzNi41LDExMzYuNCw2MzYuNXoiLz4KPHBhdGggY2xhc3M9InN0MSIgZD0iTTEzMjksOTQ2Yy0xMDYuNC0xMDYtMjc4LjgtMTA2LTM4Ni4xLDBjLTk5LjYsOTkuMy0yNTguNywxMDYtMzY1LjEsMTguMWMtNi43LTcuNi0xMy40LTE2LjItMjEuMS0yMy45CgljLTEwNi40LTEwNi0xMDYuNC0yNzgsMC0zODQuOWMxMDYuNC0xMDYsMTA2LjQtMjc4LDAtMzg0LjlzLTI3OC44LTEwNi0zODYuMSwwYy0xMDcuMywxMDYtMTA2LjQsMjc4LDAsMzg0LjkKCWMxMDYuNCwxMDYsMTA2LjQsMjc4LDAsMzg0LjljLTYzLjIsNjMtODkuMSwxNTAtNzYuNywyMzIuMWM3LjcsNTcuMywzMy41LDExMy43LDc3LjYsMTU3LjZjMTA2LjQsMTA2LDI3OC44LDEwNiwzODYuMSwwCgljMTA2LjQtMTA2LDI3OC44LTEwNiwzODYuMSwwYzEwNi40LDEwNiwyNzguOCwxMDYsMzg2LjEsMEMxNDM1LjQsMTIyNCwxNDM1LjQsMTA1MiwxMzI5LDk0NnoiLz4KPC9zdmc+Cg==)](https://nomad-lab.eu/prod/v1/staging/gui/) +![](https://coveralls.io/repos/github/nomad-coe/nomad-parser-vasp/badge.svg?branch=develop) +![](https://img.shields.io/pypi/v/nomad-parser-vasp) +![](https://img.shields.io/pypi/pyversions/nomad-parser-vasp) +# `nomad-parser-vasp` + +This is a plugin for [NOMAD](https://nomad-lab.eu) which contains the parser and extended sections definitions for [VASP](https://wannier.org/) input/output files. The parser uses the [`nomad-simulations`](https://github.com/nomad-coe/nomad-simulations) schema as the basis of the schema. ## Getting started -1. Click on the `Use this template` button and create a new plugin repository. The form will ask you to fill out the name for the new plugin repository. + + +## Development + +If you want to develop locally this package, clone the project and in the workspace folder, create a virtual environment (you can use Python 3.9, 3.10, or 3.11): +```sh +git clone https://github.com/nomad-coe/nomad-parser-vasp.git +cd nomad-parser-vasp +python3.11 -m venv .pyenv +. .pyenv/bin/activate +``` + +Make sure to have `pip` upgraded: +```sh +pip install --upgrade pip +``` + +We recommend installing `uv` for fast pip installation of the packages: +```sh +pip install uv +``` + +Install the `nomad-lab` package: +```sh +uv pip install '.[dev]' --index-url https://gitlab.mpcdf.mpg.de/api/v4/projects/2187/packages/pypi/simple +``` + +**Note!** +Until we have an official pypi NOMAD release with the plugins functionality make +sure to include NOMAD's internal package registry (via `--index-url` in the above command). + +The plugin is still under development. If you would like to contribute, install the package in editable mode (with the added `-e` flag): +```sh +uv pip install -e '.[dev]' --index-url https://gitlab.mpcdf.mpg.de/api/v4/projects/2187/packages/pypi/simple +``` + + +### Run the tests + +You can run locally the tests: +```sh +python -m pytest -sv tests +``` + +where the `-s` and `-v` options toggle the output verbosity. -2. In the newly created repository, start a new Github Codespace and generate the plugin structure. +Our CI/CD pipeline produces a more comprehensive test report using the `pytest-cov` package. You can generate a local coverage report: +```sh +uv pip install pytest-cov +python -m pytest --cov=src tests +``` -Run the following command to create a new NOMAD plugin project using cookiecutter-nomad-plugin: +### Run linting and auto-formatting +We use [Ruff](https://docs.astral.sh/ruff/) for linting and formatting the code. Ruff auto-formatting is also a part of the GitHub workflow actions. You can run locally: ```sh -cruft create https://github.com/FAIRmat-NFDI/cookiecutter-nomad-plugin +ruff check . +ruff format . --check ``` -Cookiecutter prompts you for information regarding your plugin: - -```no-highlight -full_name [John Doe]: Citizen Kane -email [john.doe@physik.hu-berlin.de]: citizen@kane.de -github_username [foo]: kane -plugin_name [foobar]: awesome-tools -module_name [awesome_tools]: awesome_tools -short_description [NOMAD example template]: An awesome plugin for NOMAD -version [0.1.0]: -Select license: -1 - MIT -2 - BSD-3 -3 - GNU GPL v3.0+ -Choose from 1, 2, 3 [1]: 2 -include_schema_package [y/n] (y): y -include_normalizer [y/n] (y): n -include_parser [y/n] (y): y -include_app [y/n] (y): n - -INFO:post_gen_project:Initializing python for package - src -.. -INFO:post_gen_project:Remove temporary folder: licenses -INFO:post_gen_project:Remove temporary folder: macros -INFO:post_gen_project:Remove temporary folder: py_sources + +### Debugging + +For interactive debugging of the tests, use `pytest` with the `--pdb` flag. We recommend using an IDE for debugging, e.g., _VSCode_. If that is the case, add the following snippet to your `.vscode/launch.json`: +```json +{ + "configurations": [ + { + "name": "", + "type": "debugpy", + "request": "launch", + "cwd": "${workspaceFolder}", + "program": "${workspaceFolder}/.pyenv/bin/pytest", + "justMyCode": true, + "env": { + "_PYTEST_RAISE": "1" + }, + "args": [ + "-sv", + "--pdb", + "", + ] + } + ] +} ``` +where `` must be changed to the local path to the test module to be debugged. +The settings configuration file `.vscode/settings.json` automatically applies the linting and formatting upon saving the modified file. -There you go - you just created a minimal NOMAD plugin: - -> [!NOTE] -> In the above prompt, we pressed `y` for schema_package and parser, this creates a python package with two plugin entry points: one for parser and one for schema_package. - -```no-highlight -nomad-awesome-tools/ -├── LICENSE -├── README.rst -├── pyproject.toml -├── move_template_files.sh -├── src -│ └── nomad_awesome_tools -│ ├── __init__.py -| ├── schema_packages -│ | ├── __init__.py -│ | └── plugin.py -| └── parsers -│ ├── __init__.py -│ └── plugin.py -| -├── tests -│ ├── conftest.py -│ └── test_awesome.py -└── MANIFEST.in +### Documentation on Github pages + +To view the documentation locally, install the related packages using: +```sh +uv pip install -r requirements_docs.txt +``` + +Run the documentation server: +```sh +mkdocs serve ``` +## Adding this plugin to NOMAD + +Currently, NOMAD has two distinct flavors that are relevant depending on your role as an user: +1. [A NOMAD Oasis](#adding-this-plugin-in-your-nomad-oasis): any user with a NOMAD Oasis instance. +2. [Local NOMAD installation and the source code of NOMAD](#adding-this-plugin-in-your-local-nomad-installation-and-the-source-code-of-nomad): internal developers. -> [!NOTE] -> The project `nomad-awesome-tools` is created in a new directory, we have included a helper script to move all the files to the parent level of the repository. +### Adding this plugin in your NOMAD Oasis +Read the [NOMAD plugin documentation](https://nomad-lab.eu/prod/v1/staging/docs/howto/oasis/plugins_install.html) for all details on how to deploy the plugin on your NOMAD instance. +### Adding this plugin in your local NOMAD installation and the source code of NOMAD + +Modify the text file under `/nomad/default_plugins.txt` and add: +```sh + +nomad-parser-vasp==x.y.z +``` +where `x.y.z` represents the released version of this plugin. + +Then, go to your NOMAD folder, activate your NOMAD virtual environment and run: ```sh -sh CHANGE_TO_PLUGIN_NAME/move_template_files.sh +deactivate +cd /nomad +source .pyenv/bin/activate +./scripts/setup_dev_env.sh +``` + +Alternatively and only valid for your local NOMAD installation, you can modify `nomad.yaml` to include this plugin: +```yaml +plugins: + entry_points: + include: + - ["nomad_parser_vasp.parsers:nomad_parser_vasp_plugin"] + - ["nomad_parser_vasp.schema_packages:nomad_parser_vasp_schema"] ``` -> [!IMPORTANT] -> The `CHANGE_TO_PLUGIN_NAME` should be substituted by the name of the plugin you've created. In the above case it'll be `sh nomad-awesome-tools/move_template_files.sh`. +**Note!** +Once you modify your `nomad.yaml` file adding `include`, all the default plugins will be disconnected, so you will need to include them as well. + + +## Main contributors +| Name | E-mail | Github profiles | +|------|------------|-----------------| +| Dr. Nathan Daelman | [nathan.daelman@physik.hu-berlin.de](mailto:nathan.daelman@physik.hu-berlin.de) | [@ndaelman-hu](https://github.com/ndaelman-hu) | +| Dr. José M. Pizarro | [jose.pizarro@physik.hu-berlin.de](mailto:jose.pizarro@physik.hu-berlin.de) | [@JosePizarro3](https://github.com/JosePizarro3) | + + + +---- + +This `nomad`_ plugin was generated with `Cookiecutter`_ along with `@nomad`_'s `cookiecutter-nomad-plugin`_ template. diff --git a/docs/assets/.gitignore b/docs/assets/.gitignore new file mode 100644 index 0000000..3881e38 --- /dev/null +++ b/docs/assets/.gitignore @@ -0,0 +1 @@ +nomad-oasis*.zip \ No newline at end of file diff --git a/docs/assets/favicon.png b/docs/assets/favicon.png new file mode 100644 index 0000000..f84c78f Binary files /dev/null and b/docs/assets/favicon.png differ diff --git a/docs/assets/nomad-plugin-logo.png b/docs/assets/nomad-plugin-logo.png new file mode 100644 index 0000000..149856c Binary files /dev/null and b/docs/assets/nomad-plugin-logo.png differ diff --git a/docs/explanation/explanation.md b/docs/explanation/explanation.md new file mode 100644 index 0000000..a2035f6 --- /dev/null +++ b/docs/explanation/explanation.md @@ -0,0 +1,4 @@ +# Explanation + +!!! note "Attention" + TODO diff --git a/docs/how_to/contribute_to_the_documentation.md b/docs/how_to/contribute_to_the_documentation.md new file mode 100644 index 0000000..173dce1 --- /dev/null +++ b/docs/how_to/contribute_to_the_documentation.md @@ -0,0 +1,4 @@ +# Contribute to the documentation + +!!! note "Attention" + TODO diff --git a/docs/how_to/contribute_to_this_plugin.md b/docs/how_to/contribute_to_this_plugin.md new file mode 100644 index 0000000..48d405a --- /dev/null +++ b/docs/how_to/contribute_to_this_plugin.md @@ -0,0 +1,5 @@ +# Contribute to This Plugin + +!!! note "Attention" + TODO + diff --git a/docs/how_to/install_this_plugin.md b/docs/how_to/install_this_plugin.md new file mode 100644 index 0000000..2b45e0f --- /dev/null +++ b/docs/how_to/install_this_plugin.md @@ -0,0 +1,4 @@ +# Install This Plugin + +!!! note "Attention" + TODO diff --git a/docs/how_to/use_this_plugin.md b/docs/how_to/use_this_plugin.md new file mode 100644 index 0000000..ad93966 --- /dev/null +++ b/docs/how_to/use_this_plugin.md @@ -0,0 +1,10 @@ +# How to Use This Plugin + +This plugin can be used in a NOMAD Oasis installation. + +## Add This Plugin to Your NOMAD installation + +Read the [NOMAD plugin documentation](https://nomad-lab.eu/prod/v1/staging/docs/plugins/plugins.html#add-a-plugin-to-your-nomad) for all details on how to deploy the plugin on your NOMAD instance. + +!!! note "Attention" + TODO diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..187ec55 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,48 @@ +# Welcome to the `nomad-parser-vasp` documentation + +A NOMAD parser plugin for VASP input/output files. + +## Introduction + +!!! note "Attention" + TODO + +
+
+ +### Tutorial + +TODO + +- [Tutorial](tutorial/tutorial.md) + +
+
+ +### How-to guides + +How-to guides provide step-by-step instructions for a wide range of tasks, with the overarching topics: + +- [Install this plugin](how_to/install_this_plugin.md) +- [Use this plugin](how_to/use_this_plugin.md) +- [Contribute to this plugin](how_to/contribute_to_this_plugin.md) +- [Contribute to the documentation](how_to/contribute_to_the_documentation.md) + +
+ +
+ +### Explanation + +The explanation [section](explanation/explanation.md) provides background knowledge on this plugin. + +
+
+ +### Reference + +The reference [section](reference/references.md) includes all CLI commands and arguments, all configuration options, +the possible schema annotations and their arguments, and a glossary of used terms. + +
+
diff --git a/docs/reference/references.md b/docs/reference/references.md new file mode 100644 index 0000000..c199e70 --- /dev/null +++ b/docs/reference/references.md @@ -0,0 +1,4 @@ +# References + +!!! note "Attention" + TODO diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css new file mode 100644 index 0000000..321e087 --- /dev/null +++ b/docs/stylesheets/extra.css @@ -0,0 +1,69 @@ + +.md-header__button.md-logo :where(img,svg) { + width: 100%; + height: 30px; +} + +.md-header, .md-header__inner { + background-color: #fff; + color: #2A4CDF; +} + +.md-header[data-md-state=shadow] { + box-shadow: 0px 2px 4px -1px rgb(0 0 0 / 20%), 0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%); + transition: box-shadow 200ms linear; +} + +.md-header__inner { + height: 80px; +} + +.md-header__topic { + font-size: 24px; +} + +.md-footer { + background-color: #2A4CDF; +} + +.md-search__form:hover { + background-color: rgba(0,0,0,.13); +} + +.md-typeset h1 { + color: black; + font-weight: 700; +} + +.youtube { + position: relative; + width: 100%; + height: 0; + padding-bottom: 56.25%; +} + +.youtube iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.home-grid { + display: grid; + grid-template-columns: 1fr 1fr; + grid-column-gap: 24px; + row-gap: 24px; +} + +.home-grid div { + border-radius: 4px; + padding: 24px; + background-color: #f3e9d9; +} + +.home-grid h3 { + margin-top: 0; + font-weight: 700; +} \ No newline at end of file diff --git a/docs/theme/partials/header.html b/docs/theme/partials/header.html new file mode 100644 index 0000000..5b091f3 --- /dev/null +++ b/docs/theme/partials/header.html @@ -0,0 +1,86 @@ +{#- + This file was automatically generated - do not edit +-#} +{% set class = "md-header" %} +{% if "navigation.tabs.sticky" in features %} + {% set class = class ~ " md-header--lifted" %} +{% endif %} +
+ + {% if "navigation.tabs.sticky" in features %} + {% if "navigation.tabs" in features %} + {% include "partials/tabs.html" %} + {% endif %} + {% endif %} +
\ No newline at end of file diff --git a/docs/tutorial/tutorial.md b/docs/tutorial/tutorial.md new file mode 100644 index 0000000..a24d72a --- /dev/null +++ b/docs/tutorial/tutorial.md @@ -0,0 +1,4 @@ +# Tutorial + +!!! note "Attention" + TODO diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..af8d344 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,60 @@ +site_name: nomad-parser-vasp +site_description: A NOMAD parser plugin for VASP input/output files. +site_author: Jose Pizarro + +repo_url: https://github.com/FAIRmat-NFDI/nomad-parser-vasp +edit_uri: "" + +nav: + - Home: index.md + - Tutorial: tutorial/tutorial.md + - How-to guides: + - Install this Plugin: how_to/install_this_plugin.md + - Use this Plugin: how_to/use_this_plugin.md + - Contribute to this plugin: how_to/contribute_to_this_plugin.md + - Contribute to the documentation: how_to/contribute_to_the_documentation.md + - Explanation: explanation/explanation.md + - Reference: reference/references.md +plugins: + - search +theme: + name: material + palette: + primary: "#2A4CDF" + accent: "#008A67" + font: + text: "Titillium Web" + logo: assets/nomad-plugin-logo.png + favicon: assets/favicon.png + features: + - navigation.instant + custom_dir: docs/theme + icon: + repo: fontawesome/brands/github +markdown_extensions: + - attr_list + - md_in_html + - admonition + - pymdownx.details + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.superfences + - toc: + permalink: True + - pymdownx.arithmatex: + generic: true + - attr_list + - mkdocs-click + - pymdownx.extra +extra: + generator: false + homepage: https://nomad-lab.eu +use_directory_urls: false +extra_css: + - stylesheets/extra.css +extra_javascript: + - javascript.js + - https://polyfill.io/v3/polyfill.min.js?features=es6 + - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js diff --git a/move_template_files.sh b/move_template_files.sh new file mode 100644 index 0000000..0ff8adb --- /dev/null +++ b/move_template_files.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +if ! command -v rsync >/dev/null 2>&1; then + echo "rsync required, but not installed!" + exit 1 +else + rsync -avh nomad-parser-vasp/ . + rm -rfv nomad-parser-vasp +fi diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..0002522 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,141 @@ +[build-system] +requires = ["setuptools>=61.0.0", "setuptools-scm>=8.0"] +build-backend = "setuptools.build_meta" + +[project] +classifiers = [ + "Intended Audience :: Developers", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "License :: OSI Approved :: Apache Software License", +] +name = "nomad-parser-vasp" +description = "A NOMAD parser plugin for VASP input/output files." +dynamic = ["version"] +readme = "README.md" +requires-python = ">=3.9" +authors = [ + { name = "Nathan Daelman", email = "jose.pizarro@physik.hu-berlin.de" }, + { name = "Jose Pizarro", email = "jose.pizarro@physik.hu-berlin.de" }, +] +maintainers = [ + { name = "Nathan Daelman", email = "ndaelman@physik.hu-berlin.de" }, + { name = "Jose Pizarro", email = "jose.pizarro@physik.hu-berlin.de" }, +] +license = { file = "LICENSE" } +dependencies = [ + "nomad-lab>=1.3.0", + "nomad-simulations@git+https://github.com/nomad-coe/nomad-simulations.git@7c101b80f14d500d6c8bc266a001444b4ba35ea9", + "python-magic-bin; sys_platform == 'win32'", +] + +[project.urls] +"Homepage" = "https://github.com/FAIRmat-NFDI/nomad-parser-vasp" +"Bug Tracker" = "https://github.com/FAIRmat-NFDI/nomad-parser-vasp/issues" +"Documentation" = "https://FAIRmat-NFDI.github.io/nomad-parser-vasp/" + +[project.optional-dependencies] +dev = [ + "mypy==1.0.1", + "ruff", + "pytest", + "pytest-timeout", + "pytest-cov", + "structlog", +] + +[tool.ruff] +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".mypy_cache", + ".nox", + ".pants.d", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "venv", +] + +# Same as Black. +line-length = 88 +indent-width = 4 + + +[tool.ruff.lint] +select = [ + "E", # pycodestyle + "PL", # pylint + "F", # Pyflakes + "UP", # pyupgrade + "I", # isort +] + +ignore = [ + "F401", # Module imported but unused + "E501", # Line too long ({width} > {limit} characters) + "E701", # Multiple statements on one line (colon) + "E731", # Do not assign a lambda expression, use a def + "E402", # Module level import not at top of file + "PLR0911", # Too many return statements + "PLR0912", # Too many branches + "PLR0913", # Too many arguments in function definition + "PLR0915", # Too many statements + "PLR2004", # Magic value used instead of constant + "PLW0603", # Using the global statement + "PLW2901", # redefined-loop-name + "PLR1714", # consider-using-in + "PLR5501", # else-if-used +] + +fixable = ["ALL"] + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +# this is entirely optional, you can remove this if you wish to +[tool.ruff.format] +# use single quotes for strings. +quote-style = "single" + +# indent with spaces, rather than tabs. +indent-style = "space" + +# Like Black, respect magic trailing commas. +skip-magic-trailing-comma = false + +# Like Black, automatically detect the appropriate line ending. +line-ending = "auto" + +[tool.setuptools] +package-dir = { "" = "src" } + +[tool.setuptools.packages.find] +where = ["src"] + +[project.entry-points.'nomad.plugin'] +parser_entry_point = "nomad_parser_vasp.parsers:parser_entry_point" +schema_package_entry_point = "nomad_parser_vasp.schema_packages:schema_package_entry_point" + + + +[tool.cruft] +# Avoid updating workflow files, this leads to permissions issues +skip = [".github/*"] diff --git a/requirements_docs.txt b/requirements_docs.txt new file mode 100644 index 0000000..bacf1ed --- /dev/null +++ b/requirements_docs.txt @@ -0,0 +1,4 @@ +mkdocs +mkdocs-material==8.1.1 +pymdown-extensions +mkdocs-click diff --git a/src/nomad_parser_vasp/__init__.py b/src/nomad_parser_vasp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/nomad_parser_vasp/parsers/__init__.py b/src/nomad_parser_vasp/parsers/__init__.py new file mode 100644 index 0000000..4ef8155 --- /dev/null +++ b/src/nomad_parser_vasp/parsers/__init__.py @@ -0,0 +1,18 @@ +from nomad.config.models.plugins import ParserEntryPoint +from pydantic import Field + + +class NewParserEntryPoint(ParserEntryPoint): + parameter: int = Field(0, description='Custom configuration parameter') + + def load(self): + from nomad_parser_vasp.parsers.parser import NewParser + + return NewParser(**self.dict()) + + +parser_entry_point = NewParserEntryPoint( + name='NewParser', + description='New parser entry point configuration.', + mainfile_name_re='.*\.newmainfilename', +) diff --git a/src/nomad_parser_vasp/parsers/parser.py b/src/nomad_parser_vasp/parsers/parser.py new file mode 100644 index 0000000..930269c --- /dev/null +++ b/src/nomad_parser_vasp/parsers/parser.py @@ -0,0 +1,32 @@ +from typing import ( + TYPE_CHECKING, +) + +if TYPE_CHECKING: + from nomad.datamodel.datamodel import ( + EntryArchive, + ) + from structlog.stdlib import ( + BoundLogger, + ) + +from nomad.config import config +from nomad.datamodel.metainfo.workflow import Workflow +from nomad.parsing.parser import MatchingParser + +configuration = config.get_plugin_entry_point( + 'nomad_parser_vasp.parsers:parser_entry_point' +) + + +class NewParser(MatchingParser): + def parse( + self, + mainfile: str, + archive: 'EntryArchive', + logger: 'BoundLogger', + child_archives: dict[str, 'EntryArchive'] = None, + ) -> None: + logger.info('NewParser.parse', parameter=configuration.parameter) + + archive.workflow2 = Workflow(name='test') diff --git a/src/nomad_parser_vasp/schema_packages/__init__.py b/src/nomad_parser_vasp/schema_packages/__init__.py new file mode 100644 index 0000000..bb7056f --- /dev/null +++ b/src/nomad_parser_vasp/schema_packages/__init__.py @@ -0,0 +1,17 @@ +from nomad.config.models.plugins import SchemaPackageEntryPoint +from pydantic import Field + + +class NewSchemaPackageEntryPoint(SchemaPackageEntryPoint): + parameter: int = Field(0, description='Custom configuration parameter') + + def load(self): + from nomad_parser_vasp.schema_packages.schema_package import m_package + + return m_package + + +schema_package_entry_point = NewSchemaPackageEntryPoint( + name='NewSchemaPackage', + description='New schema package entry point configuration.', +) diff --git a/src/nomad_parser_vasp/schema_packages/schema_package.py b/src/nomad_parser_vasp/schema_packages/schema_package.py new file mode 100644 index 0000000..b1f724f --- /dev/null +++ b/src/nomad_parser_vasp/schema_packages/schema_package.py @@ -0,0 +1,38 @@ +from typing import ( + TYPE_CHECKING, +) + +if TYPE_CHECKING: + from nomad.datamodel.datamodel import ( + EntryArchive, + ) + from structlog.stdlib import ( + BoundLogger, + ) + +from nomad.config import config +from nomad.datamodel.data import Schema +from nomad.datamodel.metainfo.annotations import ELNAnnotation, ELNComponentEnum +from nomad.metainfo import Quantity, SchemaPackage + +configuration = config.get_plugin_entry_point( + 'nomad_parser_vasp.schema_packages:schema_package_entry_point' +) + +m_package = SchemaPackage() + + +class NewSchemaPackage(Schema): + name = Quantity( + type=str, a_eln=ELNAnnotation(component=ELNComponentEnum.StringEditQuantity) + ) + message = Quantity(type=str) + + def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None: + super().normalize(archive, logger) + + logger.info('NewSchema.normalize', parameter=configuration.parameter) + self.message = f'Hello {self.name}!' + + +m_package.__init_metainfo__() diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/data/.gitkeep b/tests/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/data/example.out b/tests/data/example.out new file mode 100644 index 0000000..e69de29 diff --git a/tests/data/test.archive.yaml b/tests/data/test.archive.yaml new file mode 100644 index 0000000..7abb6bc --- /dev/null +++ b/tests/data/test.archive.yaml @@ -0,0 +1,3 @@ +data: + m_def: nomad_parser_vasp.schema_packages.schema_package.NewSchemaPackage + name: Markus diff --git a/tests/parsers/test_parser.py b/tests/parsers/test_parser.py new file mode 100644 index 0000000..166f3f8 --- /dev/null +++ b/tests/parsers/test_parser.py @@ -0,0 +1,13 @@ +import logging + +from nomad.datamodel import EntryArchive + +from nomad_parser_vasp.parsers.parser import NewParser + + +def test_parse_file(): + parser = NewParser() + archive = EntryArchive() + parser.parse('tests/data/example.out', archive, logging.getLogger()) + + assert archive.workflow2.name == 'test' diff --git a/tests/schema_packages/test_schema_package.py b/tests/schema_packages/test_schema_package.py new file mode 100644 index 0000000..4e7b746 --- /dev/null +++ b/tests/schema_packages/test_schema_package.py @@ -0,0 +1,11 @@ +import os.path + +from nomad.client import normalize_all, parse + + +def test_schema_package(): + test_file = os.path.join('tests', 'data', 'test.archive.yaml') + entry_archive = parse(test_file)[0] + normalize_all(entry_archive) + + assert entry_archive.data.message == 'Hello Markus!'