Skip to content

Commit 28c7707

Browse files
authored
Merge pull request #63 from Stuermer/master
Extend testing + add pyproject.toml
2 parents 83e0a61 + a861f1a commit 28c7707

File tree

8 files changed

+842
-53
lines changed

8 files changed

+842
-53
lines changed

.github/workflows/test.yml

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
# This `test.yml` file defines a GitHub action that will run for all pull requests,
2-
# and for all pushes to main. It installs the python test libraries `parameterized`
3-
# and `pytest`, and then runs the `pytest` command. This automatically detects
4-
# `test_*.py` files and executes tests therein.
2+
# and for all pushes to dev. It installs the python test libraries and then runs the `pytest` command.
3+
# This automatically detects `test_*.py` files and executes tests therein.
54

65
name: CI
76

87
on:
98
pull_request:
109
push:
1110
branches:
12-
- master
11+
- dev
1312
# schedule:
1413
# - cron: "0 13 * * 1" # Every Monday at 9AM EST
1514

@@ -20,11 +19,16 @@ jobs:
2019
- name: Checkout repository
2120
uses: actions/checkout@v4
2221

23-
- name: Set up environment
24-
run: |
25-
python -m pip install --upgrade pip
26-
pip install parameterized
27-
pip install pytest
22+
- name: Install uv
23+
uses: astral-sh/setup-uv@v5
24+
25+
- name: "Set up Python"
26+
uses: actions/setup-python@v5
27+
with:
28+
python-version-file: "pyproject.toml"
29+
30+
- name: Install the project
31+
run: uv sync --all-extras --dev
2832

2933
- name: Run tests
30-
run: pytest
34+
run: uv run pytest tests

database/data/main/WSe2/nk/Ushkov-e.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ REFERENCES: |
99
(Numerical data kindly provided by Georgy Ermolaev)
1010
COMMENTS: "WSe<sub>2</sub> nanoparticles with diameters from 5 to 150 nm synthesized by femtosecond laser ablation."
1111
CONDITIONS:
12-
direcrion: e
12+
direction: e
1313
DATA:
1414
- type: tabulated nk
1515
data: |

database/data/main/WSe2/nk/Ushkov-o.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ REFERENCES: |
99
(Numerical data kindly provided by Georgy Ermolaev)
1010
COMMENTS: "WSe<sub>2</sub> nanoparticles with diameters from 5 to 150 nm synthesized by femtosecond laser ablation."
1111
CONDITIONS:
12-
direcrion: o
12+
direction: o
1313
DATA:
1414
- type: tabulated nk
1515
data: |

database/data/specs/schott/misc/B270.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ COMMENTS: |
88
20 °C. Clear high transmission crown glass (modified soda-lime glass) available in form of sheets, profile rods strips and blanks.
99
CONDITIONS:
1010
temperature: 293
11-
PROPERTIES:
1211
DATA:
1312
- type: tabulated n
1413
data: |

pyproject.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[project]
2+
name = "refractiveindex-info-database"
3+
version = "2025.02.23"
4+
description = "Database of optical constants"
5+
requires-python = ">=3.10"
6+
dependencies = [
7+
"cerberus>=1.3.7",
8+
"matplotlib>=3.10.1",
9+
"numpy>=2.2.4",
10+
"pyqt6>=6.8.1",
11+
"pytest>=8.3.5",
12+
"pytest-xdist>=3.6.1",
13+
"pyyaml>=6.0.2",
14+
]
15+
16+
[tool.pytest.ini_options]
17+
addopts = "-n 12"

tests/test_parse.py

Lines changed: 0 additions & 40 deletions
This file was deleted.

