class HEKClient(object): """ Client to interact with the Heliophysics Event Knowledgebase (HEK). The HEK stores solar feature and event data generated by algorithms and human observers.""" # FIXME: Expose fields in .attrs with the right types # that is, not all StringParamWrapper! default = { 'cosec': '2', 'cmd': 'search', 'type': 'column', 'event_type': '**', } # Default to full disk. attrs.walker.apply(attrs.SpatialRegion(), {}, default) def __init__(self, url=DEFAULT_URL): self.url = url def _download(self, data): """ Download all data, even if pagiated. """ page = 1 results = [] while True: data['page'] = page fd = urlopen(self.url, urlencode(data)) try: result = json.load(fd) finally: fd.close() results.extend(result['result']) if not result['overmax']: return map(Response, results) page += 1 def query(self, *query): """ Retrieves information about HEK records matching the criteria given in the query expression. If multiple arguments are passed, they are connected with AND. The result of a query is a list of unique HEK Response objects that fulfill the criteria.""" query = attr.and_(*query) data = attrs.walker.create(query, {}) ndata = [] for elem in data: new = self.default.copy() new.update(elem) ndata.append(new) if len(ndata) == 1: return self._download(ndata[0]) else: return self._merge(self._download(data) for data in ndata) def _merge(self, responses): """ Merge responses, removing duplicates. """ return list(unique(chain.from_iterable(responses), _freeze))
class HEKClient(object): """ Client to interact with the HEK. """ # FIXME: Expose fields in .attrs with the right types # that is, not all StringParamWrapper! default = { 'cosec': '2', 'cmd': 'search', 'type': 'column', 'event_type': '**', } # Default to full disk. attrs.walker.apply(attrs.SpatialRegion(), {}, default) def __init__(self, url=DEFAULT_URL): self.url = url def _download(self, data): """ Implementation detail. """ page = 1 results = [] while True: data['page'] = page fd = urlopen(self.url, urlencode(data)) try: result = json.load() finally: fd.close() results.extend(result['result']) if not result['overmax']: return map(Response, results) page += 1 def query(self, *query): """ Retrieve information about records matching the criteria given in the query expression. If multiple arguments are passed, they are connected with AND. """ query = attr.and_(*query) data = attrs.walker.create(query, {}) ndata = [] for elem in data: new = self.default.copy() new.update(elem) ndata.append(new) if len(ndata) == 1: return self._download(ndata[0]) else: return self._merge(self._download(data) for data in ndata) def _merge(self, responses): """ Implementation detail. """ return list(unique(chain.from_iterable(responses), _freeze))
class HEKClient(BaseClient): """ Provides access to the Heliophysics Event Knowledgebase (HEK). The HEK stores solar feature and event data generated by algorithms and human observers. """ # FIXME: Expose fields in .attrs with the right types # that is, not all StringParamWrapper! default = { 'cosec': '2', 'cmd': 'search', 'type': 'column', 'event_type': '**', } # Default to full disk. attrs.walker.apply(attrs.SpatialRegion(), {}, default) def __init__(self, url=DEFAULT_URL): self.url = url def _download(self, data): """ Download all data, even if paginated. """ page = 1 results = [] while True: data['page'] = page url = self.url + urllib.parse.urlencode(data) log.debug(f'Opening {url}') fd = urllib.request.urlopen(url) try: result = codecs.decode(fd.read(), encoding='utf-8', errors='replace') result = json.loads(result) except Exception as e: raise IOError( "Failed to load return from the HEKClient.") from e finally: fd.close() results.extend(result['result']) if not result['overmax']: if len(results) > 0: return astropy.table.Table(dict_keys_same(results)) else: return astropy.table.Table() page += 1 def search(self, *args, **kwargs): """ Retrieves information about HEK records matching the criteria given in the query expression. If multiple arguments are passed, they are connected with AND. The result of a query is a list of unique HEK Response objects that fulfill the criteria. Examples ------- >>> from sunpy.net import attrs as a, Fido >>> timerange = a.Time('2011/08/09 07:23:56', '2011/08/09 12:40:29') >>> res = Fido.search(timerange, a.hek.FL, a.hek.FRM.Name == "SWPC") # doctest: +REMOTE_DATA >>> res #doctest: +SKIP <sunpy.net.fido_factory.UnifiedResponse object at ...> Results from 1 Provider: <BLANKLINE> 2 Results from the HEKClient: SOL_standard active ... skel_startc2 sum_overlap_scores ------------------------------ ------ ... ------------ ------------------ SOL2011-08-09T07:19:00L227C090 true ... None 0 SOL2011-08-09T07:48:00L296C073 true ... None 0 <BLANKLINE> <BLANKLINE> """ query = attr.and_(*args) data = attrs.walker.create(query, {}) ndata = [] for elem in data: new = self.default.copy() new.update(elem) ndata.append(new) if len(ndata) == 1: return HEKTable(self._download(ndata[0]), client=self) else: return HEKTable(self._merge( self._download(data) for data in ndata), client=self) def _merge(self, responses): """ Merge responses, removing duplicates. """ return list(unique(chain.from_iterable(responses), _freeze)) def fetch(self, *args, **kwargs): """ This is a no operation function as this client does not download data. """ return NotImplemented @classmethod def _attrs_module(cls): return 'hek', 'sunpy.net.hek.attrs' @classmethod def _can_handle_query(cls, *query): required = {core_attrs.Time} optional = {i[1] for i in inspect.getmembers(attrs, inspect.isclass) } - required qr = tuple(x for x in query if not isinstance(x, attrs.EventType)) return cls.check_attr_types_in_query(qr, required, optional)