Skip to content
Merged
Show file tree
Hide file tree
Changes from 97 commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
31cfe08
Add endpoint table
hslh Aug 7, 2025
bf7153c
Add Agent table
hslh Aug 7, 2025
58e574c
Add Catalog table
hslh Aug 7, 2025
3b8eae3
Cleaned up and ordered Catalog.csv to align with FDP specs
hslh Aug 7, 2025
4d19574
Link Catalog and Biobanks
hslh Aug 7, 2025
851f122
Clean up Agent table and align with BBMRI EMX1 FDP
hslh Aug 7, 2025
c04ba4a
Use semantic prefixes
hslh Aug 8, 2025
5c90510
Clean up Endpoint table and align with FDP specs
hslh Aug 8, 2025
fb9d603
Add option to specify Agent type
hslh Aug 8, 2025
d435e71
Fix capitalization
hslh Aug 8, 2025
39240c2
Add ldp container structure and attributes
hslh Aug 8, 2025
fbaad85
Change columns to align with molgenis.csv
hslh Aug 8, 2025
21b05e7
Catalog, not NationalNodes
hslh Aug 8, 2025
66e7f24
Don't add fdp-o metadata identifier manually
hslh Aug 8, 2025
adf1310
Don't 'manually' add endpoint url
hslh Aug 8, 2025
6b28c2c
date, not datetime
hslh Aug 8, 2025
02d392f
No fdp metadata identifier for Endpoint either
hslh Aug 8, 2025
da38f07
Integrate Agent/Catalog/Endpoint into molgenis.csv
hslh Aug 20, 2025
8015251
Merge branch 'master' into feat/directory-emx2-fdp
hslh Aug 20, 2025
edc6646
Add Biobank semantics
hslh Aug 21, 2025
bab0a13
Add semantics for Persons
hslh Aug 21, 2025
c37547b
Add Collections semantics
hslh Aug 21, 2025
654359f
Restructure LDP containers
hslh Aug 21, 2025
110de9b
dct -> dcterms
hslh Aug 21, 2025
0cdbe12
Merge branch 'master' into feat/directory-emx2-fdp
hslh Oct 23, 2025
47530c8
Remove semantics following feedback Vittorio
hslh Oct 23, 2025
1ff6e96
Remove vcard tags from Agent
hslh Oct 23, 2025
3dddf22
Agent -> Publishers
hslh Oct 23, 2025
bfbfb2a
Add Organisations table for vcard contact points
hslh Oct 23, 2025
b8c0dd9
Point contactPoint to Organisations, not Publishers
hslh Oct 23, 2025
c4addeb
Pluralise FDP tables
hslh Oct 23, 2025
a390368
Order molgenis.csv by table name
hslh Oct 23, 2025
5915b48
Add tag and property to Persons
hslh Oct 23, 2025
55db1e3
Add semantics to Catalogs
hslh Oct 23, 2025
bf14308
CSV linting
hslh Oct 23, 2025
6ea14ec
Add properties to Catalogs table
hslh Oct 23, 2025
f051ef2
Remove default policy
hslh Oct 23, 2025
5a32f12
Add DataServices
hslh Oct 23, 2025
e4675fe
Add table definition
hslh Oct 23, 2025
637cb17
Add Address table for Organisations.address to conform to vcard standard
hslh Oct 23, 2025
1d64bdd
Add dcterms:spatial to Collections.country
hslh Oct 23, 2025
a17f8c6
Add issued and modified to Collections
hslh Oct 23, 2025
d501c27
fix comma
hslh Oct 23, 2025
106819e
More commas
hslh Oct 23, 2025
52980ae
Catalog should be Catalogs
hslh Oct 23, 2025
b9c6a7a
Capitalisation
hslh Oct 23, 2025
b862d43
attribute name formatting
hslh Oct 23, 2025
3569d0e
Same
hslh Oct 23, 2025
6c708db
Add fdp-metadata_identifier attributes to allow for output of fdp-o:m…
hslh Oct 24, 2025
9664360
Neater full name computed expression which can handle null values
hslh Oct 24, 2025
3484cfc
Add refback to Endpoints.metadata_catalog as Catalogs.endpoint
hslh Oct 24, 2025
5b2402e
Get endpointURL into semantic mode
hslh Oct 24, 2025
b7ea88b
Use only fdp-o:hasSoftwareVersion for Endpoints.version
hslh Nov 27, 2025
cdbd2d3
Add four attributes to Collections
hslh Dec 1, 2025
ef215c0
Change Collections.publisher to ref
hslh Dec 1, 2025
a1b5bc5
Add dcterms:hasVersiopn to Endpoints.version for FDP SHACL compliance
hslh Dec 1, 2025
56f69e9
Merge branch 'master' into feat/directory-emx2-fdp
hslh Dec 1, 2025
b4a1361
Merge branch 'master' into feat/directory-emx2-fdp
hslh Dec 4, 2025
05bca07
Improve dummy URL
hslh Dec 4, 2025
240c022
Re-order columns
hslh Dec 4, 2025
278f159
Fix label
hslh Dec 4, 2025
197c2d6
Re-order columns
hslh Dec 4, 2025
41cded7
Add missing column
hslh Dec 4, 2025
7c55e94
Add demo data for newly added tables and columns
hslh Dec 4, 2025
81a1b8d
Bump
hslh Dec 4, 2025
fc85541
Add required field
hslh Dec 4, 2025
1872cc2
Add RDF config to demo data default settings
hslh Dec 4, 2025
a893a0b
fix LDP membership relation of Catlaogs
hslh Dec 4, 2025
00bb128
Fix test
hslh Dec 4, 2025
a581287
Merge branch 'master' into feat/directory-emx2-fdp
hslh Dec 8, 2025
b25256d
Correct description of dct:issued and dct:modified
hslh Dec 8, 2025
a73afb4
Merge branch 'master' into feat/directory-emx2-fdp
hslh Jan 12, 2026
e447980
Merge branch 'master' into feat/directory-emx2-fdp
hslh Jan 14, 2026
a9756ad
Change themes, access rights and languages from hyperlinks to ontologies
hslh Jan 14, 2026
240c313
Merge branch 'master' into feat/directory-emx2-fdp
hslh Jan 14, 2026
48bdc59
Ontology formatting got messed up
hslh Jan 14, 2026
adc5307
Update staging area demo data to match directory schema demo data
hslh Jan 14, 2026
d83b5ee
Initial catalog membership
hslh Jan 15, 2026
e4dc161
Initial catalog name retrieval
hslh Jan 15, 2026
a088456
Rename catalog_name, add checks on Catalogs table
hslh Jan 15, 2026
05e3552
Add publisher to collections
hslh Jan 15, 2026
7fcd5f0
Fill language, license, keywords
hslh Jan 15, 2026
cbe9131
Make Themes conformant to EHDS
hslh Jan 23, 2026
f6df17f
Merge branch 'master' into feat/directory-client-fdp-support
hslh Jan 23, 2026
39ec22e
Merge branch 'master' into feat/directory-client-fdp-support
hslh Jan 23, 2026
8f80ae7
Import from src rather than installed module
hslh Jan 23, 2026
59f92dc
Fix mocker patch paths
hslh Jan 23, 2026
8008620
Add test for _set_catalog_membership
hslh Jan 26, 2026
19e2fa8
Add test for _set_fdp_collection_fields
hslh Jan 28, 2026
fb99ce5
Formatting
hslh Jan 28, 2026
790584d
Check Publishers table before setting Collections.publisher
hslh Jan 29, 2026
592bb8d
Merge branch 'master' into feat/directory-client-fdp-support
hslh Jan 29, 2026
7f47cc7
Make backwards compatible with data model without FDP fields
hslh Jan 29, 2026
2bfae58
Merge branch 'master' into feat/directory-client-fdp-support
hslh Jan 29, 2026
9dd4f6a
Merge branch 'master' into feat/directory-client-fdp-support
YpeZ Mar 10, 2026
3e3024b
changed environment variable names in order to avoid clash with env v…
YpeZ Mar 10, 2026
108894c
fixed tests
YpeZ Mar 11, 2026
36e6f71
Allow Python versions > 3.10 in Pipfile, update Pipfile.lock
hslh Mar 11, 2026
dd0eece
Merge branch 'master' into feat/directory-client-fdp-support
hslh Mar 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions tools/directory/dev/.env_example
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
TARGET="https://your-server"
USERNAME=****
PASSWORD=****
DIR_USERNAME=****
DIR_PASSWORD=****
DIRECTORY="name of the BBMRI-ERIC schema"
NN_SCHEMA_PREFIX="National nodes are stored as two letter (country) codes might have a schema prefix"
PID_SERVICE="dummy"
11 changes: 6 additions & 5 deletions tools/directory/dev/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,23 @@
import os