tests/test_yaml.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
"""Tests to verify that there is a data yaml file for each entry in the catalog-nk.yml and catalog-n2.yml files,
2+
and that all files can be parsed and conform to the expected schema.
3+
4+
This test can be run by the command
5+
6+
pytest tests/test_yaml.py
7+
8+
or simply `pytest` from the repo directory. (The latter will automatically discover
9+
all test files.)
10+
"""
11+
12+
from __future__ import annotations
13+
14+
import pathlib
15+
import re
16+
17+
import pytest
18+
import yaml
19+
from cerberus import Validator
20+
21+
22+
# Extract all YAML paths from the catalog
23+
def extract_paths(catalog: str | list, base_path: str = "") -> list:
24+
paths = []
25+
for item in catalog:
26+
if isinstance(item, dict):
27+
for key, value in item.items():
28+
if key == "data":
29+
paths.append(base_path + value)
30+
elif key == "content":
31+
paths.extend(extract_paths(value, base_path))
32+
elif key == "DIVIDER":
33+
continue
34+
else:
35+
paths.extend(extract_paths([value], base_path))
36+
return paths
37+
38+
39+
# Path to the catalog files
40+
CATALOG_ROOT_PATH = pathlib.Path(__file__).resolve().parent.parent / "database"
41+
CATALOG_NK_PATH = CATALOG_ROOT_PATH / "catalog-nk.yml"
42+
CATALOG_N2_PATH = CATALOG_ROOT_PATH / "catalog-n2.yml"
43+
44+
# Load the catalog files
45+
with open(CATALOG_NK_PATH, "r", encoding="utf-8") as stream:
46+
catalog_nk = yaml.safe_load(stream)
47+
48+
with open(CATALOG_N2_PATH, "r", encoding="utf-8") as stream:
49+
catalog_n2 = yaml.safe_load(stream)
50+
51+
# Get all paths from the catalogs
52+
ALL_NK_PATHS = extract_paths(catalog_nk)
53+
ALL_N2_PATHS = extract_paths(catalog_n2)
54+
55+
# Define the regex pattern for URLs, this is used to validate the URLs in the YAML files
56+
url_regex = re.compile(
57+
r"(?i)^(?:http|ftp)s?://" # http:// or https:// also ignore case
58+
r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|" # domain...
59+
r"localhost|" # localhost...
60+
r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|" # ...or ipv4
61+
r"\[?[A-F0-9]*:[A-F0-9:]+\]?)" # ...or ipv6
62+
r"(?::\d+)?" # optional port
63+
r"(?:/?|[/?]\S+)$"
64+
)
65+
66+
# Define the schema for the YAML nk data files. This could be extended to test other levels of the yaml files and/or test
67+
# the content of each field more thoroughly. E.g. check that temperature is a number, that 'tabulated n' is a list with two columns, etc.
68+
schema = {
69+
"REFERENCES": {"type": "string", "required": True},
70+
"COMMENTS": {"type": "string", "required": False},
71+
"DATA": {"type": "list", "required": True},
72+
"CONDITIONS": {
73+
"oneof": [{"type": "string"}, {"type": "list"}, {"type": "dict"}],
74+
"required": False,
75+
},
76+
"PROPERTIES": {
77+
"oneof": [{"type": "string"}, {"type": "list"}, {"type": "dict"}],
78+
"required": False,
79+
},
80+
}
81+
82+
validator = Validator(schema)
83+
84+
# Define the schema for the 'about.yaml' files
85+
about_scheme = {
86+
"NAMES": {"type": "list", "schema": {"type": "string"}},
87+
"ABOUT": {"type": "string"},
88+
"LINKS": {
89+
"type": "list",
90+
"schema": {
91+
"type": "dict",
92+
"schema": {
93+
"url": {"type": "string", "regex": url_regex.pattern},
94+
"text": {"type": "string"},
95+
},
96+
},
97+
"required": False,
98+
},
99+
}
100+
validator_about = Validator(about_scheme)
101+
102+
# Discover the paths for all `.yml` files.
103+
DATABASE_PATH = pathlib.Path(__file__).resolve().parent.parent / "database" / "data"
104+
ALL_YAML_FILES = list(DATABASE_PATH.rglob("*.yml"))
105+
106+
107+
# Verify that each about.yml file conforms to the expected schema
108+
@pytest.mark.parametrize(
109+
"yaml_file",
110+
ALL_YAML_FILES,
111+
ids=lambda x: str(x).replace(str(DATABASE_PATH), "")[1:].replace(".yml", ""),
112+
)
113+
def test_yaml_schema(yaml_file):
114+
with open(yaml_file, "r") as file:
115+
data = yaml.safe_load(file)
116+
if yaml_file.name == "about.yml":
117+
assert validator_about.validate(data), (
118+
f"Schema validation failed for {yaml_file.name}: {validator_about.errors}"
119+
)
120+
else:
121+
assert validator.validate(data), (
122+
f"Schema validation failed for {yaml_file.name}: {validator.errors}"
123+
)
124+
125+
126+
# Verify that each yaml path referenced in the catalog files exists in the database/data directory
127+
@pytest.mark.parametrize(
128+
"path",
129+
ALL_NK_PATHS + ALL_N2_PATHS,
130+
ids=lambda x: str(x).replace(str(DATABASE_PATH), "").replace(".yml", ""),
131+
)
132+
def test_paths_exist(path):
133+
full_path = (
134+
pathlib.Path(__file__).resolve().parent.parent / "database" / "data" / path
135+
)
136+
assert full_path.exists(), f"Path does not exist: {full_path}"

0 commit comments

Comments
 (0)