Skip to content

Commit 9b44b53

Browse files
author
Michael Fritzsche
committed
added tests and support for curate step
1 parent ddcd26a commit 9b44b53

4 files changed

Lines changed: 131 additions & 24 deletions

File tree

src/hermes/commands/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# from hermes.commands.base import HermesVersionCommand
1313
# from hermes.commands.clean.base import HermesCleanCommand
1414
# from hermes.commands.init.base import HermesInitCommand
15-
# from hermes.commands.curate.base import HermesCurateCommand
15+
from hermes.commands.curate.base import HermesCurateCommand
1616
from hermes.commands.harvest.base import HermesHarvestCommand
1717
# from hermes.commands.process.base import HermesProcessCommand
1818
# from hermes.commands.deposit.base import HermesDepositCommand

src/hermes/commands/cli.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
# from hermes.commands import (HermesHelpCommand, HermesVersionCommand, HermesCleanCommand,
1717
# HermesHarvestCommand, HermesProcessCommand, HermesCurateCommand,
1818
# HermesDepositCommand, HermesPostprocessCommand, HermesInitCommand)
19-
from hermes.commands import HermesHarvestCommand
19+
from hermes.commands import HermesCurateCommand, HermesHarvestCommand
2020
from hermes.commands.base import HermesCommand
2121

2222

@@ -44,7 +44,7 @@ def main() -> None:
4444
# HermesCleanCommand(parser),
4545
HermesHarvestCommand(parser),
4646
# HermesProcessCommand(parser),
47-
# HermesCurateCommand(parser),
47+
HermesCurateCommand(parser),
4848
# HermesDepositCommand(parser),
4949
# HermesPostprocessCommand(parser),
5050
):

src/hermes/commands/curate/base.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,16 @@
55
# SPDX-FileContributor: Michael Meinel
66

77
import argparse
8-
import os
9-
import shutil
10-
import sys
118

129
from pydantic import BaseModel
1310

1411
from hermes.commands.base import HermesCommand
15-
from hermes.model.context import CodeMetaContext
12+
from hermes.model import SoftwareMetadata
13+
from hermes.model.context_manager import HermesContext
14+
from hermes.model.error import HermesValidationError
1615

1716

18-
class _CurateSettings(BaseModel):
17+
class CurateSettings(BaseModel):
1918
"""Generic deposition settings."""
2019

2120
pass
@@ -25,23 +24,30 @@ class HermesCurateCommand(HermesCommand):
2524
""" Curate the unified metadata before deposition. """
2625

2726
command_name = "curate"
28-
settings_class = _CurateSettings
27+
settings_class = CurateSettings
2928

3029
def init_command_parser(self, command_parser: argparse.ArgumentParser) -> None:
3130
pass
3231

3332
def __call__(self, args: argparse.Namespace) -> None:
34-
3533
self.log.info("# Metadata curation")
3634

37-
ctx = CodeMetaContext()
38-
process_output = ctx.hermes_dir / 'process' / (ctx.hermes_name + ".json")
35+
ctx = HermesContext()
36+
ctx.prepare_step("curate")
37+
38+
ctx.prepare_step("process")
39+
with ctx["result"] as process_ctx:
40+
expanded_data = process_ctx["expanded"]
41+
context_data = process_ctx["context"]
42+
ctx.finalize_step("process")
43+
44+
try:
45+
data = SoftwareMetadata(expanded_data[0], context_data["@context"][1])
46+
except Exception as e:
47+
raise HermesValidationError("The results of the process step are invalid.") from e
3948

40-
if not process_output.is_file():
41-
self.log.error(
42-
"No processed metadata found. Please run `hermes process` before curation."
43-
)
44-
sys.exit(1)
49+
with ctx["result"] as curate_ctx:
50+
curate_ctx["expanded"] = data.ld_value
51+
curate_ctx["context"] = {"@context": data.full_context}
4552

46-
os.makedirs(ctx.hermes_dir / 'curate', exist_ok=True)
47-
shutil.copy(process_output, ctx.hermes_dir / 'curate' / (ctx.hermes_name + '.json'))
53+
ctx.finalize_step("curate")

test/hermes_test/model/test_api_e2e.py

Lines changed: 106 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66

77
import pytest
88
import sys
9-
from hermes.model import context_manager, SoftwareMetadata
9+
from hermes.model import SoftwareMetadata
10+
from hermes.model.context_manager import HermesContext
1011
from hermes.commands import cli
1112

1213

@@ -181,10 +182,10 @@ def test_cff_harvest(tmp_path, monkeypatch, cff, res):
181182
sys.argv = ["hermes", "harvest", "--path", str(tmp_path), "--config", str(config_file)]
182183
result = {}
183184
try:
184-
monkeypatch.setattr(context_manager.HermesContext.__init__, "__defaults__", (tmp_path.cwd(),))
185+
monkeypatch.setattr(HermesContext.__init__, "__defaults__", (tmp_path.cwd(),))
185186
cli.main()
186187
except SystemExit:
187-
manager = context_manager.HermesContext()
188+
manager = HermesContext()
188189
manager.prepare_step("harvest")
189190
with manager["cff"] as cache:
190191
result = SoftwareMetadata(cache["codemeta"])
@@ -341,10 +342,10 @@ def test_codemeta_harvest(tmp_path, monkeypatch, codemeta, res):
341342
sys.argv = ["hermes", "harvest", "--path", str(tmp_path), "--config", str(config_file)]
342343
result = {}
343344
try:
344-
monkeypatch.setattr(context_manager.HermesContext.__init__, "__defaults__", (tmp_path.cwd(),))
345+
monkeypatch.setattr(HermesContext.__init__, "__defaults__", (tmp_path.cwd(),))
345346
cli.main()
346347
except SystemExit:
347-
manager = context_manager.HermesContext()
348+
manager = HermesContext()
348349
manager.prepare_step("harvest")
349350
with manager["codemeta"] as cache:
350351
result = SoftwareMetadata(cache["codemeta"])
@@ -353,3 +354,103 @@ def test_codemeta_harvest(tmp_path, monkeypatch, codemeta, res):
353354
sys.argv = orig_argv
354355

