Skip to content

Commit dc69824

Browse files
committed
add support for CWL ingest
1 parent 6453926 commit dc69824

5 files changed

Lines changed: 106 additions & 3 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
###############################################################################
2+
#
3+
# Licensed to the Apache Software Foundation (ASF) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The ASF licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an
15+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
# KIND, either express or implied. See the License for the
17+
# specific language governing permissions and limitations
18+
# under the License.
19+
#
20+
###############################################################################

‎registration_api/parsers/cwl.py‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
###############################################################################
2+
#
3+
# Licensed to the Apache Software Foundation (ASF) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The ASF licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an
15+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
# KIND, either express or implied. See the License for the
17+
# specific language governing permissions and limitations
18+
# under the License.
19+
#
20+
###############################################################################
21+
22+
import logging
23+
24+
from pygeometa.core import import_metadata
25+
import yaml
26+
27+
LOGGER = logging.getLogger(__name__)
28+
29+
30+
def from_cwl(cwl: dict, url: str = None,
31+
parent_identifier: str = None) -> dict:
32+
"""
33+
Transforms a CWL object to pygeometa MCF model
34+
35+
:param cwl: `dict` of CWL object
36+
:param url: optional `str` of URL
37+
:param parent_identifier: optional `str` of parent identifier
38+
39+
:returns: `dict` of MCF object
40+
"""
41+
42+
mcf = import_metadata('cwl', yaml.safe_dump(cwl))
43+
44+
if parent_identifier is not None:
45+
mcf['metadata']['parentidentifier'] = parent_identifier
46+
47+
if url is not None:
48+
mcf['distribution']['http'] = {
49+
'rel': 'canonical',
50+
'url': url,
51+
'type': 'application/x-yaml',
52+
'name': mcf['identification']['title'],
53+
'description': mcf['identification']['abstract']
54+
}
55+
56+
LOGGER.info(f'MCF: {mcf}')
57+
58+
return mcf

‎registration_api/processes/registration.py‎

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,13 @@
2626

2727
from jsonschema.validators import Draft202012Validator
2828
from owslib.ogcapi.records import Records
29+
from pygeoapi.process.base import BaseProcessor, ProcessorExecuteError
30+
from pygeometa.schemas.ogcapi_records import OGCAPIRecordOutputSchema
2931
import requests
32+
import yaml
33+
34+
from registration_api.parsers.cwl import from_cwl
3035

31-
from pygeoapi.process.base import BaseProcessor, ProcessorExecuteError
3236

3337
LOGGER = logging.getLogger(__name__)
3438

@@ -248,6 +252,7 @@ def execute(self, data: dict, outputs: dict = None) -> tuple:
248252

249253
self.auth = None
250254
mimetype = 'application/json'
255+
resource_mimetype = 'application/geo+json'
251256

252257
LOGGER.debug('Validating request payload against schema')
253258
validation_errors = validate_json(REGISTER_SCHEMA, data)
@@ -266,7 +271,13 @@ def execute(self, data: dict, outputs: dict = None) -> tuple:
266271

267272
if 'href' in source:
268273
LOGGER.debug('Source is a URL')
269-
content = requests.get(source['href']).json()
274+
try:
275+
content = requests.get(source['href']).json()
276+
except json.decoder.JSONDecodeError as err:
277+
LOGGER.debug(f'Error parsing JSON: {err}')
278+
LOGGER.debug('Attempting YAML parsing')
279+
content = yaml.safe_load(requests.get(source['href']).text)
280+
270281
LOGGER.debug('Performing source validation')
271282
validation_errors = validate_json(
272283
REGISTER_SCHEMA['properties']['source']['properties']['oneOf'][0]['content'], # noqa
@@ -282,6 +293,12 @@ def execute(self, data: dict, outputs: dict = None) -> tuple:
282293
LOGGER.error(f'{msg}: {content}')
283294
raise ProcessorExecuteError(msg)
284295

296+
if 'cwlVersion' in content:
297+
LOGGER.debug('Parsing CWL')
298+
content = from_cwl(content, url=source.get('href'))
299+
content = OGCAPIRecordOutputSchema().write(
300+
content, stringify=False)
301+
285302
for stac_extension in content.get('stac_extensions', []):
286303
LOGGER.debug(f'Validating against STAC Extension {stac_extension}')
287304
stac_extension_schema = requests.get(stac_extension)
@@ -373,12 +390,13 @@ def execute(self, data: dict, outputs: dict = None) -> tuple:
373390
url = f"{target['href']}/collections/{collection}/items/{id_}"
374391
elif source['rel'] == 'collection':
375392
url = f"{target['href']}/collections/{collection}"
393+
resource_mimetype = 'application/json'
376394
produced_outputs = {
377395
'id': PROCESS_REGISTER_METADATA['id'],
378396
'resource-and-data-catalogue-link': {
379397
'href': url,
380398
'rel': 'item',
381-
'type': 'application/geo+json'
399+
'type': resource_mimetype
382400
}
383401
}
384402

@@ -504,6 +522,8 @@ def validate_json(schema: dict, instance: dict) -> list:
504522

505523
validation_errors = []
506524
LOGGER.debug('Validating input against schema')
525+
LOGGER.debug(f'Input: {instance}')
526+
LOGGER.debug(f'Schema: {schema}')
507527
validator = Draft202012Validator(schema)
508528

509529
for error in validator.iter_errors(instance):

‎requirements.txt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
gunicorn==23.0.0
22
jsonschema==4.25.1
33
pygeoapi==0.21.0
4+
pygeometa==0.18.0
45
OWSLib==0.34.1
56
requests==2.32.5
7+
PyYAML==6.0.3

‎schemas/process-register.json‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@
4141
},
4242
{
4343
"$ref": "https://raw.githubusercontent.com/EOEPCA/metadata-profile/refs/heads/master/schemas/resource.json"
44+
},
45+
{
46+
"$ref": "https://gist.githubusercontent.com/tomkralidis/a6713e2bc2f9fef5f39b52e0893674bc/raw/cf23172f02df807f717a267390d09f9efa32919f/cwl-1.2.json"
4447
}
4548
]
4649
},

0 commit comments

Comments
 (0)