cdasws 1.8.2__tar.gz → 1.8.3__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.
- {cdasws-1.8.2 → cdasws-1.8.3}/PKG-INFO +1 -1
- {cdasws-1.8.2 → cdasws-1.8.3}/cdasws/__init__.py +429 -85
- {cdasws-1.8.2 → cdasws-1.8.3}/cdasws/datarequest.py +4 -2
- {cdasws-1.8.2 → cdasws-1.8.3}/cdasws.egg-info/PKG-INFO +1 -1
- {cdasws-1.8.2 → cdasws-1.8.3}/setup.py +2 -1
- {cdasws-1.8.2 → cdasws-1.8.3}/README.md +0 -0
- {cdasws-1.8.2 → cdasws-1.8.3}/cdasws/__main__.py +0 -0
- {cdasws-1.8.2 → cdasws-1.8.3}/cdasws/datarepresentation.py +0 -0
- {cdasws-1.8.2 → cdasws-1.8.3}/cdasws/timeinterval.py +0 -0
- {cdasws-1.8.2 → cdasws-1.8.3}/cdasws.egg-info/SOURCES.txt +0 -0
- {cdasws-1.8.2 → cdasws-1.8.3}/cdasws.egg-info/dependency_links.txt +0 -0
- {cdasws-1.8.2 → cdasws-1.8.3}/cdasws.egg-info/requires.txt +0 -0
- {cdasws-1.8.2 → cdasws-1.8.3}/cdasws.egg-info/top_level.txt +0 -0
- {cdasws-1.8.2 → cdasws-1.8.3}/setup.cfg +0 -0
|
@@ -60,12 +60,14 @@ import os
|
|
|
60
60
|
import platform
|
|
61
61
|
import logging
|
|
62
62
|
import re
|
|
63
|
+
from importlib.util import find_spec
|
|
63
64
|
import urllib.parse
|
|
64
65
|
from urllib.parse import urlparse
|
|
65
66
|
import json
|
|
66
67
|
from operator import itemgetter
|
|
67
68
|
import time
|
|
68
69
|
from datetime import datetime, timedelta, timezone
|
|
70
|
+
import xml.etree.ElementTree as ET
|
|
69
71
|
from tempfile import mkstemp
|
|
70
72
|
from typing import Any, Callable, Dict, List, Tuple, Union
|
|
71
73
|
|
|
@@ -79,11 +81,19 @@ from cdasws.datarequest import ImageFormat, GraphOptions, GraphRequest
|
|
|
79
81
|
from cdasws.datarequest import TextFormat, TextRequest, ThumbnailRequest
|
|
80
82
|
from cdasws.timeinterval import TimeInterval
|
|
81
83
|
|
|
82
|
-
|
|
84
|
+
|
|
85
|
+
# requires python >= 3.4
|
|
86
|
+
if find_spec('spacepy.datamodel') is not None:
|
|
83
87
|
import spacepy.datamodel as spdm # type: ignore
|
|
84
88
|
SPDM_AVAILABLE = True
|
|
85
|
-
|
|
89
|
+
else:
|
|
86
90
|
SPDM_AVAILABLE = False
|
|
91
|
+
# python < 3.4
|
|
92
|
+
#try:
|
|
93
|
+
# import spacepy.datamodel as spdm # type: ignore
|
|
94
|
+
# SPDM_AVAILABLE = True
|
|
95
|
+
#except ImportError:
|
|
96
|
+
# SPDM_AVAILABLE = False
|
|
87
97
|
|
|
88
98
|
try:
|
|
89
99
|
from cdflib.xarray import cdf_to_xarray
|
|
@@ -127,7 +137,7 @@ except ImportError:
|
|
|
127
137
|
CDF_XARRAY_AVAILABLE = False
|
|
128
138
|
|
|
129
139
|
|
|
130
|
-
__version__ = "1.8.
|
|
140
|
+
__version__ = "1.8.3"
|
|
131
141
|
|
|
132
142
|
|
|
133
143
|
#
|
|
@@ -136,6 +146,22 @@ __version__ = "1.8.2"
|
|
|
136
146
|
#
|
|
137
147
|
RETRY_LIMIT = 100
|
|
138
148
|
|
|
149
|
+
#
|
|
150
|
+
# XML schema namespace
|
|
151
|
+
#
|
|
152
|
+
NS = 'http://cdaweb.gsfc.nasa.gov/schema'
|
|
153
|
+
#
|
|
154
|
+
# XHTML schema namespace
|
|
155
|
+
#
|
|
156
|
+
XHTML_NS = 'http://www.w3.org/1999/xhtml'
|
|
157
|
+
#
|
|
158
|
+
# All namespaces found in responses.
|
|
159
|
+
#
|
|
160
|
+
NAMESPACES = {
|
|
161
|
+
'cdas': NS,
|
|
162
|
+
'xhtml': XHTML_NS
|
|
163
|
+
}
|
|
164
|
+
|
|
139
165
|
|
|
140
166
|
def _get_data_progress(
|
|
141
167
|
progress: float,
|
|
@@ -257,7 +283,7 @@ class CdasWs:
|
|
|
257
283
|
|
|
258
284
|
self._request_headers = {
|
|
259
285
|
'Content-Type' : 'application/json',
|
|
260
|
-
'Accept' : 'application/
|
|
286
|
+
'Accept' : 'application/xml',
|
|
261
287
|
'User-Agent' : self._user_agent,
|
|
262
288
|
#'Accept-Encoding' : 'gzip' # only beneficial for icdfml responses
|
|
263
289
|
}
|
|
@@ -339,17 +365,28 @@ class CdasWs:
|
|
|
339
365
|
self.logger.info('response.text: %s', response.text)
|
|
340
366
|
return []
|
|
341
367
|
|
|
342
|
-
observatory_groups = response.json()
|
|
343
|
-
|
|
344
368
|
if self.logger.level <= logging.DEBUG:
|
|
345
|
-
self.logger.debug('
|
|
346
|
-
json.dumps(observatory_groups,
|
|
347
|
-
indent=4, sort_keys=True))
|
|
369
|
+
self.logger.debug('response.text = %s', response.text)
|
|
348
370
|
|
|
349
|
-
|
|
350
|
-
|
|
371
|
+
observatory_response = ET.fromstring(response.text)
|
|
372
|
+
|
|
373
|
+
observatory_group_descriptions = []
|
|
374
|
+
for description in observatory_response.findall(\
|
|
375
|
+
'cdas:ObservatoryGroupDescription', namespaces=NAMESPACES):
|
|
376
|
+
|
|
377
|
+
observatory_ids = []
|
|
378
|
+
for observatory_id in description.findall(\
|
|
379
|
+
'cdas:ObservatoryId', namespaces=NAMESPACES):
|
|
380
|
+
|
|
381
|
+
observatory_ids.append(observatory_id.text)
|
|
351
382
|
|
|
352
|
-
|
|
383
|
+
observatory_group_descriptions.append({
|
|
384
|
+
'Name': description.find(\
|
|
385
|
+
'cdas:Name', namespaces=NAMESPACES).text,
|
|
386
|
+
'ObservatoryId': observatory_ids
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
return observatory_group_descriptions
|
|
353
390
|
|
|
354
391
|
|
|
355
392
|
def get_instrument_types(
|
|
@@ -399,17 +436,24 @@ class CdasWs:
|
|
|
399
436
|
self.logger.info('response.text: %s', response.text)
|
|
400
437
|
return []
|
|
401
438
|
|
|
402
|
-
|
|
439
|
+
if self.logger.level <= logging.DEBUG:
|
|
440
|
+
self.logger.debug('response.text = %s', response.text)
|
|
441
|
+
|
|
442
|
+
instrument_response = ET.fromstring(response.text)
|
|
403
443
|
|
|
404
444
|
if self.logger.level <= logging.DEBUG:
|
|
405
|
-
self.logger.debug('
|
|
406
|
-
|
|
407
|
-
sort_keys=True))
|
|
445
|
+
self.logger.debug('instrument_response = %s',
|
|
446
|
+
ET.tostring(instrument_response))
|
|
408
447
|
|
|
409
|
-
|
|
410
|
-
|
|
448
|
+
instrument_types = []
|
|
449
|
+
for description in instrument_response.findall(\
|
|
450
|
+
'cdas:InstrumentTypeDescription', namespaces=NAMESPACES):
|
|
411
451
|
|
|
412
|
-
|
|
452
|
+
instrument_types.append({
|
|
453
|
+
'Name': description.find('cdas:Name',
|
|
454
|
+
namespaces=NAMESPACES).text
|
|
455
|
+
})
|
|
456
|
+
return instrument_types
|
|
413
457
|
|
|
414
458
|
|
|
415
459
|
def get_instruments(
|
|
@@ -459,17 +503,29 @@ class CdasWs:
|
|
|
459
503
|
self.logger.info('response.text: %s', response.text)
|
|
460
504
|
return []
|
|
461
505
|
|
|
462
|
-
|
|
506
|
+
if self.logger.level <= logging.DEBUG:
|
|
507
|
+
self.logger.debug('response.text = %s', response.text)
|
|
508
|
+
|
|
509
|
+
instruments_response = ET.fromstring(response.text)
|
|
463
510
|
|
|
464
511
|
if self.logger.level <= logging.DEBUG:
|
|
465
|
-
self.logger.debug('instruments = %s',
|
|
466
|
-
|
|
467
|
-
sort_keys=True))
|
|
512
|
+
self.logger.debug('instruments = %s', response.text)
|
|
513
|
+
#ET.indent(instruments_response, space=' '))
|
|
468
514
|
|
|
469
|
-
|
|
470
|
-
|
|
515
|
+
instruments = []
|
|
516
|
+
for instrument_description in instruments_response.findall(\
|
|
517
|
+
'cdas:InstrumentDescription', namespaces=NAMESPACES):
|
|
471
518
|
|
|
472
|
-
|
|
519
|
+
instruments.append({
|
|
520
|
+
'Name': instrument_description.find(\
|
|
521
|
+
'cdas:Name', namespaces=NAMESPACES).text,
|
|
522
|
+
'ShortDescription': instrument_description.find(\
|
|
523
|
+
'cdas:ShortDescription', namespaces=NAMESPACES).text,
|
|
524
|
+
'LongDescription': instrument_description.find(\
|
|
525
|
+
'cdas:LongDescription', namespaces=NAMESPACES).text
|
|
526
|
+
})
|
|
527
|
+
|
|
528
|
+
return instruments
|
|
473
529
|
|
|
474
530
|
|
|
475
531
|
def get_observatories(
|
|
@@ -519,17 +575,28 @@ class CdasWs:
|
|
|
519
575
|
self.logger.info('response.text: %s', response.text)
|
|
520
576
|
return []
|
|
521
577
|
|
|
522
|
-
|
|
578
|
+
if self.logger.level <= logging.DEBUG:
|
|
579
|
+
self.logger.debug('response.text = %s', response.text)
|
|
580
|
+
|
|
581
|
+
observatory_response = ET.fromstring(response.text)
|
|
523
582
|
|
|
524
583
|
if self.logger.level <= logging.DEBUG:
|
|
525
|
-
self.logger.debug('observatories = %s',
|
|
526
|
-
json.dumps(observatories, indent=4,
|
|
527
|
-
sort_keys=True))
|
|
584
|
+
self.logger.debug('observatories = %s', response.text)
|
|
528
585
|
|
|
529
|
-
|
|
530
|
-
|
|
586
|
+
observatories = []
|
|
587
|
+
|
|
588
|
+
for observatory in observatory_response.findall(\
|
|
589
|
+
'cdas:ObservatoryDescription', namespaces=NAMESPACES):
|
|
590
|
+
observatories.append({
|
|
591
|
+
'Name': observatory.find(\
|
|
592
|
+
'cdas:Name', namespaces=NAMESPACES).text,
|
|
593
|
+
'ShortDescription': observatory.find(\
|
|
594
|
+
'cdas:ShortDescription', namespaces=NAMESPACES).text,
|
|
595
|
+
'LongDescription': observatory.find(\
|
|
596
|
+
'cdas:LongDescription', namespaces=NAMESPACES).text
|
|
597
|
+
})
|
|
531
598
|
|
|
532
|
-
return observatories
|
|
599
|
+
return observatories
|
|
533
600
|
|
|
534
601
|
|
|
535
602
|
def get_observatory_groups_and_instruments(
|
|
@@ -574,17 +641,55 @@ class CdasWs:
|
|
|
574
641
|
self.logger.info('response.text: %s', response.text)
|
|
575
642
|
return []
|
|
576
643
|
|
|
577
|
-
observatories = response.json()
|
|
578
|
-
|
|
579
644
|
if self.logger.level <= logging.DEBUG:
|
|
580
|
-
self.logger.debug('
|
|
581
|
-
json.dumps(observatories, indent=4,
|
|
582
|
-
sort_keys=True))
|
|
645
|
+
self.logger.debug('response.text = %s', response.text)
|
|
583
646
|
|
|
584
|
-
|
|
585
|
-
return []
|
|
647
|
+
observatories_response = ET.fromstring(response.text)
|
|
586
648
|
|
|
587
|
-
|
|
649
|
+
if self.logger.level <= logging.DEBUG:
|
|
650
|
+
self.logger.debug('observatories = %s', response.text)
|
|
651
|
+
|
|
652
|
+
o_g_i_ds = []
|
|
653
|
+
|
|
654
|
+
for o_g_i_d in observatories_response.findall(\
|
|
655
|
+
'cdas:ObservatoryGroupInstrumentDescription',\
|
|
656
|
+
namespaces=NAMESPACES):
|
|
657
|
+
|
|
658
|
+
o_g_i_d_name = o_g_i_d.find('cdas:Name',
|
|
659
|
+
namespaces=NAMESPACES).text
|
|
660
|
+
o_is = []
|
|
661
|
+
for o_i in o_g_i_d.findall('cdas:ObservatoryInstruments',
|
|
662
|
+
namespaces=NAMESPACES):
|
|
663
|
+
|
|
664
|
+
o_i_name = o_i.find('cdas:Name',
|
|
665
|
+
namespaces=NAMESPACES).text
|
|
666
|
+
i_ds = []
|
|
667
|
+
for i_d in o_i.findall('cdas:InstrumentDescription',
|
|
668
|
+
namespaces=NAMESPACES):
|
|
669
|
+
i_d_name = i_d.find('cdas:Name',
|
|
670
|
+
namespaces=NAMESPACES).text
|
|
671
|
+
i_d_short_description = \
|
|
672
|
+
i_d.find('cdas:ShortDescription',
|
|
673
|
+
namespaces=NAMESPACES).text
|
|
674
|
+
i_d_long_description = \
|
|
675
|
+
i_d.find('cdas:LongDescription',
|
|
676
|
+
namespaces=NAMESPACES).text
|
|
677
|
+
i_ds.append({
|
|
678
|
+
'Name': i_d_name,
|
|
679
|
+
'ShortDescription': i_d_short_description,
|
|
680
|
+
'LongDescription': i_d_long_description
|
|
681
|
+
})
|
|
682
|
+
o_is.append({
|
|
683
|
+
'Name': o_i_name,
|
|
684
|
+
'InstrumentDescription': i_ds
|
|
685
|
+
})
|
|
686
|
+
|
|
687
|
+
o_g_i_ds.append({
|
|
688
|
+
'Name': o_g_i_d_name,
|
|
689
|
+
'ObservatoryInstruments': o_is
|
|
690
|
+
})
|
|
691
|
+
|
|
692
|
+
return o_g_i_ds
|
|
588
693
|
|
|
589
694
|
|
|
590
695
|
# pylint: disable=too-many-branches
|
|
@@ -711,16 +816,97 @@ class CdasWs:
|
|
|
711
816
|
self.logger.info('response.text: %s', response.text)
|
|
712
817
|
return []
|
|
713
818
|
|
|
714
|
-
datasets = response.json()
|
|
715
|
-
|
|
716
819
|
if self.logger.level <= logging.DEBUG:
|
|
717
|
-
self.logger.debug('
|
|
718
|
-
json.dumps(datasets, indent=4, sort_keys=True))
|
|
820
|
+
self.logger.debug('response.text = %s', response.text)
|
|
719
821
|
|
|
720
|
-
|
|
721
|
-
return []
|
|
822
|
+
dss = ET.fromstring(response.text)
|
|
722
823
|
|
|
723
|
-
|
|
824
|
+
if self.logger.level <= logging.DEBUG:
|
|
825
|
+
self.logger.debug('datasets = %s', response.text)
|
|
826
|
+
|
|
827
|
+
datasets = []
|
|
828
|
+
for ds in dss.findall('cdas:DatasetDescription',
|
|
829
|
+
namespaces=NAMESPACES):
|
|
830
|
+
|
|
831
|
+
observatory_groups = []
|
|
832
|
+
for o_g in ds.findall('cdas:ObservatoryGroup',
|
|
833
|
+
namespaces=NAMESPACES):
|
|
834
|
+
observatory_groups.append(o_g.text)
|
|
835
|
+
|
|
836
|
+
instrument_types = []
|
|
837
|
+
for i_t in ds.findall('cdas:InstrumentType',
|
|
838
|
+
namespaces=NAMESPACES):
|
|
839
|
+
instrument_types.append(i_t.text)
|
|
840
|
+
|
|
841
|
+
dataset_links = []
|
|
842
|
+
for d_l in ds.findall('cdas:DatasetLink',
|
|
843
|
+
namespaces=NAMESPACES):
|
|
844
|
+
dataset_links.append({
|
|
845
|
+
'Title': d_l.find('cdas:Title',
|
|
846
|
+
namespaces=NAMESPACES).text,
|
|
847
|
+
'Text': d_l.find('cdas:Text',
|
|
848
|
+
namespaces=NAMESPACES).text,
|
|
849
|
+
'Url': d_l.find('cdas:Url',
|
|
850
|
+
namespaces=NAMESPACES).text,
|
|
851
|
+
})
|
|
852
|
+
|
|
853
|
+
observatories = []
|
|
854
|
+
for obs_elem in ds.findall('cdas:Observatory',
|
|
855
|
+
namespaces=NAMESPACES):
|
|
856
|
+
observatories.append(obs_elem.text)
|
|
857
|
+
|
|
858
|
+
instruments = []
|
|
859
|
+
for instr_elem in ds.findall('cdas:Instrument',
|
|
860
|
+
namespaces=NAMESPACES):
|
|
861
|
+
instruments.append(instr_elem.text)
|
|
862
|
+
|
|
863
|
+
dataset = {
|
|
864
|
+
'Id': ds.find('cdas:Id', namespaces=NAMESPACES).text,
|
|
865
|
+
'Observatory': observatories,
|
|
866
|
+
'Instrument': instruments,
|
|
867
|
+
'ObservatoryGroup': observatory_groups,
|
|
868
|
+
'InstrumentType': instrument_types,
|
|
869
|
+
'Label': ds.find('cdas:Label',
|
|
870
|
+
namespaces=NAMESPACES).text,
|
|
871
|
+
'TimeInterval': {
|
|
872
|
+
'Start': ds.find('cdas:TimeInterval/cdas:Start',
|
|
873
|
+
namespaces=NAMESPACES).text,
|
|
874
|
+
'End': ds.find('cdas:TimeInterval/cdas:End',
|
|
875
|
+
namespaces=NAMESPACES).text
|
|
876
|
+
},
|
|
877
|
+
'PiName': ds.find('cdas:PiName',
|
|
878
|
+
namespaces=NAMESPACES).text,
|
|
879
|
+
'PiAffiliation': ds.find('cdas:PiAffiliation',
|
|
880
|
+
namespaces=NAMESPACES).text,
|
|
881
|
+
'Notes': ds.find('cdas:Notes',
|
|
882
|
+
namespaces=NAMESPACES).text,
|
|
883
|
+
'DatasetLink': dataset_links
|
|
884
|
+
}
|
|
885
|
+
doi = ds.find('cdas:Doi', namespaces=NAMESPACES)
|
|
886
|
+
if doi is not None:
|
|
887
|
+
dataset['Doi'] = doi.text
|
|
888
|
+
|
|
889
|
+
spase_resource_id = ds.find('cdas:SpaseResourceId',
|
|
890
|
+
namespaces=NAMESPACES)
|
|
891
|
+
if spase_resource_id is not None:
|
|
892
|
+
dataset['SpaseResourceId'] = spase_resource_id.text
|
|
893
|
+
|
|
894
|
+
additional_metadata = []
|
|
895
|
+
for add_meta in ds.findall('cdas:AdditionalMetadata',
|
|
896
|
+
namespaces=NAMESPACES):
|
|
897
|
+
meta_type = add_meta.attrib['Type']
|
|
898
|
+
value = add_meta.text
|
|
899
|
+
additional_metadata.append({
|
|
900
|
+
'Type': meta_type,
|
|
901
|
+
'value': value
|
|
902
|
+
})
|
|
903
|
+
|
|
904
|
+
if len(additional_metadata) > 0:
|
|
905
|
+
dataset['AdditionalMetadata'] = additional_metadata
|
|
906
|
+
|
|
907
|
+
datasets.append(dataset)
|
|
908
|
+
|
|
909
|
+
return sorted(datasets, key=itemgetter('Id'))
|
|
724
910
|
# pylint: enable=too-many-branches
|
|
725
911
|
|
|
726
912
|
|
|
@@ -791,24 +977,23 @@ class CdasWs:
|
|
|
791
977
|
self.logger.info('response.text: %s', response.text)
|
|
792
978
|
return []
|
|
793
979
|
|
|
794
|
-
inventory = response.json()
|
|
795
|
-
|
|
796
980
|
if self.logger.level <= logging.DEBUG:
|
|
797
|
-
self.logger.debug('
|
|
798
|
-
json.dumps(inventory, indent=4, sort_keys=True))
|
|
981
|
+
self.logger.debug('response.text = %s', response.text)
|
|
799
982
|
|
|
983
|
+
inventory = ET.fromstring(response.text)
|
|
800
984
|
intervals = []
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
985
|
+
for inventory_desc in inventory.findall(\
|
|
986
|
+
'cdas:InventoryDescription',
|
|
987
|
+
namespaces=NAMESPACES):
|
|
988
|
+
for time_interval in inventory_desc.findall(\
|
|
989
|
+
'cdas:TimeInterval',
|
|
990
|
+
namespaces=NAMESPACES):
|
|
808
991
|
intervals.append(
|
|
809
992
|
TimeInterval(
|
|
810
|
-
time_interval
|
|
811
|
-
|
|
993
|
+
time_interval.find('cdas:Start',
|
|
994
|
+
namespaces=NAMESPACES).text,
|
|
995
|
+
time_interval.find('cdas:End',
|
|
996
|
+
namespaces=NAMESPACES).text
|
|
812
997
|
)
|
|
813
998
|
)
|
|
814
999
|
|
|
@@ -881,12 +1066,36 @@ class CdasWs:
|
|
|
881
1066
|
self.logger.info('response.text: %s', response.text)
|
|
882
1067
|
return []
|
|
883
1068
|
|
|
884
|
-
|
|
1069
|
+
if self.logger.level <= logging.DEBUG:
|
|
1070
|
+
self.logger.debug('response.text = %s', response.text)
|
|
885
1071
|
|
|
886
|
-
|
|
887
|
-
|
|
1072
|
+
var_descriptions = ET.fromstring(response.text)
|
|
1073
|
+
|
|
1074
|
+
variables = []
|
|
1075
|
+
for var_description in var_descriptions.findall(\
|
|
1076
|
+
'cdas:VariableDescription',
|
|
1077
|
+
namespaces=NAMESPACES):
|
|
1078
|
+
name = var_description.find('cdas:Name',
|
|
1079
|
+
namespaces=NAMESPACES).text
|
|
1080
|
+
short_description = var_description.find(\
|
|
1081
|
+
'cdas:ShortDescription',
|
|
1082
|
+
namespaces=NAMESPACES).text
|
|
1083
|
+
if short_description is None:
|
|
1084
|
+
short_description = ''
|
|
1085
|
+
|
|
1086
|
+
long_description = var_description.find(\
|
|
1087
|
+
'cdas:LongDescription',
|
|
1088
|
+
namespaces=NAMESPACES).text
|
|
1089
|
+
if long_description is None:
|
|
1090
|
+
long_description = ''
|
|
888
1091
|
|
|
889
|
-
|
|
1092
|
+
variables.append({
|
|
1093
|
+
'Name': name,
|
|
1094
|
+
'ShortDescription': short_description,
|
|
1095
|
+
'LongDescription': long_description
|
|
1096
|
+
})
|
|
1097
|
+
|
|
1098
|
+
return variables
|
|
890
1099
|
|
|
891
1100
|
|
|
892
1101
|
def get_variable_names(
|
|
@@ -915,6 +1124,143 @@ class CdasWs:
|
|
|
915
1124
|
return variable_names
|
|
916
1125
|
|
|
917
1126
|
|
|
1127
|
+
@staticmethod
|
|
1128
|
+
def _get_thumbnail_description_dict(
|
|
1129
|
+
file_description_elem: ET.Element
|
|
1130
|
+
) -> Dict:
|
|
1131
|
+
"""
|
|
1132
|
+
Gets ThumbnailDescription dictionary representation from the
|
|
1133
|
+
given FileDescription element.
|
|
1134
|
+
|
|
1135
|
+
Parameters
|
|
1136
|
+
----------
|
|
1137
|
+
file_description_elem
|
|
1138
|
+
a FileDescription Element.
|
|
1139
|
+
Returns
|
|
1140
|
+
-------
|
|
1141
|
+
Dict
|
|
1142
|
+
a Dictionary representation of the ThumbnailDescription
|
|
1143
|
+
contained in the given FileDescription element.
|
|
1144
|
+
"""
|
|
1145
|
+
thumbnail_desc = file_description_elem.find(\
|
|
1146
|
+
'cdas:ThumbnailDescription',
|
|
1147
|
+
namespaces=NAMESPACES)
|
|
1148
|
+
if thumbnail_desc is not None:
|
|
1149
|
+
time_interval = thumbnail_desc.find('cdas:TimeInterval',
|
|
1150
|
+
namespaces=NAMESPACES)
|
|
1151
|
+
start = time_interval.find('cdas:Start',
|
|
1152
|
+
namespaces=NAMESPACES).text
|
|
1153
|
+
end = time_interval.find('cdas:End',
|
|
1154
|
+
namespaces=NAMESPACES).text
|
|
1155
|
+
return {
|
|
1156
|
+
'Name': thumbnail_desc.find('cdas:Name',
|
|
1157
|
+
namespaces=NAMESPACES).text,
|
|
1158
|
+
'Dataset': thumbnail_desc.find('cdas:Dataset',
|
|
1159
|
+
namespaces=NAMESPACES).text,
|
|
1160
|
+
'TimeInterval': {
|
|
1161
|
+
'Start': start,
|
|
1162
|
+
'End': end
|
|
1163
|
+
},
|
|
1164
|
+
'VarName': thumbnail_desc.find('cdas:VarName',
|
|
1165
|
+
namespaces=NAMESPACES).text,
|
|
1166
|
+
'Options': int(thumbnail_desc.find(\
|
|
1167
|
+
'cdas:Options',
|
|
1168
|
+
namespaces=NAMESPACES).text),
|
|
1169
|
+
'NumFrames': int(thumbnail_desc.find(\
|
|
1170
|
+
'cdas:NumFrames',
|
|
1171
|
+
namespaces=NAMESPACES).text),
|
|
1172
|
+
'NumRows': int(thumbnail_desc.find(\
|
|
1173
|
+
'cdas:NumRows',
|
|
1174
|
+
namespaces=NAMESPACES).text),
|
|
1175
|
+
'NumCols': int(thumbnail_desc.find(\
|
|
1176
|
+
'cdas:NumCols',
|
|
1177
|
+
namespaces=NAMESPACES).text),
|
|
1178
|
+
'TitleHeight': int(thumbnail_desc.find(\
|
|
1179
|
+
'cdas:TitleHeight',
|
|
1180
|
+
namespaces=NAMESPACES).text),
|
|
1181
|
+
'ThumbnailHeight': int(thumbnail_desc.find(\
|
|
1182
|
+
'cdas:ThumbnailHeight',
|
|
1183
|
+
namespaces=NAMESPACES).text),
|
|
1184
|
+
'ThumbnailWidth': int(thumbnail_desc.find(\
|
|
1185
|
+
'cdas:ThumbnailWidth',
|
|
1186
|
+
namespaces=NAMESPACES).text),
|
|
1187
|
+
'StartRecord': int(thumbnail_desc.find(\
|
|
1188
|
+
'cdas:StartRecord',
|
|
1189
|
+
namespaces=NAMESPACES).text),
|
|
1190
|
+
'MyScale': float(thumbnail_desc.find(\
|
|
1191
|
+
'cdas:MyScale',
|
|
1192
|
+
namespaces=NAMESPACES).text),
|
|
1193
|
+
'XyStep': float(thumbnail_desc.find(\
|
|
1194
|
+
'cdas:XyStep',
|
|
1195
|
+
namespaces=NAMESPACES).text)
|
|
1196
|
+
}
|
|
1197
|
+
return None
|
|
1198
|
+
|
|
1199
|
+
|
|
1200
|
+
@staticmethod
|
|
1201
|
+
def _get_data_result_dict(
|
|
1202
|
+
xml_data_result: str
|
|
1203
|
+
) -> Dict:
|
|
1204
|
+
"""
|
|
1205
|
+
Gets DataResult dictionary representation from the
|
|
1206
|
+
given XML DataResult element.
|
|
1207
|
+
|
|
1208
|
+
Parameters
|
|
1209
|
+
----------
|
|
1210
|
+
xml_data_result
|
|
1211
|
+
XML representation of a DataResult.
|
|
1212
|
+
Returns
|
|
1213
|
+
-------
|
|
1214
|
+
Dict
|
|
1215
|
+
a Dictionary representation of the given XML representation
|
|
1216
|
+
of a DataResult.
|
|
1217
|
+
"""
|
|
1218
|
+
data_result = ET.fromstring(xml_data_result)
|
|
1219
|
+
file_descriptions = []
|
|
1220
|
+
for file_description in data_result.findall(\
|
|
1221
|
+
'cdas:FileDescription', namespaces=NAMESPACES):
|
|
1222
|
+
|
|
1223
|
+
dict_file_description = {
|
|
1224
|
+
'Name': file_description.find('cdas:Name',
|
|
1225
|
+
namespaces=NAMESPACES).text,
|
|
1226
|
+
'MimeType': file_description.find(\
|
|
1227
|
+
'cdas:MimeType',
|
|
1228
|
+
namespaces=NAMESPACES).text,
|
|
1229
|
+
'StartTime': file_description.find(\
|
|
1230
|
+
'cdas:StartTime',
|
|
1231
|
+
namespaces=NAMESPACES).text,
|
|
1232
|
+
'EndTime': file_description.find(\
|
|
1233
|
+
'cdas:EndTime',
|
|
1234
|
+
namespaces=NAMESPACES).text,
|
|
1235
|
+
'Length': int(file_description.find(\
|
|
1236
|
+
'cdas:Length',
|
|
1237
|
+
namespaces=NAMESPACES).text),
|
|
1238
|
+
'LastModified': file_description.find(\
|
|
1239
|
+
'cdas:LastModified',
|
|
1240
|
+
namespaces=NAMESPACES).text
|
|
1241
|
+
}
|
|
1242
|
+
thumbnail_dict = CdasWs._get_thumbnail_description_dict(\
|
|
1243
|
+
file_description)
|
|
1244
|
+
if thumbnail_dict is not None:
|
|
1245
|
+
dict_file_description['ThumbnailDescription'] = \
|
|
1246
|
+
thumbnail_dict
|
|
1247
|
+
|
|
1248
|
+
thumbnail_id_elem = file_description.find(\
|
|
1249
|
+
'cdas:ThumbnailId',
|
|
1250
|
+
namespaces=NAMESPACES)
|
|
1251
|
+
if thumbnail_id_elem is not None:
|
|
1252
|
+
dict_file_description['ThumbnailId'] = \
|
|
1253
|
+
thumbnail_id_elem.text
|
|
1254
|
+
|
|
1255
|
+
file_descriptions.append(dict_file_description)
|
|
1256
|
+
|
|
1257
|
+
if len(file_descriptions) > 0:
|
|
1258
|
+
return {
|
|
1259
|
+
'FileDescription': file_descriptions
|
|
1260
|
+
}
|
|
1261
|
+
return None
|
|
1262
|
+
|
|
1263
|
+
|
|
918
1264
|
def get_data_result(
|
|
919
1265
|
self,
|
|
920
1266
|
data_request: DataRequest,
|
|
@@ -962,18 +1308,10 @@ class CdasWs:
|
|
|
962
1308
|
response = self._session.post(url, data=data_request.json(),
|
|
963
1309
|
timeout=self._timeout)
|
|
964
1310
|
|
|
965
|
-
try:
|
|
966
|
-
data_result = response.json()
|
|
967
|
-
except ValueError:
|
|
968
|
-
# for example, a 503 from apache will not be json
|
|
969
|
-
self.logger.debug('Non-JSON response: %s', response.text)
|
|
970
|
-
|
|
971
|
-
if self.logger.level <= logging.DEBUG:
|
|
972
|
-
self.logger.debug('data_result = %s',
|
|
973
|
-
json.dumps(data_result, indent=4,
|
|
974
|
-
sort_keys=True))
|
|
975
1311
|
if response.status_code == 200:
|
|
976
1312
|
|
|
1313
|
+
data_result = CdasWs._get_data_result_dict(response.text)
|
|
1314
|
+
|
|
977
1315
|
if not data_result:
|
|
978
1316
|
return (response.status_code, None)
|
|
979
1317
|
|
|
@@ -1074,7 +1412,7 @@ class CdasWs:
|
|
|
1074
1412
|
--------
|
|
1075
1413
|
CdasWs.get_data : In addition to what get_data_file does,
|
|
1076
1414
|
get_data also downloads and reads the data file into memory
|
|
1077
|
-
(SpaceData object).
|
|
1415
|
+
(SpaceData or xarray.Dataset object).
|
|
1078
1416
|
"""
|
|
1079
1417
|
# pylint: disable=too-many-locals
|
|
1080
1418
|
# pylint: disable=too-many-return-statements
|
|
@@ -1308,7 +1646,7 @@ class CdasWs:
|
|
|
1308
1646
|
Tuple
|
|
1309
1647
|
[0] contains a dictionary of HTTP and CDAS status information.
|
|
1310
1648
|
When successful, ['http']['status_code'] will be 200.<br>
|
|
1311
|
-
[1] contains the requested data (SpaceData or xarray.
|
|
1649
|
+
[1] contains the requested data (SpaceData or xarray.Dataset
|
|
1312
1650
|
object) or None.
|
|
1313
1651
|
Raises
|
|
1314
1652
|
------
|
|
@@ -1972,14 +2310,20 @@ class CdasWs:
|
|
|
1972
2310
|
self.logger.info('response.text: %s', response.text)
|
|
1973
2311
|
return (response.status_code, None)
|
|
1974
2312
|
|
|
1975
|
-
results = response.json()
|
|
1976
|
-
|
|
1977
2313
|
if self.logger.level <= logging.DEBUG:
|
|
1978
|
-
self.logger.debug('
|
|
1979
|
-
json.dumps(results,
|
|
1980
|
-
indent=4, sort_keys=True))
|
|
2314
|
+
self.logger.debug('response.text = %s', response.text)
|
|
1981
2315
|
|
|
1982
|
-
|
|
1983
|
-
|
|
2316
|
+
results = ET.fromstring(response.text)
|
|
2317
|
+
|
|
2318
|
+
ssc_id = []
|
|
2319
|
+
for ssc_id_elem in results.findall('SscId'):
|
|
2320
|
+
ssc_id.append(ssc_id_elem.text)
|
|
2321
|
+
|
|
2322
|
+
if len(ssc_id) == 0:
|
|
2323
|
+
result = None
|
|
2324
|
+
elif len(ssc_id) == 1:
|
|
2325
|
+
result = ssc_id[0]
|
|
2326
|
+
else:
|
|
2327
|
+
result = ssc_id
|
|
1984
2328
|
|
|
1985
|
-
return (response.status_code,
|
|
2329
|
+
return (response.status_code, result)
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
#
|
|
25
25
|
# NOSA HEADER END
|
|
26
26
|
#
|
|
27
|
-
# Copyright (c) 2019-
|
|
27
|
+
# Copyright (c) 2019-2024 United States Government as represented by
|
|
28
28
|
# the National Aeronautics and Space Administration. No copyright is
|
|
29
29
|
# claimed in the United States under Title 17, U.S.Code. All Other
|
|
30
30
|
# Rights Reserved.
|
|
@@ -36,7 +36,7 @@ Package defining classes to represent the DataRequestEntity and its
|
|
|
36
36
|
sub-classes from
|
|
37
37
|
<https://cdaweb.gsfc.nasa.gov/WebServices/REST/CDAS.xsd>.<br>
|
|
38
38
|
|
|
39
|
-
Copyright © 2019-
|
|
39
|
+
Copyright © 2019-2024 United States Government as represented by the
|
|
40
40
|
National Aeronautics and Space Administration. No copyright is claimed in
|
|
41
41
|
the United States under Title 17, U.S.Code. All Other Rights Reserved.
|
|
42
42
|
"""
|
|
@@ -378,6 +378,7 @@ class GraphOptions:
|
|
|
378
378
|
related variables from different datasets will result in the
|
|
379
379
|
same graphs being produced as when the option is not included.
|
|
380
380
|
"""
|
|
381
|
+
# pylint: disable=too-many-arguments
|
|
381
382
|
def __init__(self,
|
|
382
383
|
coarse_noise_filter: bool = False,
|
|
383
384
|
x_axis_width_factor: int = 3,
|
|
@@ -391,6 +392,7 @@ class GraphOptions:
|
|
|
391
392
|
self._y_axis_height_factor = y_axis_height_factor
|
|
392
393
|
self._combine = combine
|
|
393
394
|
self._overplot = overplot
|
|
395
|
+
# pylint: enable=too-many-arguments
|
|
394
396
|
|
|
395
397
|
|
|
396
398
|
@property
|
|
@@ -10,7 +10,7 @@ README = (HERE / "README.md").read_text()
|
|
|
10
10
|
# This call to setup() does all the work
|
|
11
11
|
setup(
|
|
12
12
|
name="cdasws",
|
|
13
|
-
version="1.8.
|
|
13
|
+
version="1.8.3",
|
|
14
14
|
description="NASA's Coordinated Data Analysis System Web Service Client Library",
|
|
15
15
|
long_description=README,
|
|
16
16
|
long_description_content_type="text/markdown",
|
|
@@ -19,6 +19,7 @@ setup(
|
|
|
19
19
|
author_email="NASA-SPDF-Support@nasa.onmicrosoft.com",
|
|
20
20
|
license="NOSA",
|
|
21
21
|
packages=["cdasws"],
|
|
22
|
+
# python_requires=[">3.4"]
|
|
22
23
|
# packages=find_packages(exclude=["tests"]),
|
|
23
24
|
# packages=find_packages(),
|
|
24
25
|
include_package_data=True,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|