diff --git a/.cruft.json b/.cruft.json new file mode 100644 index 0000000..6bba759 --- /dev/null +++ b/.cruft.json @@ -0,0 +1,26 @@ +{ + "template": "https://github.com/FAIRmat-NFDI/cookiecutter-nomad-plugin", + "commit": "dbf41935075d9057d69478db6eb9e7901bb44992", + "checkout": null, + "context": { + "cookiecutter": { + "full_name": "Sebastian Brueckner", + "email": "sebastian.brueckner@physik.hu-berlin.de", + "github_username": "budschi", + "plugin_name": "ikz_raman", + "module_name": "ikz_raman", + "short_description": "NOMAD plugin for Raman data from a Horiba LabRAM instrument", + "version": "0.1.0", + "license": "MIT", + "include_schema_package": true, + "include_normalizer": false, + "include_parser": true, + "include_app": true, + "_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..544ec7a --- /dev/null +++ b/.github/workflows/actions.yml @@ -0,0 +1,56 @@ +name: install-and-test-workflow +on: [push] +jobs: + install-and-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.9 + uses: actions/setup-python@v5 + with: + python-version: 3.9 + - name: Install dependencies + run: | + pip install --upgrade pip + pip install '.[dev]' --index-url https://gitlab.mpcdf.mpg.de/api/v4/projects/2187/packages/pypi/simple + pip install coverage coveralls + - name: Test with pytest + run: | + python -m coverage run -m pytest -sv + - name: Submit to coveralls + continue-on-error: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + coveralls --service=github + build-and-install: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.9 + uses: actions/setup-python@v5 + with: + python-version: 3.9 + - name: Build the package + run: | + pip install --upgrade pip + pip install build + python -m build --sdist + - name: Install the package + run: | + pip install dist/*.tar.gz --index-url https://gitlab.mpcdf.mpg.de/api/v4/projects/2187/packages/pypi/simple + ruff-linting: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: chartboost/ruff-action@v1 + with: + args: "check ." + # to enable auto-formatting check, uncomment the following lines below + # ruff-formatting: + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v4 + # - uses: chartboost/ruff-action@v1 + # with: + # args: "format . --check" diff --git a/.github/workflows/cruft-update.yml b/.github/workflows/cruft-update.yml new file mode 100644 index 0000000..ace73a7 --- /dev/null +++ b/.github/workflows/cruft-update.yml @@ -0,0 +1,75 @@ +# /.github/workflows/cruft-update.yml +name: Update repository with Cruft +permissions: + contents: write + pull-requests: write +on: + schedule: + - cron: "0 14 * * 1" # Every Monday at 2pm (UTC time) + workflow_dispatch: +jobs: + update: + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + include: + - add-paths: . + body: Use this to merge the changes to this repository. + branch: cruft/update + commit-message: "chore: accept new Cruft update" + title: New updates detected with Cruft + - add-paths: .cruft.json + body: Use this to reject the changes in this repository. + branch: cruft/reject + commit-message: "chore: reject new Cruft update" + title: Reject new updates detected with Cruft + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-python@v4 + with: + python-version: "3.10" + + - name: Install Cruft + run: pip3 install cruft + + - name: Check if update is available + continue-on-error: false + id: check + run: | + CHANGES=0 + if [ -f .cruft.json ]; then + if ! cruft check; then + CHANGES=1 + fi + else + echo "No .cruft.json file" + fi + + echo "has_changes=$CHANGES" >> "$GITHUB_OUTPUT" + + - name: Run update if available + if: steps.check.outputs.has_changes == '1' + run: | + git config --global user.email "you@example.com" + git config --global user.name "GitHub" + + cruft update --skip-apply-ask --refresh-private-variables + git restore --staged . + + - name: Create pull request + if: steps.check.outputs.has_changes == '1' + uses: peter-evans/create-pull-request@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + add-paths: ${{ matrix.add-paths }} + commit-message: ${{ matrix.commit-message }} + branch: ${{ matrix.branch }} + delete-branch: true + branch-suffix: timestamp + title: ${{ matrix.title }} + body: | + This is an autogenerated PR. ${{ matrix.body }} + + [Cruft](https://cruft.github.io/cruft/) has detected updates from the Cookiecutter repository. 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/.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..d37f73b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,201 +1,22 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +The MIT License (MIT) - 1. Definitions. +Copyright (c) 2024 Sebastian Brueckner - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - 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 "[]" - 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 - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - 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. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..b5ccc2d --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +recursive-include * nomad_plugin.yaml diff --git a/README.md b/README.md index fcf513e..b585afe 100644 --- a/README.md +++ b/README.md @@ -1,84 +1,93 @@ -# nomad-plugin-template -A template repository for creating a repository with a NOMAD plugin package. +# nomad-ikz_raman +NOMAD plugin for Raman data from a Horiba LabRAM instrument -## 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. +This `nomad`_ plugin was generated with `Cookiecutter`_ along with `@nomad`_'s `cookiecutter-nomad-plugin`_ template. -2. In the newly created repository, start a new Github Codespace and generate the plugin structure. -Run the following command to create a new NOMAD plugin project using cookiecutter-nomad-plugin: +### Install + +You should create a virtual environment. You will need the `nomad-lab` package (and `pytest`). +We recommend using Python 3.9. ```sh -cruft create https://github.com/FAIRmat-NFDI/cookiecutter-nomad-plugin +python3 -m venv .pyenv +source .pyenv/bin/activate +pip install --upgrade pip +pip install -e '.[dev]' --index-url https://gitlab.mpcdf.mpg.de/api/v4/projects/2187/packages/pypi/simple ``` -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 +**Note!** +Until we have an official pypi NOMAD release with the plugins functionality. Make +sure to include NOMAD's internal package registry (e.g. via `--index-url`). + +### Testing + +You can run automated tests with `pytest`: + +```sh +pytest -svx tests ``` +### Run linting + +```sh +ruff check . +``` +### Run auto-formatting +This is entirely optional. To add this as a check in github actions pipeline, uncomment the `ruff-formatting` step in `./github/workflows/actions.yaml`. -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 +```sh +ruff format . ``` +### Developing a NOMAD plugin + +Follow the [guide](https://nomad-lab.eu/prod/v1/staging/docs/howto/plugins/plugins.html) on how to develop NOMAD plugins. + +### Build the python package -> [!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. +The `pyproject.toml` file contains everything that is necessary to turn the project +into a pip installable python package. Run the python build tool to create a package distribution: + +``` +pip install build +python -m build --sdist +``` +You can install the package with pip: + +``` +pip install dist/nomad-ikz_raman-0.1.0 +``` + +Read more about python packages, `pyproject.toml`, and how to upload packages to PyPI +on the [PyPI documentation](https://packaging.python.org/en/latest/tutorials/packaging-projects/). + +### Documentation on Github pages + +To deploy documentation on Github pages, make sure to [enable GitHub pages via the repo settings](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#publishing-from-a-branch). + +To view the documentation locally, install the documentation related packages using: ```sh -sh CHANGE_TO_PLUGIN_NAME/move_template_files.sh +pip install -r requirements_docs.txt ``` -> [!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`. +Run the documentation server: +```sh +mkdocs serve +``` + +### Template update + +We use cruft to update the project based on template changes. A `cruft-update.yml` is included in Github workflows to automatically check for updates and create pull requests to apply updates. Follow the [instructions](https://github.blog/changelog/2022-05-03-github-actions-prevent-github-actions-from-creating-and-approving-pull-requests/) on how to enable Github Actions to create pull requests. + +To run the check for updates locally, follow the instructions on [`cruft` website](https://cruft.github.io/cruft/#updating-a-project). + +### License +Distributed under the terms of the `MIT`_ license, "nomad-ikz_raman" is free and open source software 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..7289444 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,48 @@ +# Welcome to the `nomad-ikz_raman` documentation + +NOMAD plugin for Raman data from a Horiba LabRAM instrument + +## 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..a9a6a4d --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,57 @@ +site_name: nomad-ikz_raman +site_description: NOMAD plugin for Raman data from a Horiba LabRAM instrument +site_author: Sebastian Brueckner + +repo_url: https://github.com/budschi/nomad-ikz_raman + +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 +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..761fd5a --- /dev/null +++ b/move_template_files.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +rsync -avh nomad-ikz_raman/ . +rm -rfv nomad-ikz_raman diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..c3f96f0 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,114 @@ +[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 :: MIT License", +] +name = "nomad-ikz_raman" +description = "NOMAD plugin for Raman data from a Horiba LabRAM instrument" +version = "0.1.0" +readme = "README.rst" +requires-python = ">=3.9" +authors = [ + { name = "Sebastian Brueckner", email = "sebastian.brueckner@physik.hu-berlin.de" }, +] +maintainers = [ + { name = "Sebastian Brueckner", email = "sebastian.brueckner@physik.hu-berlin.de" }, +] +license = { file = "LICENSE" } +dependencies = ["nomad-lab>=1.2.2dev578"] + +[project.urls] +Repository = "https://github.com/budschi/nomad-ikz_raman" + +[project.optional-dependencies] +dev = ["ruff", "pytest", "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 = [ + # pycodestyle + "E", + # Pyflakes + "F", + # pyupgrade + "UP", + # isort + "I", + # pylint + "PL", +] + +ignore = [ + "F403", # 'from module import *' used; unable to detect undefined names +] + +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'] +myparser = "nomad_ikz_raman.parsers:myparser" +mypackage = "nomad_ikz_raman.schema_packages:mypackage" + +myapp = "nomad_ikz_raman.apps:myapp" 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_ikz_raman/__init__.py b/src/nomad_ikz_raman/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/nomad_ikz_raman/apps/__init__.py b/src/nomad_ikz_raman/apps/__init__.py new file mode 100644 index 0000000..cfbc588 --- /dev/null +++ b/src/nomad_ikz_raman/apps/__init__.py @@ -0,0 +1,24 @@ +from nomad.config.models.plugins import AppEntryPoint +from nomad.config.models.ui import App, Column, Columns, FilterMenu, FilterMenus + + +myapp = AppEntryPoint( + name='MyApp', + description='App defined using the new plugin mechanism.', + app=App( + label='MyApp', + path='myapp', + category='simulation', + columns=Columns( + selected=['entry_id'], + options={ + 'entry_id': Column(), + }, + ), + filter_menus=FilterMenus( + options={ + 'material': FilterMenu(label='Material'), + } + ), + ), +) diff --git a/src/nomad_ikz_raman/parsers/__init__.py b/src/nomad_ikz_raman/parsers/__init__.py new file mode 100644 index 0000000..c0024b9 --- /dev/null +++ b/src/nomad_ikz_raman/parsers/__init__.py @@ -0,0 +1,18 @@ +from nomad.config.models.plugins import ParserEntryPoint +from pydantic import Field + + +class MyParserEntryPoint(ParserEntryPoint): + parameter: int = Field(0, description='Custom configuration parameter') + + def load(self): + from nomad_ikz_raman.parsers.myparser import MyParser + + return MyParser(**self.dict()) + + +myparser = MyParserEntryPoint( + name='MyParser', + description='Parser defined using the new plugin mechanism.', + mainfile_name_re='.*\.myparser', +) diff --git a/src/nomad_ikz_raman/parsers/myparser.py b/src/nomad_ikz_raman/parsers/myparser.py new file mode 100644 index 0000000..c39e423 --- /dev/null +++ b/src/nomad_ikz_raman/parsers/myparser.py @@ -0,0 +1,31 @@ +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.results import Material, Results +from nomad.parsing.parser import MatchingParser + +configuration = config.get_plugin_entry_point( + 'nomad_ikz_raman.parsers:myparser' +) + + +class MyParser(MatchingParser): + def parse( + self, + mainfile: str, + archive: 'EntryArchive', + logger: 'BoundLogger', + child_archives: dict[str, 'EntryArchive'] = None, + ) -> None: + logger.info('MyParser.parse', parameter=configuration.parameter) + archive.results = Results(material=Material(elements=['H', 'O'])) diff --git a/src/nomad_ikz_raman/schema_packages/__init__.py b/src/nomad_ikz_raman/schema_packages/__init__.py new file mode 100644 index 0000000..0fec924 --- /dev/null +++ b/src/nomad_ikz_raman/schema_packages/__init__.py @@ -0,0 +1,17 @@ +from nomad.config.models.plugins import SchemaPackageEntryPoint +from pydantic import Field + + +class MySchemaPackageEntryPoint(SchemaPackageEntryPoint): + parameter: int = Field(0, description='Custom configuration parameter') + + def load(self): + from nomad_ikz_raman.schema_packages.mypackage import m_package + + return m_package + + +mypackage = MySchemaPackageEntryPoint( + name='MyPackage', + description='Schema package defined using the new plugin mechanism.', +) diff --git a/src/nomad_ikz_raman/schema_packages/mypackage.py b/src/nomad_ikz_raman/schema_packages/mypackage.py new file mode 100644 index 0000000..49c16e1 --- /dev/null +++ b/src/nomad_ikz_raman/schema_packages/mypackage.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_ikz_raman.schema_packages:mypackage' +) + +m_package = SchemaPackage() + + +class MySchema(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('MySchema.normalize', parameter=configuration.parameter) + self.message = f'Hello {self.name}!' + + +m_package.__init_metainfo__() diff --git a/tests/apps/test_app.py b/tests/apps/test_app.py new file mode 100644 index 0000000..40824fa --- /dev/null +++ b/tests/apps/test_app.py @@ -0,0 +1,4 @@ +def test_importing_app(): + # this will raise an exception if pydantic model validation fails for th app + from nomad_ikz_raman.apps import myapp + 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..3d07c0b --- /dev/null +++ b/tests/data/test.archive.yaml @@ -0,0 +1,3 @@ +data: + m_def: nomad_ikz_raman.schema_packages.mypackage.MySchema + name: Markus diff --git a/tests/parsers/test_parser.py b/tests/parsers/test_parser.py new file mode 100644 index 0000000..e677d55 --- /dev/null +++ b/tests/parsers/test_parser.py @@ -0,0 +1,12 @@ +import logging + +from nomad.datamodel import EntryArchive +from nomad_ikz_raman.parsers.myparser import MyParser + + +def test_parse_file(): + parser = MyParser() + archive = EntryArchive() + parser.parse('tests/data/example.out', archive, logging.getLogger()) + + assert archive.results.material.elements == ['H', 'O'] diff --git a/tests/schema_packages/test_schema.py b/tests/schema_packages/test_schema.py new file mode 100644 index 0000000..76210db --- /dev/null +++ b/tests/schema_packages/test_schema.py @@ -0,0 +1,11 @@ +import os.path + +from nomad.client import normalize_all, parse + + +def test_schema(): + 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!'