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.
Files changed (70) hide show
  1. CHAP/TaskManager.py +216 -0
  2. CHAP/__init__.py +27 -0
  3. CHAP/common/__init__.py +57 -0
  4. CHAP/common/models/__init__.py +8 -0
  5. CHAP/common/models/common.py +124 -0
  6. CHAP/common/models/integration.py +659 -0
  7. CHAP/common/models/map.py +1291 -0
  8. CHAP/common/processor.py +2869 -0
  9. CHAP/common/reader.py +658 -0
  10. CHAP/common/utils.py +110 -0
  11. CHAP/common/writer.py +730 -0
  12. CHAP/edd/__init__.py +23 -0
  13. CHAP/edd/models.py +876 -0
  14. CHAP/edd/processor.py +3069 -0
  15. CHAP/edd/reader.py +1023 -0
  16. CHAP/edd/select_material_params_gui.py +348 -0
  17. CHAP/edd/utils.py +1572 -0
  18. CHAP/edd/writer.py +26 -0
  19. CHAP/foxden/__init__.py +19 -0
  20. CHAP/foxden/models.py +71 -0
  21. CHAP/foxden/processor.py +124 -0
  22. CHAP/foxden/reader.py +224 -0
  23. CHAP/foxden/utils.py +80 -0
  24. CHAP/foxden/writer.py +168 -0
  25. CHAP/giwaxs/__init__.py +11 -0
  26. CHAP/giwaxs/models.py +491 -0
  27. CHAP/giwaxs/processor.py +776 -0
  28. CHAP/giwaxs/reader.py +8 -0
  29. CHAP/giwaxs/writer.py +8 -0
  30. CHAP/inference/__init__.py +7 -0
  31. CHAP/inference/processor.py +69 -0
  32. CHAP/inference/reader.py +8 -0
  33. CHAP/inference/writer.py +8 -0
  34. CHAP/models.py +227 -0
  35. CHAP/pipeline.py +479 -0
  36. CHAP/processor.py +125 -0
  37. CHAP/reader.py +124 -0
  38. CHAP/runner.py +277 -0
  39. CHAP/saxswaxs/__init__.py +7 -0
  40. CHAP/saxswaxs/processor.py +8 -0
  41. CHAP/saxswaxs/reader.py +8 -0
  42. CHAP/saxswaxs/writer.py +8 -0
  43. CHAP/server.py +125 -0
  44. CHAP/sin2psi/__init__.py +7 -0
  45. CHAP/sin2psi/processor.py +8 -0
  46. CHAP/sin2psi/reader.py +8 -0
  47. CHAP/sin2psi/writer.py +8 -0
  48. CHAP/tomo/__init__.py +15 -0
  49. CHAP/tomo/models.py +210 -0
  50. CHAP/tomo/processor.py +3862 -0
  51. CHAP/tomo/reader.py +9 -0
  52. CHAP/tomo/writer.py +59 -0
  53. CHAP/utils/__init__.py +6 -0
  54. CHAP/utils/converters.py +188 -0
  55. CHAP/utils/fit.py +2947 -0
  56. CHAP/utils/general.py +2655 -0
  57. CHAP/utils/material.py +274 -0
  58. CHAP/utils/models.py +595 -0
  59. CHAP/utils/parfile.py +224 -0
  60. CHAP/writer.py +122 -0
  61. MLaaS/__init__.py +0 -0
  62. MLaaS/ktrain.py +205 -0
  63. MLaaS/mnist_img.py +83 -0
  64. MLaaS/tfaas_client.py +371 -0
  65. chessanalysispipeline-0.0.17.dev3.dist-info/LICENSE +60 -0
  66. chessanalysispipeline-0.0.17.dev3.dist-info/METADATA +29 -0
  67. chessanalysispipeline-0.0.17.dev3.dist-info/RECORD +70 -0
  68. chessanalysispipeline-0.0.17.dev3.dist-info/WHEEL +5 -0
  69. chessanalysispipeline-0.0.17.dev3.dist-info/entry_points.txt +2 -0
  70. 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()
@@ -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
@@ -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