from dotenv import load_dotenv
from tools.directory.src.molgenis_emx2.directory_client.directory import Directory
from tools.directory.src.molgenis_emx2.directory_client.directory_client import (
from directory.src.molgenis_emx2.directory_client.directory import Directory
from directory.src.molgenis_emx2.directory_client.directory_client import (
DirectorySession,
)
from tools.directory.src.molgenis_emx2.directory_client.pid_service import (
from directory.src.molgenis_emx2.directory_client.pid_service import (
DummyPidService,
NoOpPidService,
PidService,
)

# Get credentials from .env
load_dotenv('./tools/directory/dev/.env')
load_dotenv()

target = os.getenv("TARGET")
username = os.getenv("USERNAME")
password = os.getenv("PASSWORD")
username = os.getenv("DIR_USERNAME")
password = os.getenv("DIR_PASSWORD")
directory_schema = os.getenv("DIRECTORY")
pid_service_type = os.getenv(
"PID_SERVICE"
Expand Down
67 changes: 66 additions & 1 deletion tools/directory/src/molgenis_emx2/directory_client/directory.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
from typing import List, Optional

from molgenis_emx2_pyclient.exceptions import NoSuchTableException

from .directory_client import AttributesRequest, DirectorySession
from .errors import DirectoryError, ErrorReport, requests_error_handler
from .errors import (
DirectoryError,
DirectoryWarning,
ErrorReport,
requests_error_handler,
)
from .model import ExternalServerNode, FileIngestNode, Node
from .pid_manager import PidManagerFactory
from .pid_service import BasePidService
Expand Down Expand Up @@ -110,15 +117,73 @@ def _init_state(self, nodes: List[Node], report: ErrorReport) -> PublishingState
matching_attrs=["exact_mapping", "ntbt_mapping"],
)

self.printer.print("📦 Retrieving FDP catalog and publisher")
try:
catalogs = self.session.get(
table='Catalogs', schema=self.session.directory_schema
)
catalog_id = self._get_catalog_id(catalogs)
except NoSuchTableException:
self.printer.print_warning(
DirectoryWarning(' Table Catalogs not found'), indent=1
)
catalog_id = ''

try:
publishers = self.session.get(
table="Publishers", schema=self.session.directory_schema
)
publisher_id = self._get_publisher_id(publishers)
except NoSuchTableException:
self.printer.print_warning(
DirectoryWarning(' Table Publishers not found'), indent=1
)
publisher_id = ''

return PublishingState(
existing_data=published_data,
quality_info=quality_info,
eu_node_data=eu_node_data,
diseases=diseases,
catalog_id=catalog_id,
publisher_id=publisher_id,
nodes=nodes,
report=report,
)

def _get_catalog_id(self, catalogs: list) -> str:
if len(catalogs) == 0:
self.printer.print_warning(
DirectoryWarning(' No FDP catalog found'), indent=1
)
catalog_id = ''
else:
catalog_id = catalogs[0]['id']
if len(catalogs) > 1:
self.printer.print_warning(
DirectoryWarning(
f' More than one FDP catalog found, selecting {catalog_id}'
),
indent=1,
)
return catalog_id

def _get_publisher_id(self, publishers: list) -> str:
if len(publishers) > 0 and 'BBMRI-ERIC' in [
publisher['name'] for publisher in publishers
]:
publisher_id = "BBMRI-ERIC"
else:
self.printer.print_warning(
DirectoryWarning(
" Publisher 'BBMRI-ERIC' not found, "
"not setting Collections.publisher field"
),
indent=1,
)
publisher_id = ""
return publisher_id

async def _prepare_nodes(self, nodes, state):
for node in nodes:
self.printer.print_node_title(node)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ def _transform_node(self, node_data: NodeData, state: PublishingState):
existing_biobanks=state.existing_data.biobanks,
eu_node_data=state.eu_node_data,
diseases=state.diseases,
catalog_id=state.catalog_id,
publisher_id=state.publisher_id,
).transform()
if warnings:
state.report.add_node_warnings(node_data.node, warnings)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class PublishingState:
nodes: List[Node]
report: ErrorReport
diseases: OntologyTable
catalog_id: str
publisher_id: str
data_to_publish: MixedData = field(init=False)

def __post_init__(self):
Expand Down
36 changes: 36 additions & 0 deletions tools/directory/src/molgenis_emx2/directory_client/transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,18 @@ def __init__(
existing_biobanks: Table,
eu_node_data: NodeData,
diseases: OntologyTable,
catalog_id: str,
publisher_id: str,
):
self.node_data = node_data
self.quality = quality
self.printer = printer
self.existing_biobanks = existing_biobanks.rows_by_id
self.eu_node_data = eu_node_data
self.category_mapper = CategoryMapper(diseases)
self.catalog_id = catalog_id
self.publisher_id = publisher_id
self.diseases = diseases

self.warnings = []

Expand All @@ -43,6 +48,8 @@ def transform(self):
7. Add biobank labels (biobank name) to collections
8. Adds the combined qualities to collections
9. Sets the collections' categories
10. Adds all non-withdrawn collections to the main FDP catalog
11. Fill in FDP-related fields for collections

"""
self._set_national_node_code()
Expand All @@ -54,6 +61,9 @@ def transform(self):
self._set_biobank_labels()
self._set_combined_qualities()
self._set_collection_categories()
if self.catalog_id:
self._set_catalog_membership()
self._set_collection_fdp_fields()
return self.warnings

def _set_commercial_use_bool(self):
Expand Down Expand Up @@ -188,3 +198,29 @@ def _set_withdrawn(self):
):
for row in table.rows:
row["withdrawn"] = True

def _set_catalog_membership(self):
"""
Adds all non-withdrawn collections to the FDP catalog
"""
self.printer.print("Setting FDP catalog membership")
for row in self.node_data.collections.rows:
if not row['withdrawn']:
row['catalog'] = self.catalog_id

def _set_collection_fdp_fields(self):
"""
Fill in FDP-related fields for collections
"""
self.printer.print("Setting FDP-related fields for collections")
for row in self.node_data.collections.rows:
if self.publisher_id:
row['publisher'] = self.publisher_id
row['language'] = 'English'
row[
'license'
] = 'https://ejp-rd-vp.github.io/resource-metadata-schema/license/v1.0.txt'
keywords = []
for diagnosis in row['diagnosis_available']:
keywords.append(self.diseases.rows_by_id[diagnosis]['label'])
row['keywords'] = keywords
2 changes: 1 addition & 1 deletion tools/directory/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import pytest

from molgenis_emx2.directory_client.model import (
from src.molgenis_emx2.directory_client.model import (
Node,
NodeData,
Source,
Expand Down
4 changes: 2 additions & 2 deletions tools/directory/tests/test_categories.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

import pytest

from molgenis_emx2.directory_client.categories import Category, CategoryMapper
from molgenis_emx2.directory_client.model import OntologyTable
from src.molgenis_emx2.directory_client.categories import Category, CategoryMapper
from src.molgenis_emx2.directory_client.model import OntologyTable


@pytest.fixture
Expand Down
14 changes: 9 additions & 5 deletions tools/directory/tests/test_directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@

import pytest

from molgenis_emx2.directory_client.directory import Directory
from molgenis_emx2.directory_client.errors import DirectoryError, ErrorReport
from molgenis_emx2.directory_client.model import ExternalServerNode, Node
from molgenis_emx2.directory_client.publisher import PublishingState
from src.molgenis_emx2.directory_client.directory import Directory
from src.molgenis_emx2.directory_client.errors import DirectoryError, ErrorReport
from src.molgenis_emx2.directory_client.model import ExternalServerNode, Node
from src.molgenis_emx2.directory_client.publisher import PublishingState

pytest_plugins = ("pytest_asyncio",)


@pytest.fixture
def report_init():
with patch("molgenis_emx2.directory_client.directory.ErrorReport") as report_mock:
with patch(
"src.molgenis_emx2.directory_client.directory.ErrorReport"
) as report_mock:
yield report_mock


Expand Down Expand Up @@ -95,6 +97,8 @@ def _setup_state(nodes: List[Node], eric: Directory, report_init):
nodes=nodes,
report=report,
diseases=MagicMock(),
catalog_id=MagicMock(),
publisher_id=MagicMock()
)
eric._init_state = MagicMock()
eric._init_state.return_value = state
Expand Down
4 changes: 2 additions & 2 deletions tools/directory/tests/test_errors.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import pytest
import requests.exceptions

from molgenis_emx2.directory_client.errors import (
from src.molgenis_emx2.directory_client.errors import (
DirectoryError,
DirectoryWarning,
ErrorReport,
requests_error_handler,
)
from molgenis_emx2.directory_client.model import Node
from src.molgenis_emx2.directory_client.model import Node


def test_warning():
Expand Down
2 changes: 1 addition & 1 deletion tools/directory/tests/test_model.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# noinspection PyProtectedMember
from unittest.mock import MagicMock

from molgenis_emx2.directory_client.model import (
from src.molgenis_emx2.directory_client.model import (
ExternalServerNode,
Node,
NodeData,
Expand Down
2 changes: 1 addition & 1 deletion tools/directory/tests/test_model_fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pytest

from molgenis_emx2.directory_client.model_fitting import ModelFitter
from src.molgenis_emx2.directory_client.model_fitting import ModelFitter


@pytest.fixture
Expand Down
8 changes: 4 additions & 4 deletions tools/directory/tests/test_pid_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@

import pytest

from molgenis_emx2.directory_client.model import Table, TableType
from molgenis_emx2.directory_client.pid_manager import (
from src.molgenis_emx2.directory_client.model import Table, TableType
from src.molgenis_emx2.directory_client.pid_manager import (
NoOpPidManager,
PidManager,
PidManagerFactory,
)
from molgenis_emx2.directory_client.pid_service import (
from src.molgenis_emx2.directory_client.pid_service import (
DummyPidService,
NoOpPidService,
Status,
)
from molgenis_emx2.directory_client.printer import Printer
from src.molgenis_emx2.directory_client.printer import Printer


@pytest.fixture
Expand Down
4 changes: 2 additions & 2 deletions tools/directory/tests/test_pid_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

import pytest

from molgenis_emx2.directory_client.errors import DirectoryError
from molgenis_emx2.directory_client.pid_service import (
from src.molgenis_emx2.directory_client.errors import DirectoryError
from src.molgenis_emx2.directory_client.pid_service import (
DummyPidService,
NoOpPidService,
PidService,
Expand Down
6 changes: 3 additions & 3 deletions tools/directory/tests/test_printer.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import textwrap

from molgenis_emx2.directory_client.errors import (
from src.molgenis_emx2.directory_client.errors import (
DirectoryError,
DirectoryWarning,
ErrorReport,
)
from molgenis_emx2.directory_client.model import Node
from molgenis_emx2.directory_client.printer import Printer
from src.molgenis_emx2.directory_client.model import Node
from src.molgenis_emx2.directory_client.printer import Printer


def test_indentation(capsys):
Expand Down
12 changes: 6 additions & 6 deletions tools/directory/tests/test_publication_preparer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

import pytest

from molgenis_emx2.directory_client.errors import DirectoryWarning, ErrorReport
from molgenis_emx2.directory_client.model import Node
from molgenis_emx2.directory_client.publication_preparer import PublicationPreparer
from src.molgenis_emx2.directory_client.errors import DirectoryWarning, ErrorReport
from src.molgenis_emx2.directory_client.model import Node
from src.molgenis_emx2.directory_client.publication_preparer import PublicationPreparer


@pytest.fixture
def validator_init():
with (
patch(
"molgenis_emx2.directory_client.publication_preparer.Validator"
"src.molgenis_emx2.directory_client.publication_preparer.Validator"
) as validator_mock
):
yield validator_mock
Expand All @@ -20,15 +20,15 @@ def validator_init():
@pytest.fixture
def model_fitter_init():
with patch(
"molgenis_emx2.directory_client.publication_preparer.ModelFitter"
"src.molgenis_emx2.directory_client.publication_preparer.ModelFitter"
) as model_fitter_mock:
yield model_fitter_mock


@pytest.fixture
def transformer_init():
with patch(
"molgenis_emx2.directory_client.publication_preparer.Transformer"
"src.molgenis_emx2.directory_client.publication_preparer.Transformer"
) as transformer_mock:
yield transformer_mock

Expand Down
Loading