355356
assert result.data_dict == res.data_dict
357+
358+
359+
@pytest.mark.parametrize(
360+
"process_result, res",
361+
[
362+
2 * (
363+
SoftwareMetadata({
364+
"@type": ["http://schema.org/SoftwareSourceCode"],
365+
"http://schema.org/description": [{"@value": "for testing"}],
366+
"http://schema.org/name": [{"@value": "Test"}]
367+
}),
368+
),
369+
2 * (
370+
SoftwareMetadata({
371+
"@type": ["http://schema.org/SoftwareSourceCode"],
372+
"http://schema.org/applicationCategory": [{"@id": "Testing"}],
373+
"http://schema.org/author": [
374+
{
375+
"@list": [
376+
{
377+
"@id": "_:author_1",
378+
"@type": ["http://schema.org/Person"],
379+
"http://schema.org/email": [{"@value": "test.testi@test.testi"}],
380+
"http://schema.org/familyName": [{"@value": "Testi"}],
381+
"http://schema.org/givenName": [{"@value": "Test"}]
382+
}
383+
]
384+
}
385+
],
386+
"http://schema.org/codeRepository": [{"@id": "https://github.com/softwarepub/hermes"}],
387+
"http://schema.org/contributor": [
388+
{
389+
"@id": "_:contributor_1",
390+
"@type": ["http://schema.org/Person"],
391+
"http://schema.org/email": [{"@value": "test.testi@test.testi"}],
392+
"http://schema.org/familyName": [{"@value": "Testi"}],
393+
"http://schema.org/givenName": [{"@value": "Test"}]
394+
}
395+
],
396+
"http://schema.org/dateCreated": [{"@type": "http://schema.org/Date", "@value": "2026-01-16"}],
397+
"http://schema.org/dateModified": [{"@type": "http://schema.org/Date", "@value": "2026-01-16"}],
398+
"http://schema.org/datePublished": [{"@type": "http://schema.org/Date", "@value": "2026-01-16"}],
399+
"http://schema.org/description": [{"@value": "for testing"}],
400+
"http://schema.org/funder": [
401+
{
402+
"@type": ["http://schema.org/Organization"],
403+
"http://schema.org/name": [{"@value": "TestsTests"}]
404+
}
405+
],
406+
"http://schema.org/keywords": [{"@value": "testing"}, {"@value": "more testing"}],
407+
"http://schema.org/license": [
408+
{"@id": "https://spdx.org/licenses/Adobe-2006"},
409+
{"@id": "https://spdx.org/licenses/Abstyles"},
410+
{"@id": "https://spdx.org/licenses/AGPL-1.0-only"}
411+
],
412+
"http://schema.org/name": [{"@value": "Test"}],
413+
"http://schema.org/operatingSystem": [{"@value": "Windows"}],
414+
"http://schema.org/programmingLanguage": [{"@value": "Python"}, {"@value": "Python 3"}],
415+
"http://schema.org/relatedLink": [{"@id": "https://docs.software-metadata.pub/en/latest"}],
416+
"http://schema.org/releaseNotes": [{"@value": "get it now"}],
417+
"http://schema.org/version": [{"@value": "1.1.1"}],
418+
"https://codemeta.github.io/terms/developmentStatus": [{"@id": "abandoned"}],
419+
"https://codemeta.github.io/terms/funding": [{"@value": "none :("}],
420+
"https://codemeta.github.io/terms/isSourceCodeOf": [{"@id": "HERMES"}],
421+
"https://codemeta.github.io/terms/issueTracker": [
422+
{"@id": "https://github.com/softwarepub/hermes/issues"}
423+
],
424+
"https://codemeta.github.io/terms/referencePublication": [{"@id": "https://arxiv.org/abs/2201.09015"}]
425+
}),
426+
),
427+
]
428+
)
429+
def test_do_nothing_curate(tmp_path, monkeypatch, process_result, res):
430+
monkeypatch.chdir(tmp_path)
431+
432+
manager = HermesContext(tmp_path)
433+
manager.prepare_step("process")
434+
with manager["result"] as cache:
435+
cache["expanded"] = process_result.ld_value
436+
cache["context"] = {"@context": process_result.full_context}
437+
manager.finalize_step("process")
438+
439+
config_file = tmp_path / "hermes.toml"
440+
config_file.write_text("")
441+
442+
orig_argv = sys.argv[:]
443+
sys.argv = ["hermes", "curate", "--path", str(tmp_path), "--config", str(config_file)]
444+
result = {}
445+
try:
446+
monkeypatch.setattr(HermesContext.__init__, "__defaults__", (tmp_path.cwd(),))
447+
cli.main()
448+
except SystemExit:
449+
manager.prepare_step("curate")
450+
with manager["result"] as cache:
451+
result = SoftwareMetadata(cache["expanded"][0], cache["context"]["@context"][1])
452+
manager.finalize_step("curate")
453+
finally:
454+
sys.argv = orig_argv
455+
456+
assert result.data_dict == res.data_dict

0 commit comments

Comments
 (0)