hapiclient 0.2.6__tar.gz → 0.2.8__tar.gz
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.
- {hapiclient-0.2.6 → hapiclient-0.2.8}/CHANGES.txt +18 -2
- {hapiclient-0.2.6 → hapiclient-0.2.8}/PKG-INFO +59 -7
- hapiclient-0.2.6/hapiclient.egg-info/PKG-INFO → hapiclient-0.2.8/README.md +43 -16
- {hapiclient-0.2.6 → hapiclient-0.2.8}/hapiclient/__init__.py +10 -1
- hapiclient-0.2.8/hapiclient/cache.py +255 -0
- hapiclient-0.2.8/hapiclient/capabilities.py +42 -0
- hapiclient-0.2.8/hapiclient/catalog.py +10 -0
- hapiclient-0.2.8/hapiclient/data.py +271 -0
- hapiclient-0.2.8/hapiclient/get.py +408 -0
- hapiclient-0.2.8/hapiclient/hapi.py +255 -0
- {hapiclient-0.2.6 → hapiclient-0.2.8}/hapiclient/hapitime.py +49 -63
- hapiclient-0.2.8/hapiclient/info.py +26 -0
- hapiclient-0.2.8/hapiclient/log.py +51 -0
- hapiclient-0.2.8/hapiclient/servers.py +16 -0
- {hapiclient-0.2.6 → hapiclient-0.2.8}/hapiclient/util.py +143 -140
- hapiclient-0.2.6/README.md → hapiclient-0.2.8/hapiclient.egg-info/PKG-INFO +68 -5
- hapiclient-0.2.8/hapiclient.egg-info/SOURCES.txt +29 -0
- {hapiclient-0.2.6 → hapiclient-0.2.8}/setup.py +6 -3
- {hapiclient-0.2.6/hapiclient → hapiclient-0.2.8}/test/test_chunking.py +86 -58
- hapiclient-0.2.8/test/test_datetime2hapitime.py +32 -0
- hapiclient-0.2.8/test/test_hapi_data_requests.py +224 -0
- hapiclient-0.2.8/test/test_hapi_metadata_requests.py +152 -0
- hapiclient-0.2.8/test/test_hapitime2datetime.py +102 -0
- hapiclient-0.2.8/test/test_hapitime_reformat.py +83 -0
- hapiclient-0.2.8/test/test_logging.py +137 -0
- hapiclient-0.2.6/hapiclient/hapi.py +0 -1060
- hapiclient-0.2.6/hapiclient/test/__init__.py +0 -0
- hapiclient-0.2.6/hapiclient/test/compare.py +0 -240
- hapiclient-0.2.6/hapiclient/test/test_datetime2hapitime.py +0 -17
- hapiclient-0.2.6/hapiclient/test/test_hapi.py +0 -340
- hapiclient-0.2.6/hapiclient/test/test_hapitime2datetime.py +0 -124
- hapiclient-0.2.6/hapiclient/test/test_hapitime_reformat.py +0 -79
- hapiclient-0.2.6/hapiclient.egg-info/SOURCES.txt +0 -21
- {hapiclient-0.2.6 → hapiclient-0.2.8}/LICENSE.txt +0 -0
- {hapiclient-0.2.6 → hapiclient-0.2.8}/MANIFEST.in +0 -0
- {hapiclient-0.2.6 → hapiclient-0.2.8}/hapiclient.egg-info/dependency_links.txt +0 -0
- {hapiclient-0.2.6 → hapiclient-0.2.8}/hapiclient.egg-info/requires.txt +1 -1
- {hapiclient-0.2.6 → hapiclient-0.2.8}/hapiclient.egg-info/top_level.txt +0 -0
- {hapiclient-0.2.6 → hapiclient-0.2.8}/setup.cfg +0 -0
|
@@ -10,7 +10,7 @@ v0.0.6:
|
|
|
10
10
|
2018-10-04 -- Improve dateticks.py
|
|
11
11
|
2018-10-04 -- Add hapi_demo.ipynb
|
|
12
12
|
2018-10-04 -- Other documentation improvements
|
|
13
|
-
v0.0.7:
|
|
13
|
+
v0.0.7:
|
|
14
14
|
2018-10-06 -- Improve documentation
|
|
15
15
|
2018-10-06 -- Add reader tests
|
|
16
16
|
2018-10-23 -- Improve dateticks and tests
|
|
@@ -103,4 +103,20 @@ v0.2.6b1:
|
|
|
103
103
|
2023-02-04 -- 2ef7cff Unicode fix; Log string fix
|
|
104
104
|
2024-05-11 -- fba4ad3 Testing Updates
|
|
105
105
|
v0.2.6:
|
|
106
|
-
|
|
106
|
+
2023-05-24 -- Use token for PyPi in Makefile
|
|
107
|
+
v0.2.7b1:
|
|
108
|
+
2025-03-01 -- Unrecognized ISO 8601 time format: '00:00:00.Z' https://github.com/hapi-server/client-python/issues/76
|
|
109
|
+
2025-03-01 -- 'infer_datetime_format' is deprecated ... https://github.com/hapi-server/client-python/issues/78
|
|
110
|
+
2026-04-08 -- Improve NaN handling https://github.com/hapi-server/client-python/issues/88
|
|
111
|
+
2026-05-02 -- Logging and testing https://github.com/hapi-server/client-python/issues/89
|
|
112
|
+
v0.2.7:
|
|
113
|
+
2026-05-02 -- Support for Python 2.7 dropped. This is last release with support for 3.5 through 3.8.
|
|
114
|
+
v0.2.8b0:
|
|
115
|
+
2026-05-02 -- Documentation
|
|
116
|
+
v0.2.8b1:
|
|
117
|
+
2026-05-02 -- Versioning updates
|
|
118
|
+
2026-05-19 -- Better response error messages
|
|
119
|
+
v0.2.8b2:
|
|
120
|
+
2026-05-20 -- Refactor
|
|
121
|
+
v0.2.8:
|
|
122
|
+
2026-06-04 -- Compat. fixes for hapiplot package.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: hapiclient
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: Interface to Heliophysics data server API
|
|
5
5
|
Home-page: http://pypi.python.org/pypi/hapiclient/
|
|
6
6
|
Author: Bob Weigel
|
|
@@ -8,13 +8,29 @@ Author-email: rweigel@gmu.edu
|
|
|
8
8
|
License: LICENSE.txt
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE.txt
|
|
11
|
+
Requires-Dist: urllib3
|
|
12
|
+
Requires-Dist: joblib
|
|
13
|
+
Requires-Dist: isodate>=0.6.0
|
|
14
|
+
Requires-Dist: pandas>=0.23
|
|
15
|
+
Requires-Dist: numpy>=1.14.3
|
|
16
|
+
Dynamic: author
|
|
17
|
+
Dynamic: author-email
|
|
18
|
+
Dynamic: description
|
|
19
|
+
Dynamic: description-content-type
|
|
20
|
+
Dynamic: home-page
|
|
21
|
+
Dynamic: license
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
Dynamic: requires-dist
|
|
24
|
+
Dynamic: summary
|
|
11
25
|
|
|
12
26
|
[](https://zenodo.org/badge/latestdoi/93170857)
|
|
13
27
|
[](https://app.travis-ci.com/hapi-server/client-python)
|
|
14
28
|
|
|
15
29
|
**HAPI Client for Python**
|
|
16
30
|
|
|
17
|
-
Basic usage examples for various HAPI servers are given in [hapi_demo.py](https://github.com/hapi-server/client-python/blob/master/hapi_demo.py)
|
|
31
|
+
Basic usage examples for various HAPI servers are given in [hapi_demo.py](https://github.com/hapi-server/client-python/blob/master/hapi_demo.py). See also
|
|
32
|
+
* Examples section of a Jupyter Notebook hosted on Google Colab: [](https://colab.research.google.com/github/hapi-server/client-python-notebooks/blob/master/hapi_demo.ipynb#examples).
|
|
33
|
+
* [PyHC Summer School tutorials](https://github.com/hapi-server/tutorial-python)
|
|
18
34
|
|
|
19
35
|
# Installation
|
|
20
36
|
|
|
@@ -50,6 +66,7 @@ start = '2003-09-01T00:00:00'
|
|
|
50
66
|
stop = '2003-12-01T00:00:00'
|
|
51
67
|
parameters = 'DST1800'
|
|
52
68
|
opts = {'logging': True}
|
|
69
|
+
# See misc/hapi_logging_demo.py for example of using conventional Python logging.
|
|
53
70
|
|
|
54
71
|
# Get data
|
|
55
72
|
data, meta = hapi(server, dataset, parameters, start, stop, **opts)
|
|
@@ -92,7 +109,41 @@ returns the [Numpy N-D array](https://docs.scipy.org/doc/numpy-1.15.1/user/quick
|
|
|
92
109
|
|
|
93
110
|
The HAPI client data model is intentionally basic. There is an ongoing discussion of a data model for Heliophysics data among the [PyHC community](https://heliopython.org/). When this data model is complete, a function that converts `data` and `meta` to that data model will be included in the `hapiclient` package.
|
|
94
111
|
|
|
95
|
-
# Development
|
|
112
|
+
# Development and Testing
|
|
113
|
+
|
|
114
|
+
## Testing Python versions available with tox-env
|
|
115
|
+
|
|
116
|
+
As of 2026-04-14, Python 3.8+ is available with tox-env.
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
git clone https://github.com/hapi-server/client-python
|
|
120
|
+
cd client-python; python -m pip install -e .
|
|
121
|
+
|
|
122
|
+
# Run a specific test on current Python version (default is log_level=INFO
|
|
123
|
+
# for hapiclient logger and test logger when executed this way).
|
|
124
|
+
python test/test_hapi_data_requests.py
|
|
125
|
+
|
|
126
|
+
# Run a specific test on a specific Python version with all logging
|
|
127
|
+
tox -e py311 -- test/test_hapi_data_requests.py
|
|
128
|
+
# Set log level for test logger
|
|
129
|
+
tox -e py311 -- test/test_hapi_data_requests.py --log-level=INFO
|
|
130
|
+
|
|
131
|
+
# Run a specific test on all Python versions set by tox.ini `envlist`
|
|
132
|
+
tox -- test/test_hapi_data_requests.py
|
|
133
|
+
|
|
134
|
+
# Run all tests in ./test
|
|
135
|
+
tox
|
|
136
|
+
|
|
137
|
+
# Run long-running tests
|
|
138
|
+
tox -e long-test
|
|
139
|
+
|
|
140
|
+
# Run long-running tests on a specific Python version
|
|
141
|
+
tox -e long-test --override testenv:long-test.basepython=python3.11
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Testing Python versions available with Anaconda
|
|
145
|
+
|
|
146
|
+
As of 2026-04-14, Python 3.5+ is available with Anaconda.
|
|
96
147
|
|
|
97
148
|
```bash
|
|
98
149
|
git clone https://github.com/hapi-server/client-python
|
|
@@ -117,12 +168,13 @@ make repository-test
|
|
|
117
168
|
|
|
118
169
|
To run an individual unit test in a Python session, use, e.g.,
|
|
119
170
|
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
test_reader_short()
|
|
171
|
+
```bash
|
|
172
|
+
cd test; python test_hapitime_reformat.py
|
|
123
173
|
```
|
|
124
174
|
|
|
125
175
|
# Contact
|
|
126
176
|
|
|
127
177
|
Submit bug reports and feature requests on the [repository issue
|
|
128
178
|
tracker](https://github.com/hapi-server/client-python/issues>).
|
|
179
|
+
|
|
180
|
+
Before submitting a pull request, please post an issue with the proposed changes for discussion prior to developing the pull request.
|
|
@@ -1,20 +1,11 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: hapiclient
|
|
3
|
-
Version: 0.2.6
|
|
4
|
-
Summary: Interface to Heliophysics data server API
|
|
5
|
-
Home-page: http://pypi.python.org/pypi/hapiclient/
|
|
6
|
-
Author: Bob Weigel
|
|
7
|
-
Author-email: rweigel@gmu.edu
|
|
8
|
-
License: LICENSE.txt
|
|
9
|
-
Description-Content-Type: text/markdown
|
|
10
|
-
License-File: LICENSE.txt
|
|
11
|
-
|
|
12
1
|
[](https://zenodo.org/badge/latestdoi/93170857)
|
|
13
2
|
[](https://app.travis-ci.com/hapi-server/client-python)
|
|
14
3
|
|
|
15
4
|
**HAPI Client for Python**
|
|
16
5
|
|
|
17
|
-
Basic usage examples for various HAPI servers are given in [hapi_demo.py](https://github.com/hapi-server/client-python/blob/master/hapi_demo.py)
|
|
6
|
+
Basic usage examples for various HAPI servers are given in [hapi_demo.py](https://github.com/hapi-server/client-python/blob/master/hapi_demo.py). See also
|
|
7
|
+
* Examples section of a Jupyter Notebook hosted on Google Colab: [](https://colab.research.google.com/github/hapi-server/client-python-notebooks/blob/master/hapi_demo.ipynb#examples).
|
|
8
|
+
* [PyHC Summer School tutorials](https://github.com/hapi-server/tutorial-python)
|
|
18
9
|
|
|
19
10
|
# Installation
|
|
20
11
|
|
|
@@ -50,6 +41,7 @@ start = '2003-09-01T00:00:00'
|
|
|
50
41
|
stop = '2003-12-01T00:00:00'
|
|
51
42
|
parameters = 'DST1800'
|
|
52
43
|
opts = {'logging': True}
|
|
44
|
+
# See misc/hapi_logging_demo.py for example of using conventional Python logging.
|
|
53
45
|
|
|
54
46
|
# Get data
|
|
55
47
|
data, meta = hapi(server, dataset, parameters, start, stop, **opts)
|
|
@@ -92,7 +84,41 @@ returns the [Numpy N-D array](https://docs.scipy.org/doc/numpy-1.15.1/user/quick
|
|
|
92
84
|
|
|
93
85
|
The HAPI client data model is intentionally basic. There is an ongoing discussion of a data model for Heliophysics data among the [PyHC community](https://heliopython.org/). When this data model is complete, a function that converts `data` and `meta` to that data model will be included in the `hapiclient` package.
|
|
94
86
|
|
|
95
|
-
# Development
|
|
87
|
+
# Development and Testing
|
|
88
|
+
|
|
89
|
+
## Testing Python versions available with tox-env
|
|
90
|
+
|
|
91
|
+
As of 2026-04-14, Python 3.8+ is available with tox-env.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
git clone https://github.com/hapi-server/client-python
|
|
95
|
+
cd client-python; python -m pip install -e .
|
|
96
|
+
|
|
97
|
+
# Run a specific test on current Python version (default is log_level=INFO
|
|
98
|
+
# for hapiclient logger and test logger when executed this way).
|
|
99
|
+
python test/test_hapi_data_requests.py
|
|
100
|
+
|
|
101
|
+
# Run a specific test on a specific Python version with all logging
|
|
102
|
+
tox -e py311 -- test/test_hapi_data_requests.py
|
|
103
|
+
# Set log level for test logger
|
|
104
|
+
tox -e py311 -- test/test_hapi_data_requests.py --log-level=INFO
|
|
105
|
+
|
|
106
|
+
# Run a specific test on all Python versions set by tox.ini `envlist`
|
|
107
|
+
tox -- test/test_hapi_data_requests.py
|
|
108
|
+
|
|
109
|
+
# Run all tests in ./test
|
|
110
|
+
tox
|
|
111
|
+
|
|
112
|
+
# Run long-running tests
|
|
113
|
+
tox -e long-test
|
|
114
|
+
|
|
115
|
+
# Run long-running tests on a specific Python version
|
|
116
|
+
tox -e long-test --override testenv:long-test.basepython=python3.11
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Testing Python versions available with Anaconda
|
|
120
|
+
|
|
121
|
+
As of 2026-04-14, Python 3.5+ is available with Anaconda.
|
|
96
122
|
|
|
97
123
|
```bash
|
|
98
124
|
git clone https://github.com/hapi-server/client-python
|
|
@@ -117,12 +143,13 @@ make repository-test
|
|
|
117
143
|
|
|
118
144
|
To run an individual unit test in a Python session, use, e.g.,
|
|
119
145
|
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
test_reader_short()
|
|
146
|
+
```bash
|
|
147
|
+
cd test; python test_hapitime_reformat.py
|
|
123
148
|
```
|
|
124
149
|
|
|
125
150
|
# Contact
|
|
126
151
|
|
|
127
152
|
Submit bug reports and feature requests on the [repository issue
|
|
128
153
|
tracker](https://github.com/hapi-server/client-python/issues>).
|
|
154
|
+
|
|
155
|
+
Before submitting a pull request, please post an issue with the proposed changes for discussion prior to developing the pull request.
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# Allow "from hapiclient import hapi"
|
|
2
2
|
from hapiclient.hapi import hapi
|
|
3
3
|
|
|
4
|
+
# Allow "from hapiclient import request2path"
|
|
5
|
+
from hapiclient.hapi import request2path
|
|
6
|
+
|
|
4
7
|
# Allow "from hapiclient import hapitime2datetime"
|
|
5
8
|
from hapiclient.hapitime import hapitime2datetime
|
|
6
9
|
|
|
@@ -10,9 +13,15 @@ from hapiclient.hapitime import datetime2hapitime
|
|
|
10
13
|
# Allow "from hapiclient import HAPIError"
|
|
11
14
|
from hapiclient.util import HAPIError
|
|
12
15
|
|
|
13
|
-
__version__ = '0.2.
|
|
16
|
+
__version__ = '0.2.8'
|
|
14
17
|
|
|
15
18
|
import sys
|
|
19
|
+
import platform
|
|
20
|
+
|
|
21
|
+
if sys.version_info < (3, 10) and platform.system() == "Darwin":
|
|
22
|
+
import warnings
|
|
23
|
+
warnings.filterwarnings("ignore", message=".*urllib3.*OpenSSL.*")
|
|
24
|
+
|
|
16
25
|
if sys.version_info[0] < 3:
|
|
17
26
|
# Python 2.7
|
|
18
27
|
reload(sys)
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
def server2dirname(server):
|
|
2
|
+
"""Convert a server URL to a directory name."""
|
|
3
|
+
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
urld = re.sub(r"https*://", "", server)
|
|
7
|
+
urld = re.sub(r'/', '_', urld)
|
|
8
|
+
|
|
9
|
+
return urld
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def cachedir(*args):
|
|
13
|
+
"""HAPI cache directory.
|
|
14
|
+
|
|
15
|
+
cachedir() returns os.path.join(tempfile.gettempdir(), 'hapi-data')
|
|
16
|
+
|
|
17
|
+
cachedir(basedir, server) returns os.path.join(basedir, server2dirname(server))
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import os
|
|
21
|
+
import tempfile
|
|
22
|
+
|
|
23
|
+
if len(args) != 0 and len(args) != 2:
|
|
24
|
+
raise ValueError('cachedir() takes either 0 or 2 arguments.')
|
|
25
|
+
|
|
26
|
+
if len(args) == 0:
|
|
27
|
+
# cachedir()
|
|
28
|
+
return os.path.join(tempfile.gettempdir(), 'hapi-data')
|
|
29
|
+
|
|
30
|
+
if len(args) == 2:
|
|
31
|
+
# cachedir(base_dir, server)
|
|
32
|
+
return os.path.join(args[0], server2dirname(args[1]))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def request2path(*args):
|
|
36
|
+
# request2path(server, dataset, parameters, start, stop)
|
|
37
|
+
# request2path(server, dataset, parameters, start, stop, cachedir)
|
|
38
|
+
import os
|
|
39
|
+
import re
|
|
40
|
+
import platform
|
|
41
|
+
|
|
42
|
+
if len(args) == 5:
|
|
43
|
+
# Use default if cachedir not given.
|
|
44
|
+
cachedirectory = cachedir()
|
|
45
|
+
else:
|
|
46
|
+
cachedirectory = args[5]
|
|
47
|
+
|
|
48
|
+
args = list(args)
|
|
49
|
+
|
|
50
|
+
# Replace forbidden characters in directory and filename
|
|
51
|
+
# Replacements assume that there will be no name collisions,
|
|
52
|
+
# e.g., one parameter named abc-< and another abc-@lt@.
|
|
53
|
+
# This also introduces an incompatibility between caches on Windows
|
|
54
|
+
# Unix.
|
|
55
|
+
if platform.system() == 'Windows':
|
|
56
|
+
# List and code from responses in
|
|
57
|
+
# https://stackoverflow.com/q/1976007
|
|
58
|
+
reps = (
|
|
59
|
+
('<', '@lt@'),
|
|
60
|
+
('>', '@gt@'),
|
|
61
|
+
(':', '@colon@'),
|
|
62
|
+
('"', '@doublequote@'),
|
|
63
|
+
('/', '@forwardslash@'),
|
|
64
|
+
('/', '@backslash@'),
|
|
65
|
+
('\\|', '@pipe@'),
|
|
66
|
+
('\\?', '@questionmark@'),
|
|
67
|
+
('\\*', '@asterisk@')
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
for element in reps:
|
|
71
|
+
args[1] = re.sub(element[0], element[1], args[1])
|
|
72
|
+
args[2] = re.sub(element[0], element[1], args[2])
|
|
73
|
+
|
|
74
|
+
else:
|
|
75
|
+
args[1] = re.sub('/','@forwardslash@',args[1])
|
|
76
|
+
args[2] = re.sub('/','@forwardslash@',args[2])
|
|
77
|
+
|
|
78
|
+
# To shorten filenames.
|
|
79
|
+
args[3] = re.sub(r'-|:|\.|Z', '', args[3])
|
|
80
|
+
args[4] = re.sub(r'-|:|\.|Z', '', args[4])
|
|
81
|
+
|
|
82
|
+
# URL subdirectory
|
|
83
|
+
urldirectory = server2dirname(args[0])
|
|
84
|
+
fname = '%s_%s_%s_%s' % (args[1], args[2], args[3], args[4])
|
|
85
|
+
|
|
86
|
+
return os.path.join(cachedirectory, urldirectory, fname)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def meta_cache_paths(SERVER, DATASET, cachedir):
|
|
90
|
+
"""Return dict with metadata cache directory and file names."""
|
|
91
|
+
|
|
92
|
+
fname_root = request2path(SERVER, DATASET, '', '', '', cachedir)
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
'json': fname_root + '.json',
|
|
96
|
+
'pkl': fname_root + '.pkl'
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def meta_cache_read(SERVER, DATASET, opts):
|
|
101
|
+
"""Read metadata from PKL cache. Returns meta dict or None."""
|
|
102
|
+
|
|
103
|
+
import os
|
|
104
|
+
import pickle
|
|
105
|
+
|
|
106
|
+
from hapiclient.log import log
|
|
107
|
+
|
|
108
|
+
if not opts["usecache"]:
|
|
109
|
+
log('Not checking metadata cache because usecache is False.')
|
|
110
|
+
return None
|
|
111
|
+
|
|
112
|
+
fnamepkl = meta_cache_paths(SERVER, DATASET, opts['cachedir'])['pkl']
|
|
113
|
+
if os.path.isfile(fnamepkl):
|
|
114
|
+
log('Reading %s' % os.path.basename(fnamepkl))
|
|
115
|
+
with open(fnamepkl, 'rb') as f:
|
|
116
|
+
return pickle.load(f)
|
|
117
|
+
|
|
118
|
+
if opts["usecache"]:
|
|
119
|
+
log('No metadata cache file found: %s' % os.path.basename(fnamepkl))
|
|
120
|
+
|
|
121
|
+
return None
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def meta_cache_write(meta, SERVER, DATASET, opts):
|
|
125
|
+
"""Write metadata to JSON and PKL cache files."""
|
|
126
|
+
|
|
127
|
+
import os
|
|
128
|
+
import json
|
|
129
|
+
import pickle
|
|
130
|
+
|
|
131
|
+
from hapiclient.log import log
|
|
132
|
+
|
|
133
|
+
if not opts["cache"]:
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
paths = meta_cache_paths(SERVER, DATASET, opts['cachedir'])
|
|
137
|
+
fnamejson, fnamepkl = paths['json'], paths['pkl']
|
|
138
|
+
|
|
139
|
+
server_dir = cachedir(opts["cachedir"], SERVER)
|
|
140
|
+
os.makedirs(server_dir, exist_ok=True)
|
|
141
|
+
|
|
142
|
+
log('Writing %s ' % os.path.basename(fnamejson))
|
|
143
|
+
with open(fnamejson, 'w') as f:
|
|
144
|
+
json.dump(meta, f, indent=4)
|
|
145
|
+
|
|
146
|
+
log('Writing %s ' % os.path.basename(fnamepkl))
|
|
147
|
+
with open(fnamepkl, 'wb') as f:
|
|
148
|
+
# protocol=2 used for Python 2.7 compatibility.
|
|
149
|
+
pickle.dump(meta, f, protocol=2)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def data_cache_paths(SERVER, DATASET, PARAMETERS, START, STOP, cachedir):
|
|
153
|
+
"""Return dict with data cache file names."""
|
|
154
|
+
|
|
155
|
+
fname_root = request2path(SERVER, DATASET, PARAMETERS, START, STOP, cachedir)
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
'csv': fname_root + '.csv',
|
|
159
|
+
'bin': fname_root + '.bin',
|
|
160
|
+
'npy': fname_root + '.npy',
|
|
161
|
+
'pkl': fname_root + '.pkl'
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def data_cache_read_metax(SERVER, DATASET, PARAMETERS, START, STOP, opts):
|
|
166
|
+
"""Read extended request metadata from PKL cache. Returns meta dict or None."""
|
|
167
|
+
|
|
168
|
+
import os
|
|
169
|
+
import pickle
|
|
170
|
+
|
|
171
|
+
from hapiclient.log import log
|
|
172
|
+
|
|
173
|
+
if not opts["usecache"]:
|
|
174
|
+
log('Not checking data cache because usecache is False.')
|
|
175
|
+
return None
|
|
176
|
+
|
|
177
|
+
fnamepklx = data_cache_paths(SERVER, DATASET, PARAMETERS, START, STOP, opts['cachedir'])['pkl']
|
|
178
|
+
if os.path.isfile(fnamepklx):
|
|
179
|
+
log('Reading subsetted metadata cache %s' % os.path.basename(fnamepklx))
|
|
180
|
+
with open(fnamepklx, 'rb') as f:
|
|
181
|
+
return pickle.load(f)
|
|
182
|
+
if opts["usecache"]:
|
|
183
|
+
log('No subsetted metadata cache file found: %s' % os.path.basename(fnamepklx))
|
|
184
|
+
|
|
185
|
+
return None
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def data_cache_read_npy(SERVER, DATASET, PARAMETERS, START, STOP, opts):
|
|
189
|
+
"""Read cached numpy data array. Returns None if not cached."""
|
|
190
|
+
|
|
191
|
+
import os
|
|
192
|
+
import numpy as np
|
|
193
|
+
|
|
194
|
+
from hapiclient.log import log
|
|
195
|
+
|
|
196
|
+
if not opts["usecache"]:
|
|
197
|
+
return None
|
|
198
|
+
|
|
199
|
+
fnamenpy = data_cache_paths(SERVER, DATASET, PARAMETERS, START, STOP, opts['cachedir'])['npy']
|
|
200
|
+
|
|
201
|
+
if not os.path.isfile(fnamenpy):
|
|
202
|
+
return None
|
|
203
|
+
|
|
204
|
+
log('Reading %s ' % os.path.basename(fnamenpy))
|
|
205
|
+
with open(fnamenpy, 'rb') as f:
|
|
206
|
+
data = np.load(f)
|
|
207
|
+
|
|
208
|
+
return data
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def data_cache_write(data_result, meta, SERVER, DATASET, PARAMETERS, START, STOP, opts):
|
|
212
|
+
"""Write data array and extended metadata to cache files.
|
|
213
|
+
|
|
214
|
+
Also updates meta with file-related x_ fields before writing.
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
import os
|
|
218
|
+
import pickle
|
|
219
|
+
import warnings
|
|
220
|
+
import numpy as np
|
|
221
|
+
|
|
222
|
+
from hapiclient.log import log
|
|
223
|
+
|
|
224
|
+
data_paths = data_cache_paths(SERVER, DATASET, PARAMETERS, START, STOP, opts['cachedir'])
|
|
225
|
+
fnamecsv, fnamebin, fnamenpy, fnamepklx = data_paths['csv'], data_paths['bin'], data_paths['npy'], data_paths['pkl']
|
|
226
|
+
|
|
227
|
+
meta_paths = meta_cache_paths(SERVER, DATASET, opts['cachedir'])
|
|
228
|
+
fnamejson, fnamepkl = meta_paths['json'], meta_paths['pkl']
|
|
229
|
+
|
|
230
|
+
meta.update({"x_metaFileParsed": fnamepkl})
|
|
231
|
+
meta.update({"x_dataFileParsed": fnamenpy})
|
|
232
|
+
meta.update({"x_metaFile": fnamejson})
|
|
233
|
+
meta.update({"x_dataFile": fnamebin if opts['format'] == 'binary' else fnamecsv})
|
|
234
|
+
|
|
235
|
+
if not opts["cache"]:
|
|
236
|
+
# Need to return after meta is updated.
|
|
237
|
+
return
|
|
238
|
+
|
|
239
|
+
server_dir = cachedir(opts["cachedir"], SERVER)
|
|
240
|
+
os.makedirs(server_dir, exist_ok=True)
|
|
241
|
+
|
|
242
|
+
log('Writing %s' % os.path.basename(fnamepklx))
|
|
243
|
+
with open(fnamepklx, 'wb') as f:
|
|
244
|
+
pickle.dump(meta, f, protocol=2)
|
|
245
|
+
|
|
246
|
+
log('Writing %s' % os.path.basename(fnamenpy))
|
|
247
|
+
with warnings.catch_warnings():
|
|
248
|
+
# Ignore warning that occurs when saving Unicode data.
|
|
249
|
+
kwargs = {
|
|
250
|
+
'message': r"Stored array in format 3\.0.*",
|
|
251
|
+
'category': UserWarning,
|
|
252
|
+
'module': r"numpy\.lib\.format"
|
|
253
|
+
}
|
|
254
|
+
warnings.filterwarnings("ignore", **kwargs)
|
|
255
|
+
np.save(fnamenpy, data_result)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
|
|
2
|
+
def capabilities(SERVER):
|
|
3
|
+
"""Return the capabilities of a HAPI server.
|
|
4
|
+
|
|
5
|
+
Args:
|
|
6
|
+
SERVER (str): The base URL of the HAPI server.
|
|
7
|
+
|
|
8
|
+
Returns:
|
|
9
|
+
dict: A dictionary containing the capabilities of the server.
|
|
10
|
+
"""
|
|
11
|
+
from hapiclient.util import urlopen
|
|
12
|
+
|
|
13
|
+
caps = urlopen(SERVER + '/capabilities', parse_json=True)
|
|
14
|
+
|
|
15
|
+
return caps
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_format(SERVER, format):
|
|
19
|
+
"""Return the transport format to use, accounting for server capabilities.
|
|
20
|
+
|
|
21
|
+
If the requested format is not supported by the server, falls back to 'csv'
|
|
22
|
+
with a warning.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from hapiclient.util import error, warning
|
|
26
|
+
|
|
27
|
+
cformats = ['csv', 'binary'] # client formats
|
|
28
|
+
if format not in cformats:
|
|
29
|
+
msg = 'This client does not handle transport format "%s". Available options: %s'
|
|
30
|
+
error(msg % (format, ', '.join(cformats)))
|
|
31
|
+
|
|
32
|
+
if format != 'csv':
|
|
33
|
+
caps = capabilities(SERVER)
|
|
34
|
+
sformats = caps["outputFormats"] # Server formats
|
|
35
|
+
if format not in sformats:
|
|
36
|
+
msg = 'Requested transport format "%s" not avaiable from %s. Will use "csv". Available options: %s'
|
|
37
|
+
warning(msg % (format, SERVER, ', '.join(sformats)))
|
|
38
|
+
format = 'csv'
|
|
39
|
+
if 'binary' not in sformats:
|
|
40
|
+
format = 'csv'
|
|
41
|
+
|
|
42
|
+
return format
|