ChessAnalysisPipeline 0.0.17.dev3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- CHAP/TaskManager.py +216 -0
- CHAP/__init__.py +27 -0
- CHAP/common/__init__.py +57 -0
- CHAP/common/models/__init__.py +8 -0
- CHAP/common/models/common.py +124 -0
- CHAP/common/models/integration.py +659 -0
- CHAP/common/models/map.py +1291 -0
- CHAP/common/processor.py +2869 -0
- CHAP/common/reader.py +658 -0
- CHAP/common/utils.py +110 -0
- CHAP/common/writer.py +730 -0
- CHAP/edd/__init__.py +23 -0
- CHAP/edd/models.py +876 -0
- CHAP/edd/processor.py +3069 -0
- CHAP/edd/reader.py +1023 -0
- CHAP/edd/select_material_params_gui.py +348 -0
- CHAP/edd/utils.py +1572 -0
- CHAP/edd/writer.py +26 -0
- CHAP/foxden/__init__.py +19 -0
- CHAP/foxden/models.py +71 -0
- CHAP/foxden/processor.py +124 -0
- CHAP/foxden/reader.py +224 -0
- CHAP/foxden/utils.py +80 -0
- CHAP/foxden/writer.py +168 -0
- CHAP/giwaxs/__init__.py +11 -0
- CHAP/giwaxs/models.py +491 -0
- CHAP/giwaxs/processor.py +776 -0
- CHAP/giwaxs/reader.py +8 -0
- CHAP/giwaxs/writer.py +8 -0
- CHAP/inference/__init__.py +7 -0
- CHAP/inference/processor.py +69 -0
- CHAP/inference/reader.py +8 -0
- CHAP/inference/writer.py +8 -0
- CHAP/models.py +227 -0
- CHAP/pipeline.py +479 -0
- CHAP/processor.py +125 -0
- CHAP/reader.py +124 -0
- CHAP/runner.py +277 -0
- CHAP/saxswaxs/__init__.py +7 -0
- CHAP/saxswaxs/processor.py +8 -0
- CHAP/saxswaxs/reader.py +8 -0
- CHAP/saxswaxs/writer.py +8 -0
- CHAP/server.py +125 -0
- CHAP/sin2psi/__init__.py +7 -0
- CHAP/sin2psi/processor.py +8 -0
- CHAP/sin2psi/reader.py +8 -0
- CHAP/sin2psi/writer.py +8 -0
- CHAP/tomo/__init__.py +15 -0
- CHAP/tomo/models.py +210 -0
- CHAP/tomo/processor.py +3862 -0
- CHAP/tomo/reader.py +9 -0
- CHAP/tomo/writer.py +59 -0
- CHAP/utils/__init__.py +6 -0
- CHAP/utils/converters.py +188 -0
- CHAP/utils/fit.py +2947 -0
- CHAP/utils/general.py +2655 -0
- CHAP/utils/material.py +274 -0
- CHAP/utils/models.py +595 -0
- CHAP/utils/parfile.py +224 -0
- CHAP/writer.py +122 -0
- MLaaS/__init__.py +0 -0
- MLaaS/ktrain.py +205 -0
- MLaaS/mnist_img.py +83 -0
- MLaaS/tfaas_client.py +371 -0
- chessanalysispipeline-0.0.17.dev3.dist-info/LICENSE +60 -0
- chessanalysispipeline-0.0.17.dev3.dist-info/METADATA +29 -0
- chessanalysispipeline-0.0.17.dev3.dist-info/RECORD +70 -0
- chessanalysispipeline-0.0.17.dev3.dist-info/WHEEL +5 -0
- chessanalysispipeline-0.0.17.dev3.dist-info/entry_points.txt +2 -0
- chessanalysispipeline-0.0.17.dev3.dist-info/top_level.txt +2 -0
CHAP/edd/writer.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""EDD specific writers."""
|
|
3
|
+
|
|
4
|
+
# Local modules
|
|
5
|
+
from CHAP import Writer
|
|
6
|
+
|
|
7
|
+
class StrainAnalysisUpdateWriter(Writer):
|
|
8
|
+
def write(self, data):
|
|
9
|
+
# Third party modules
|
|
10
|
+
from nexusformat.nexus import nxload
|
|
11
|
+
|
|
12
|
+
# Local modules
|
|
13
|
+
from CHAP.edd.processor import StrainAnalysisProcessor
|
|
14
|
+
|
|
15
|
+
points = self.unwrap_pipelinedata(data)[0]
|
|
16
|
+
nxroot = nxload(self.filename, mode='r+')
|
|
17
|
+
StrainAnalysisProcessor.add_points(nxroot, points, logger=self.logger)
|
|
18
|
+
|
|
19
|
+
return nxroot
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
if __name__ == '__main__':
|
|
23
|
+
# Local modules
|
|
24
|
+
from CHAP.writer import main
|
|
25
|
+
|
|
26
|
+
main()
|
CHAP/foxden/__init__.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""This subpackage contains `PipelineItems` to communicate with FOXDEN
|
|
2
|
+
services.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from CHAP.foxden.processor import (
|
|
6
|
+
# FoxdenMetadataProcessor,
|
|
7
|
+
FoxdenProvenanceProcessor,
|
|
8
|
+
)
|
|
9
|
+
from CHAP.foxden.reader import (
|
|
10
|
+
FoxdenDataDiscoveryReader,
|
|
11
|
+
FoxdenMetadataReader,
|
|
12
|
+
FoxdenProvenanceReader,
|
|
13
|
+
FoxdenSpecScansReader,
|
|
14
|
+
)
|
|
15
|
+
from CHAP.foxden.writer import (
|
|
16
|
+
FoxdenDoiWriter,
|
|
17
|
+
FoxdenMetadataWriter,
|
|
18
|
+
FoxdenProvenanceWriter,
|
|
19
|
+
)
|
CHAP/foxden/models.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""FOXDEN Pydantic model classes."""
|
|
2
|
+
|
|
3
|
+
# System modules
|
|
4
|
+
from typing import (
|
|
5
|
+
# Literal,
|
|
6
|
+
Optional,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
# Third party modules
|
|
10
|
+
from pydantic import (
|
|
11
|
+
conint,
|
|
12
|
+
constr,
|
|
13
|
+
# field_validator,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# Local modules
|
|
17
|
+
from CHAP import CHAPBaseModel
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class FoxdenRequestConfig(CHAPBaseModel):
|
|
21
|
+
"""FOXDEN HTTP request base configuration class.
|
|
22
|
+
|
|
23
|
+
:param url: URL of service.
|
|
24
|
+
:type url: str
|
|
25
|
+
:param did: FOXDEN dataset identifier (did).
|
|
26
|
+
:type did: string, optional
|
|
27
|
+
:param query: FOXDEN query.
|
|
28
|
+
:type query: string, optional
|
|
29
|
+
:param method: HTTP request method (not case sensitive),
|
|
30
|
+
defaults to `'POST'`.
|
|
31
|
+
:type method: Literal['DELETE', 'GET', 'POST', 'PUT'], optional
|
|
32
|
+
# :param scope: FOXDEN scope (not case sensitive).
|
|
33
|
+
# :type scope: Literal['read', 'write'], optional
|
|
34
|
+
# :param idx: Ask Valentin, currently it's ignored
|
|
35
|
+
# :type idx: int, optional
|
|
36
|
+
:param limit: Maximum number of returned records,
|
|
37
|
+
defaults to `10`.
|
|
38
|
+
:type limit: int, optional
|
|
39
|
+
:param verbose: Verbose output flag, defaults to `False`.
|
|
40
|
+
:type verbose: bool, optional
|
|
41
|
+
"""
|
|
42
|
+
# Mimics golib.services.data.ServiceQuery
|
|
43
|
+
did: Optional[constr(
|
|
44
|
+
strict=True, strip_whitespace=True, to_lower=True)] = None
|
|
45
|
+
limit: Optional[conint(gt=0)] = 10
|
|
46
|
+
query: Optional[constr(
|
|
47
|
+
strict=True, strip_whitespace=True, to_lower=True)] = None
|
|
48
|
+
# method: Optional[Literal['DELETE', 'GET', 'POST', 'PUT']] = 'POST'
|
|
49
|
+
# scope: Optional[Literal['read', 'write']] = None
|
|
50
|
+
# sortkeys: Optional[
|
|
51
|
+
# conlist[item_type=constr(strict=True, strip_whitespace=True)]] = None
|
|
52
|
+
# sortorder: Optional[int] = None
|
|
53
|
+
# spec: Optional[map[string]any] ?
|
|
54
|
+
# sql: Optional[constr(strict=True, strip_whitespace=True)] = None
|
|
55
|
+
# idx: Optional[conint(ge=0)] = 0
|
|
56
|
+
url: constr(strict=True, strip_whitespace=True)
|
|
57
|
+
verbose: Optional[bool] = None
|
|
58
|
+
|
|
59
|
+
# @field_validator('method', mode='before')
|
|
60
|
+
# @classmethod
|
|
61
|
+
# def validate_method(cls, method):
|
|
62
|
+
# """Capitalize method."""
|
|
63
|
+
# return method.upper()
|
|
64
|
+
|
|
65
|
+
# @field_validator('scope', mode='before')
|
|
66
|
+
# @classmethod
|
|
67
|
+
# def validate_scope(cls, scope):
|
|
68
|
+
# """Enforce lowercase for scope."""
|
|
69
|
+
# if isinstance(scope, str):
|
|
70
|
+
# return scope.lower()
|
|
71
|
+
# return scope
|
CHAP/foxden/processor.py
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
#-*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
File : processor.py
|
|
5
|
+
Author : Valentin Kuznetsov <vkuznet AT gmail dot com>
|
|
6
|
+
Description: Processor module for FOXDEN services
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# Local modules
|
|
10
|
+
from CHAP.common.utils import (
|
|
11
|
+
osinfo,
|
|
12
|
+
environments,
|
|
13
|
+
)
|
|
14
|
+
from CHAP.processor import Processor
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
#class FoxdenMetadataProcessor(Processor):
|
|
18
|
+
# """Processor to collect CHAP workflow metadata from a workflow
|
|
19
|
+
# NeXus output object.
|
|
20
|
+
# """
|
|
21
|
+
# def process(self, data):
|
|
22
|
+
# """Extract metadata from a workflow NeXus output object for
|
|
23
|
+
# submission to the FOXDEN Metadata service.
|
|
24
|
+
#
|
|
25
|
+
# :param data: Input data.
|
|
26
|
+
# :type data: list[PipelineData]
|
|
27
|
+
# :return: CHAP workflow metadata record.
|
|
28
|
+
# :rtype: dict
|
|
29
|
+
# """
|
|
30
|
+
# # Third party modules
|
|
31
|
+
# from json import loads
|
|
32
|
+
# from nexusformat.nexus import (
|
|
33
|
+
# NXentry,
|
|
34
|
+
# NXroot,
|
|
35
|
+
# )
|
|
36
|
+
#
|
|
37
|
+
# # Load and validate the workflow NeXus output object
|
|
38
|
+
# nxentry = self.get_data(data, remove=False)
|
|
39
|
+
# if isinstance(nxentry, NXroot):
|
|
40
|
+
# nxentry = nxentry[nxentry.default]
|
|
41
|
+
# if not isinstance(nxentry, NXentry):
|
|
42
|
+
# raise ValueError(f'Invalid input data type {type(nxentry)}')
|
|
43
|
+
#
|
|
44
|
+
# # Get did and experiment type
|
|
45
|
+
# map_config = loads(str(nxentry.map_config))
|
|
46
|
+
# did = map_config['did']
|
|
47
|
+
# experiment_type = map_config['experiment_type']
|
|
48
|
+
#
|
|
49
|
+
# # Extract metadata
|
|
50
|
+
# method = getattr(self, f'_get_metadata_{experiment_type.lower()}')
|
|
51
|
+
# metadata = method(nxentry)
|
|
52
|
+
#
|
|
53
|
+
# if 'reconstructed_data' in metadata:
|
|
54
|
+
# did = f'{did}/{experiment_type.lower()}_reconstructed'
|
|
55
|
+
# else:
|
|
56
|
+
# did = f'{did}/{experiment_type.lower()}_reduced'
|
|
57
|
+
# return {'did': did, 'application': 'CHAP', 'metadata': metadata}
|
|
58
|
+
#
|
|
59
|
+
# def _get_metadata_tomo(self, nxentry):
|
|
60
|
+
# metadata = {}
|
|
61
|
+
# if 'reduced_data' in nxentry:
|
|
62
|
+
# data = nxentry.reduced_data
|
|
63
|
+
# metadata.update({
|
|
64
|
+
# 'reduced_data': {
|
|
65
|
+
# 'date': str(data.date),
|
|
66
|
+
# 'img_row_bounds': data.img_row_bounds.tolist(),
|
|
67
|
+
# }
|
|
68
|
+
# })
|
|
69
|
+
# if 'reconstructed_data' in nxentry:
|
|
70
|
+
# data = nxentry.reconstructed_data
|
|
71
|
+
# metadata.update({
|
|
72
|
+
# 'reconstructed_data': {
|
|
73
|
+
# 'date': str(data.date),
|
|
74
|
+
# 'center_offsets': data.center_offsets.tolist(),
|
|
75
|
+
# 'center_rows': data.center_offsets.tolist(),
|
|
76
|
+
# 'center_stack_index': int(data.center_stack_index),
|
|
77
|
+
# 'x_bounds': data.x_bounds.tolist(),
|
|
78
|
+
# 'y_bounds': data.y_bounds.tolist(),
|
|
79
|
+
# }
|
|
80
|
+
# })
|
|
81
|
+
# if 'combined_data' in nxentry:
|
|
82
|
+
# data = nxentry.combined_data
|
|
83
|
+
# metadata.update({
|
|
84
|
+
# 'combined_data': {
|
|
85
|
+
# 'date': str(data.date),
|
|
86
|
+
# }
|
|
87
|
+
# })
|
|
88
|
+
# return metadata
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class FoxdenProvenanceProcessor(Processor):
|
|
92
|
+
"""Processor to collect CHAP workflow provenance data."""
|
|
93
|
+
def process(self, data):
|
|
94
|
+
"""Extract provenance data from the pipeline data for
|
|
95
|
+
submission to the FOXDEN Provenance service.
|
|
96
|
+
|
|
97
|
+
:param data: Input data.
|
|
98
|
+
:type data: list[PipelineData]
|
|
99
|
+
:return: CHAP workflow provenance record.
|
|
100
|
+
:rtype: dict
|
|
101
|
+
"""
|
|
102
|
+
# Load the provenance info
|
|
103
|
+
provenance = self.get_data(data, schema='provenance')
|
|
104
|
+
|
|
105
|
+
# Add system info to provenance data
|
|
106
|
+
did = provenance['did']
|
|
107
|
+
provenance.update({
|
|
108
|
+
'parent_did': did.rsplit('/', 1)[0],
|
|
109
|
+
'scripts': [
|
|
110
|
+
{'name': 'CHAP', 'parent_script': None, 'order_idx': 1}],
|
|
111
|
+
'site': 'Cornell',
|
|
112
|
+
'osinfo': osinfo(),
|
|
113
|
+
'environments': environments(),
|
|
114
|
+
'processing': 'CHAP pipeline',
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
return provenance
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
if __name__ == '__main__':
|
|
121
|
+
# Local modules
|
|
122
|
+
from CHAP.processor import main
|
|
123
|
+
|
|
124
|
+
main()
|
CHAP/foxden/reader.py
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
#-*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
File : reader.py
|
|
5
|
+
Author : Valentin Kuznetsov <vkuznet AT gmail dot com>
|
|
6
|
+
Description: FOXDEN readers
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# System modules
|
|
10
|
+
import json
|
|
11
|
+
|
|
12
|
+
# Local modules
|
|
13
|
+
from CHAP.pipeline import PipelineItem
|
|
14
|
+
from CHAP.foxden.utils import HttpRequest
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class FoxdenDataDiscoveryReader(PipelineItem):
|
|
18
|
+
"""Reader for the FOXDEN Data Discovery service."""
|
|
19
|
+
def read(self, config):
|
|
20
|
+
"""Read records from the FOXDEN Data Discovery service based on
|
|
21
|
+
did or an arbitrary query.
|
|
22
|
+
|
|
23
|
+
:param config: FOXDEN HTTP request configuration.
|
|
24
|
+
:type config: CHAP.foxden.models.FoxdenRequestConfig
|
|
25
|
+
:return: Discovered data records.
|
|
26
|
+
:rtype: list
|
|
27
|
+
"""
|
|
28
|
+
# Load and validate the FoxdenRequestConfig configuration
|
|
29
|
+
config = self.get_config(
|
|
30
|
+
config=config, schema='foxden.models.FoxdenRequestConfig')
|
|
31
|
+
self.logger.debug(f'config: {config}')
|
|
32
|
+
|
|
33
|
+
# Submit HTTP request and return response
|
|
34
|
+
rurl = f'{config.url}/search'
|
|
35
|
+
request = {'client': 'CHAP-FoxdenDataDiscoveryReader'}
|
|
36
|
+
if config.did is None:
|
|
37
|
+
if config.query is None:
|
|
38
|
+
query = '{}'
|
|
39
|
+
else:
|
|
40
|
+
query = config.query
|
|
41
|
+
request['service_query'] = {'query': query, 'limit': config.limit}
|
|
42
|
+
else:
|
|
43
|
+
if config.limit is not None:
|
|
44
|
+
self.logger.warning(
|
|
45
|
+
f'Ignoring parameter "limit" ({config.limit}), '
|
|
46
|
+
'when "did" is specified')
|
|
47
|
+
if config.query is not None:
|
|
48
|
+
self.logger.warning(
|
|
49
|
+
f'Ignoring parameter "query" ({config.query}), '
|
|
50
|
+
'when "did" is specified')
|
|
51
|
+
request['service_query'] = {'query': f'did:{config.did}'}
|
|
52
|
+
payload = json.dumps(request)
|
|
53
|
+
self.logger.info(f'method=POST url={rurl} payload={payload}')
|
|
54
|
+
response = HttpRequest(rurl, payload, method='POST', scope='read')
|
|
55
|
+
if config.verbose:
|
|
56
|
+
self.logger.info(
|
|
57
|
+
f'code={response.status_code} data={response.text}')
|
|
58
|
+
if response.status_code == 200:
|
|
59
|
+
result = json.loads(response.text)['results']['records']
|
|
60
|
+
else:
|
|
61
|
+
self.logger.warning(f'HTTP error code {response.status_code}')
|
|
62
|
+
result = []
|
|
63
|
+
self.logger.debug(f'Returning {len(result)} records')
|
|
64
|
+
return result
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class FoxdenMetadataReader(PipelineItem):
|
|
68
|
+
"""Reader for the FOXDEN Metadata service."""
|
|
69
|
+
def read(self, config):
|
|
70
|
+
"""Read records from the FOXDEN Metadata service based on did
|
|
71
|
+
or an arbitrary query.
|
|
72
|
+
|
|
73
|
+
:param config: FOXDEN HTTP request configuration.
|
|
74
|
+
:type config: CHAP.foxden.models.FoxdenRequestConfig
|
|
75
|
+
:return: Metadata records.
|
|
76
|
+
:rtype: list
|
|
77
|
+
"""
|
|
78
|
+
# Load and validate the FoxdenRequestConfig configuration
|
|
79
|
+
config = self.get_config(
|
|
80
|
+
config=config, schema='foxden.models.FoxdenRequestConfig')
|
|
81
|
+
self.logger.debug(f'config: {config}')
|
|
82
|
+
|
|
83
|
+
# Submit HTTP request and return response
|
|
84
|
+
rurl = f'{config.url}/search'
|
|
85
|
+
request = {'client': 'CHAP-FoxdenMetadataReader'}
|
|
86
|
+
if config.did is None:
|
|
87
|
+
if config.query is None:
|
|
88
|
+
query = '{}'
|
|
89
|
+
else:
|
|
90
|
+
query = config.query
|
|
91
|
+
request['service_query'] = {'query': query}
|
|
92
|
+
else:
|
|
93
|
+
if config.query is not None:
|
|
94
|
+
self.logger.warning(
|
|
95
|
+
f'Ignoring parameter "query" ({config.query}), '
|
|
96
|
+
'when "did" is specified')
|
|
97
|
+
request['service_query'] = {'query': f'did:{config.did}'}
|
|
98
|
+
payload = json.dumps(request)
|
|
99
|
+
self.logger.info(f'method=POST url={rurl} payload={payload}')
|
|
100
|
+
response = HttpRequest(rurl, payload, method='POST', scope='read')
|
|
101
|
+
if config.verbose:
|
|
102
|
+
self.logger.info(
|
|
103
|
+
f'code={response.status_code} data={response.text}')
|
|
104
|
+
if response.status_code == 200:
|
|
105
|
+
result = json.loads(response.text)
|
|
106
|
+
else:
|
|
107
|
+
self.logger.warning(f'HTTP error code {response.status_code}')
|
|
108
|
+
result = []
|
|
109
|
+
self.logger.debug(f'Returning {len(result)} records')
|
|
110
|
+
return result
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class FoxdenProvenanceReader(PipelineItem):
|
|
114
|
+
"""Reader for FOXDEN Provenance data from a specific FOXDEN
|
|
115
|
+
Provenance service.
|
|
116
|
+
"""
|
|
117
|
+
def read(self, config):
|
|
118
|
+
"""Read records from the FOXDEN Provenance service based on did
|
|
119
|
+
or an arbitrary query.
|
|
120
|
+
|
|
121
|
+
:param config: FOXDEN HTTP request configuration.
|
|
122
|
+
:type config: CHAP.foxden.models.FoxdenRequestConfig
|
|
123
|
+
:return: Provenance input and output file records.
|
|
124
|
+
:rtype: list
|
|
125
|
+
"""
|
|
126
|
+
# Load and validate the FoxdenRequestConfig configuration
|
|
127
|
+
config = self.get_config(
|
|
128
|
+
config=config, schema='foxden.models.FoxdenRequestConfig')
|
|
129
|
+
self.logger.debug(f'config: {config}')
|
|
130
|
+
|
|
131
|
+
# Submit HTTP request and return response
|
|
132
|
+
rurl = f'{config.url}/files?did={config.did}'
|
|
133
|
+
request = {'client': 'CHAP-FoxdenProvenanceReader'}
|
|
134
|
+
if config.did is None:
|
|
135
|
+
if config.query is None:
|
|
136
|
+
query = '{}'
|
|
137
|
+
else:
|
|
138
|
+
query = config.query
|
|
139
|
+
request['service_query'] = {'query': query, 'limit': config.limit}
|
|
140
|
+
else:
|
|
141
|
+
if config.limit is not None:
|
|
142
|
+
self.logger.warning(
|
|
143
|
+
f'Ignoring parameter "limit" ({config.limit}), '
|
|
144
|
+
'when "did" is specified')
|
|
145
|
+
if config.query is not None:
|
|
146
|
+
self.logger.warning(
|
|
147
|
+
f'Ignoring parameter "query" ({config.query}), '
|
|
148
|
+
'when "did" is specified')
|
|
149
|
+
request['service_query'] = {'query': f'did:{config.did}'}
|
|
150
|
+
payload = json.dumps(request)
|
|
151
|
+
self.logger.info(f'method=GET url={rurl} payload={payload}')
|
|
152
|
+
response = HttpRequest(rurl, payload, method='GET', scope='read')
|
|
153
|
+
exit(f'\n\nresponse.text:\n{response.text}')
|
|
154
|
+
if config.verbose:
|
|
155
|
+
self.logger.info(
|
|
156
|
+
f'code={response.status_code} data={response.text}')
|
|
157
|
+
if response.status_code == 200:
|
|
158
|
+
result = [{'name': v['name'], 'file_type': v['file_type']}
|
|
159
|
+
for v in json.loads(response.text)]
|
|
160
|
+
else:
|
|
161
|
+
self.logger.warning(f'HTTP error code {response.status_code}')
|
|
162
|
+
result = []
|
|
163
|
+
self.logger.debug(f'Returning {len(result)} records')
|
|
164
|
+
return result
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class FoxdenSpecScansReader(PipelineItem):
|
|
168
|
+
"""Reader for FOXDEN SpecScans data from a specific FOXDEN
|
|
169
|
+
SpecScans service.
|
|
170
|
+
"""
|
|
171
|
+
def read(
|
|
172
|
+
self, url, data, did='', query='', spec=None, method='POST', # 'GET',
|
|
173
|
+
verbose=False):
|
|
174
|
+
# TODO FIX
|
|
175
|
+
"""Read and return data from a specific FOXDEN SpecScans
|
|
176
|
+
service.
|
|
177
|
+
|
|
178
|
+
:param url: URL of service.
|
|
179
|
+
:type url: str
|
|
180
|
+
:param data: Input data.
|
|
181
|
+
:type data: list[PipelineData]
|
|
182
|
+
:param did: FOXDEN dataset identifier (did).
|
|
183
|
+
:type did: string, optional
|
|
184
|
+
:param query: FOXDEN query.
|
|
185
|
+
:type query: string, optional
|
|
186
|
+
:param spec: FOXDEN spec.
|
|
187
|
+
:type spec: dictionary, optional
|
|
188
|
+
:param method: HTTP method to use, `'POST'` for creation or
|
|
189
|
+
`'PUT'` for update, defaults to `'POST'`.
|
|
190
|
+
:type method: str, optional
|
|
191
|
+
:param verbose: Verbose output flag, defaults to `False`.
|
|
192
|
+
:type verbose: bool, optional
|
|
193
|
+
:return: Contents of the input data.
|
|
194
|
+
:rtype: object
|
|
195
|
+
"""
|
|
196
|
+
self.logger.info(
|
|
197
|
+
f'Executing "process" with url={url} data={data} did={did}')
|
|
198
|
+
rurl = f'{url}/search'
|
|
199
|
+
request = {'client': 'CHAP-FoxdenSpecScansReader', 'service_query': {}}
|
|
200
|
+
if did:
|
|
201
|
+
request['service_query'].update({'spec': {'did': did}})
|
|
202
|
+
if query:
|
|
203
|
+
request['service_query'].update({'query': query})
|
|
204
|
+
if spec:
|
|
205
|
+
request['service_query'].update({'spec': spec})
|
|
206
|
+
payload = json.dumps(request)
|
|
207
|
+
if verbose:
|
|
208
|
+
self.logger.info(f'method={method} url={rurl} payload={payload}')
|
|
209
|
+
response = HttpRequest(rurl, payload, method=method)
|
|
210
|
+
if verbose:
|
|
211
|
+
self.logger.info(
|
|
212
|
+
f'code={response.status_code} data={response.text}')
|
|
213
|
+
if response.status_code == 200:
|
|
214
|
+
data = json.loads(response.text)
|
|
215
|
+
else:
|
|
216
|
+
data = []
|
|
217
|
+
return data
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
if __name__ == '__main__':
|
|
221
|
+
# Local modules
|
|
222
|
+
from CHAP.reader import main
|
|
223
|
+
|
|
224
|
+
main()
|
CHAP/foxden/utils.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""FOXDEN utils module."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def readFoxdenToken(scope):
|
|
5
|
+
"""Obtain a FOXDEN token.
|
|
6
|
+
|
|
7
|
+
:param scope: FOXDEN scope: `'read'` or `'write'`.
|
|
8
|
+
:type scope: string
|
|
9
|
+
"""
|
|
10
|
+
# System modules
|
|
11
|
+
import os
|
|
12
|
+
|
|
13
|
+
token = os.getenv(f'FOXDEN_{scope.upper()}_TOKEN')
|
|
14
|
+
if not token:
|
|
15
|
+
token_file = os.path.join(
|
|
16
|
+
os.getenv('HOME'), f'.foxden.{scope.lower()}.token')
|
|
17
|
+
if os.path.exists(token_file):
|
|
18
|
+
with open(token_file, 'r') as f:
|
|
19
|
+
token = f.read()
|
|
20
|
+
return token
|
|
21
|
+
|
|
22
|
+
def HttpRequest(
|
|
23
|
+
url, payload, method='POST', headers=None, scope='read', timeout=10,
|
|
24
|
+
dry_run=False):
|
|
25
|
+
"""Submit a HTTP request to a FOXDEN service
|
|
26
|
+
|
|
27
|
+
:param url: URL of service.
|
|
28
|
+
:type url: str
|
|
29
|
+
:param payload: HTTP request payload.
|
|
30
|
+
:type payload: str
|
|
31
|
+
:param method: HTTP method to use, defaults to `'POST'`.
|
|
32
|
+
:type method: str, optional
|
|
33
|
+
:param headers: HTTP headers to use.
|
|
34
|
+
:type headers: dictionary, optional
|
|
35
|
+
:param scope: FOXDEN scope: `'read'` or `'write'`,
|
|
36
|
+
defaults to `'read'`.
|
|
37
|
+
:type scope: string, optional
|
|
38
|
+
:param timeout: Timeout of HTTP request, defaults to `10`.
|
|
39
|
+
:type timeout: str, optional
|
|
40
|
+
:param dry_run: `dry_run` option to verify HTTP workflow,
|
|
41
|
+
defaults to `False`.
|
|
42
|
+
:type dry_run: bool, optional
|
|
43
|
+
:return: HTTP response.
|
|
44
|
+
:rtype: requests.models.Response
|
|
45
|
+
"""
|
|
46
|
+
# Third party modules
|
|
47
|
+
from requests import (
|
|
48
|
+
get,
|
|
49
|
+
post,
|
|
50
|
+
put,
|
|
51
|
+
delete,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if headers is None:
|
|
55
|
+
headers = {}
|
|
56
|
+
if 'Content-Type' not in headers:
|
|
57
|
+
headers['Content-type'] = 'application/json'
|
|
58
|
+
if 'Accept' not in headers:
|
|
59
|
+
headers['Accept'] = 'application/json'
|
|
60
|
+
token = readFoxdenToken(scope)
|
|
61
|
+
if token:
|
|
62
|
+
headers['Authorization'] = f'Bearer {token}'
|
|
63
|
+
else:
|
|
64
|
+
raise RuntimeError(f'Unable to obtain token with scope {scope}')
|
|
65
|
+
if dry_run:
|
|
66
|
+
print('### HTTP reader call', url, headers, payload)
|
|
67
|
+
return []
|
|
68
|
+
|
|
69
|
+
# Make actual HTTP request to FOXDEN service
|
|
70
|
+
if method.lower() == 'get':
|
|
71
|
+
response = get(url, headers=headers, timeout=timeout)
|
|
72
|
+
elif method.lower() == 'post':
|
|
73
|
+
response = post(url, headers=headers, timeout=timeout, data=payload)
|
|
74
|
+
elif method.lower() == 'put':
|
|
75
|
+
response = put(url, headers=headers, timeout=timeout, data=payload)
|
|
76
|
+
elif method.lower() == 'delete':
|
|
77
|
+
response = delete(url, headers=headers, timeout=timeout, data=payload)
|
|
78
|
+
else:
|
|
79
|
+
raise ValueError(f'Unsupported method {method}')
|
|
80
|
+
return response
|