Skip to content

Commit cca64f9

Browse files
authored
Merge pull request #448 from FAIRmat-NFDI/move-nomad-examples-to-plugin
Move NOMAD examples to plugin
2 parents 1cb5a34 + 49682ee commit cca64f9

19 files changed

+688
-50
lines changed

.github/workflows/plugin_test.yaml

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,21 @@ jobs:
2020
fail-fast: false
2121
matrix:
2222
include:
23-
23+
- plugin: pynxtools-apm
24+
branch: main
25+
tests_to_run: tests/.
2426
- plugin: pynxtools-ellips
2527
branch: main
2628
tests_to_run: tests/.
27-
- plugin: pynxtools-raman
29+
- plugin: pynxtools-em
2830
branch: main
2931
tests_to_run: tests/.
3032
- plugin: pynxtools-mpes
3133
branch: main
3234
tests_to_run: tests/.
35+
- plugin: pynxtools-raman
36+
branch: main
37+
tests_to_run: tests/.
3338
- plugin: pynxtools-stm
3439
branch: main
3540
tests_to_run: tests/.
@@ -39,24 +44,16 @@ jobs:
3944
- plugin: pynxtools-xrd
4045
branch: main
4146
tests_to_run: tests/.
42-
# - plugin: pynxtools-apm
43-
# branch: main
44-
# tests_to_run: tests/.
45-
# - plugin: pynxtools-xrd
46-
# branch: update-tests
47-
# tests_to_run: tests/.
48-
# - plugin: pynxtools-em
49-
# branch: main
50-
# tests_to_run: tests/.
47+
5148
steps:
5249
- uses: actions/checkout@v3
5350
with:
5451
fetch-depth: 0
5552
submodules: recursive
56-
- name: Set up Python 3.9
53+
- name: Set up Python 3.11
5754
uses: actions/setup-python@v5
5855
with:
59-
python-version: 3.9
56+
python-version: 3.11
6057
- name: Install dependencies
6158
run: |
6259
curl -LsSf https://astral.sh/uv/install.sh | sh
@@ -73,12 +70,12 @@ jobs:
7370
ref: ${{ matrix.branch }}
7471
- name: Install nomad
7572
run: |
76-
uv pip install nomad-lab@git+https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-FAIR.git
73+
uv pip install nomad-lab[infrastructure]@git+https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-FAIR.git
7774
- name: Install ${{ matrix.plugin }}
7875
run: |
7976
cd ${{ matrix.plugin }}
8077
uv pip install .
8178
- name: Run ${{ matrix.plugin }} tests
8279
run: |
8380
cd ${{ matrix.plugin }}
84-
pytest ${{ matrix.tests_to_run }}
81+
pytest ${{ matrix.tests_to_run }}

.github/workflows/pytest.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ jobs:
3434
curl -LsSf https://astral.sh/uv/install.sh | sh
3535
uv pip install coverage coveralls
3636
- name: Install nomad
37-
if: "${{ matrix.python_version != '3.8' && matrix.python_version != '3.12'}}"
37+
if: "${{ matrix.python_version != '3.8'}}"
3838
run: |
39-
uv pip install nomad-lab@git+https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-FAIR.git
39+
uv pip install nomad-lab[infrastructure]@git+https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-FAIR.git
4040
- name: Install pynx
4141
run: |
4242
uv pip install ".[dev]"

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
repos:
22
- repo: https://github.com/astral-sh/ruff-pre-commit
33
# Ruff version.
4-
rev: v0.7.0
4+
rev: v0.8.0
55
hooks:
66
# Run the linter.
77
- id: ruff

CITATION.cff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ message:
44
If you use this software, please cite it using the
55
metadata from this file.
66
type: software
7-
version: 0.8.2
7+
version: 0.9.0
88
authors:
99
- given-names: Sherjeel
1010
family-names: Shabih

MANIFEST.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ recursive-include src/pynxtools/definitions/contributed_definitions/ *.xml
1010
include src/pynxtools/definitions/*.xsd
1111
include src/pynxtools/nexus-version.txt
1212
include src/pynxtools/remote_definitions_url.txt
13-
include src/pynxtools/definitions/NXDL_VERSION
13+
include src/pynxtools/definitions/NXDL_VERSION
14+
graft src/pynxtools/nomad/examples

dev-requirements.txt

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ colorama==0.4.6
2626
# mkdocs
2727
# mkdocs-material
2828
# pytest
29-
contourpy==1.3.0
29+
contourpy==1.3.1
3030
# via matplotlib
31-
coverage==7.6.4
31+
coverage==7.6.8
3232
# via pytest-cov
3333
cycler==0.12.1
3434
# via matplotlib
3535
distlib==0.3.9
3636
# via virtualenv
3737
filelock==3.16.1
3838
# via virtualenv
39-
fonttools==4.54.1
39+
fonttools==4.55.0
4040
# via matplotlib
4141
ghp-import==2.1.0
4242
# via mkdocs
@@ -46,7 +46,7 @@ hjson==3.1.0
4646
# via
4747
# mkdocs-macros-plugin
4848
# super-collections
49-
identify==2.6.1
49+
identify==2.6.3
5050
# via pre-commit
5151
idna==3.10
5252
# via requests
@@ -92,15 +92,15 @@ mkdocs-click==0.8.1
9292
# via pynxtools (pyproject.toml)
9393
mkdocs-get-deps==0.2.0
9494
# via mkdocs
95-
mkdocs-macros-plugin==1.3.6
95+
mkdocs-macros-plugin==1.3.7
9696
# via pynxtools (pyproject.toml)
97-
mkdocs-material==9.5.42
97+
mkdocs-material==9.5.46
9898
# via pynxtools (pyproject.toml)
9999
mkdocs-material-extensions==1.3.1
100100
# via
101101
# pynxtools (pyproject.toml)
102102
# mkdocs-material
103-
mypy==1.12.1
103+
mypy==1.13.0
104104
# via pynxtools (pyproject.toml)
105105
mypy-extensions==1.0.0
106106
# via mypy
@@ -116,7 +116,7 @@ numpy==1.26.4
116116
# pandas
117117
# scipy
118118
# xarray
119-
packaging==24.1
119+
packaging==24.2
120120
# via
121121
# matplotlib
122122
# mkdocs
@@ -145,7 +145,7 @@ pre-commit==4.0.1
145145
# via pynxtools (pyproject.toml)
146146
pygments==2.18.0
147147
# via mkdocs-material
148-
pymdown-extensions==10.11.2
148+
pymdown-extensions==10.12
149149
# via mkdocs-material
150150
pyparsing==3.2.0
151151
# via matplotlib
@@ -154,7 +154,7 @@ pytest==8.3.3
154154
# pynxtools (pyproject.toml)
155155
# pytest-cov
156156
# pytest-timeout
157-
pytest-cov==5.0.0
157+
pytest-cov==6.0.0
158158
# via pynxtools (pyproject.toml)
159159
pytest-timeout==2.3.1
160160
# via pynxtools (pyproject.toml)
@@ -177,11 +177,11 @@ pyyaml==6.0.2
177177
# pyyaml-env-tag
178178
pyyaml-env-tag==0.1
179179
# via mkdocs
180-
regex==2024.9.11
180+
regex==2024.11.6
181181
# via mkdocs-material
182182
requests==2.32.3
183183
# via mkdocs-material
184-
ruff==0.7.0
184+
ruff==0.8.0
185185
# via pynxtools (pyproject.toml)
186186
scipy==1.14.1
187187
# via ase
@@ -195,7 +195,7 @@ super-collections==0.5.3
195195
# via mkdocs-macros-plugin
196196
termcolor==2.5.0
197197
# via mkdocs-macros-plugin
198-
tomli==2.0.2 ; python_full_version <= '3.11'
198+
tomli==2.1.0 ; python_full_version <= '3.11'
199199
# via coverage
200200
types-pytz==2024.2.0.20241003
201201
# via pynxtools (pyproject.toml)
@@ -211,13 +211,13 @@ urllib3==2.2.3
211211
# via
212212
# requests
213213
# types-requests
214-
uv==0.4.25
214+
uv==0.5.4
215215
# via pynxtools (pyproject.toml)
216-
virtualenv==20.27.0
216+
virtualenv==20.28.0
217217
# via pre-commit
218-
watchdog==5.0.3
218+
watchdog==6.0.0
219219
# via mkdocs
220-
xarray==2024.9.0
220+
xarray==2024.11.0
221221
# via pynxtools (pyproject.toml)
222-
zipp==3.20.2
222+
zipp==3.21.0
223223
# via importlib-metadata

docs/how-tos/using-pynxtools-test-framework.md

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ To test integration of a plugin with the `pynxtools` core system, we need to:
77
## How to write an integration test for a reader plugin with `pynxtools.testing`
88
It is very simple to write a test to verify the plugin integration with `pynxtools` within the plugin's tests directory. The developer can place the test where they want, but they need to use the provided test interface from `pynxtools`. An example test for `pynxtools-FOO` (a demo plugin) plugin is given below:
99

10-
```python
11-
# test_plugin.py
12-
10+
```python title="test_plugin.py"
1311
import os
1412

1513
import pytest
@@ -51,6 +49,9 @@ def test_foo_reader(nxdl, reader_name, files_or_dir, tmp_path, caplog):
5149
# Use `ignore_undocumented` to skip undocumented fields
5250
# caplog_level can be "ERROR" or "WARNING"
5351
test.check_reproducibility_of_nexus()
52+
# Here, you can also pass `ignore_lines` (a list) or `ignore_sections` (a dict)
53+
# if you want to ignore certain lines or lines within a section in the comparison
54+
# of the log files of the reference -nxs file and the one created in the test.
5455
```
5556

5657
Alongside the test data in `test/data`, it is also possible to add other types of test data inside the test directory of the plugin.
@@ -60,3 +61,82 @@ You can also pass additional parameters to `test.convert_to_nexus`:
6061
- `caplog_level` (str): Can be either "ERROR" (by default) or "warning". This parameter determines the level at which the caplog is set during testing. If it is "WARNING", the test will also fail if any warnings are reported by the reader.
6162

6263
- `ignore_undocumented` (boolean): If true, the test skipts the verification of undocumented keys. Otherwise, a warning massages for undocumented keys is raised
64+
65+
# How to write an integration test for a NOMAD example in a reader plugin
66+
It is also possible to ship examples for NOMAD directly with the reader plugin. As an example, `pynxtools-mpes` comes with its own NOMAD example (see [here](https://github.com/FAIRmat-NFDI/pynxtools-mpes/tree/bring-in-examples/src/pynxtools_mpes/nomad)) using the ExampleUploadEntryPoint of NOMAD (see [here](https://nomad-lab.eu/prod/v1/staging/docs/howto/plugins/example_uploads.html) for more documentation).
67+
68+
The `testing` sub-package of `pynxtools` provides two functionalities for testing the `ExampleUploadEntryPoint` defined in a `pynxtools` plugin:
69+
1) Test that the ExampleUploadEntryPoint can be properly loaded
70+
2) Test that the schemas and files in the example folder(s) can be parsed by NOMAD
71+
72+
We will write a test for a `pynxtools_foo_example_entrypoint` defined in the pyproject.toml file of a demo `pynxtools-FOO` (here the actual example data resides in the folder `src/pynxtools_foo/nomad/examples`):
73+
74+
```python title="pyproject.toml"
75+
[project.entry-points.'nomad.plugin']
76+
pynxtools_foo_example = "pynxtools_foo.nomad.entrypoints:pynxtools_foo_example_entrypoint"
77+
```
78+
79+
```python title="src/pynxtools_foo/nomad/nomad_example_entrypoint.py"
80+
from nomad.config.models.plugins import ExampleUploadEntryPoint
81+
82+
pynxtools_foo_example_entrypoint = ExampleUploadEntryPoint(
83+
title="My example upload",
84+
description="""
85+
This is an example upload for the pynxtools-FOO package.
86+
""",
87+
plugin_package="pynxtools_foo",
88+
resources=["nomad/examples/*"],
89+
)
90+
```
91+
A test for the `pynxtools_foo_example_entrypoint` could look like this:
92+
```python title="test_nomad_examples.py"
93+
import nomad
94+
95+
from pynxtools.testing.nomad_example import (
96+
get_file_parameter,
97+
parse_nomad_examples,
98+
example_upload_entry_point_valid,
99+
)
100+
101+
from pynxtools_foo.nomad.entrypoints import pynxtools_foo_example_entrypoint
102+
103+
104+
EXAMPLE_PATH = os.path.join(
105+
os.path.dirname(__file__),
106+
"..",
107+
"src",
108+
"pynxtools_foo",
109+
"nomad",
110+
"examples",
111+
)
112+
113+
114+
@pytest.mark.parametrize(
115+
"mainfile",
116+
get_file_parameter(EXAMPLE_PATH),
117+
)
118+
def test_parse_nomad_examples(mainfile):
119+
"""Test if NOMAD examples work."""
120+
archive_dict = parse_nomad_examples(mainfile)
121+
# Here, you can also implement more logic if you know the contents of the archive_dict
122+
123+
124+
@pytest.mark.parametrize(
125+
("entrypoint", "example_path"),
126+
[
127+
pytest.param(
128+
pynxtools_foo_example_entrypoint,
129+
EXAMPLE_PATH,
130+
id="pynxtools_foo_example",
131+
),
132+
],
133+
)
134+
def test_example_upload_entry_point_valid(entrypoint, example_path):
135+
"""Test if NOMAD ExampleUploadEntryPoint works."""
136+
example_upload_entry_point_valid(
137+
entrypoint=entrypoint,
138+
example_path=example_path,
139+
)
140+
141+
```
142+

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ xrd = [
9696
nexus_parser = "pynxtools.nomad.entrypoints:nexus_parser"
9797
nexus_schema = "pynxtools.nomad.entrypoints:nexus_schema"
9898
nexus_data_converter = "pynxtools.nomad.entrypoints:nexus_data_converter"
99+
iv_temp_example = "pynxtools.nomad.entrypoints:iv_temp_example"
99100

100101
[project.scripts]
101102
read_nexus = "pynxtools.nexus.nexus:main"
@@ -128,7 +129,7 @@ select = [
128129
"E", # pycodestyle
129130
"W", # pycodestyle
130131
"PL", # pylint
131-
"NPY201",
132+
# "NPY201", # reactivate when np>2.0 is used
132133
]
133134
ignore = [
134135
"E501", # Line too long ({width} > {limit} characters)

src/pynxtools/nomad/entrypoints.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
1+
#
2+
# Copyright The NOMAD Authors.
3+
#
4+
# This file is part of NOMAD. See https://nomad-lab.eu for further info.
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
118
try:
2-
from nomad.config.models.plugins import ParserEntryPoint, SchemaPackageEntryPoint
19+
from nomad.config.models.plugins import (
20+
ParserEntryPoint,
21+
SchemaPackageEntryPoint,
22+
ExampleUploadEntryPoint,
23+
)
324
except ImportError as exc:
425
raise ImportError(
526
"Could not import nomad package. Please install the package 'nomad-lab'."
@@ -43,3 +64,14 @@ def load(self):
4364
mainfile_name_re=r".*\.nxs",
4465
mainfile_mime_re="application/x-hdf5",
4566
)
67+
68+
iv_temp_example = ExampleUploadEntryPoint(
69+
title="Sensor Scan - IV Temperature Curve",
70+
category="FAIRmat examples",
71+
description="""
72+
This example shows users how to take data from a Python framework and map it out to a Nexus application definition for IV Temperature measurements, [`NXiv_temp`](https://fairmat-nfdi.github.io/nexus_definitions/classes/contributed_definitions/NXiv_temp.html).
73+
We use the Nexus ELN features of NOMAD to generate a Nexus file.
74+
""",
75+
plugin_package="pynxtools",
76+
resources=["nomad/examples/iv_temp/*"],
77+
)

0 commit comments

Comments
 (0)