def get_samp_client() -> SAMPIntegratedClient: """ creates a new SAMP client and tries to connect to the hub :return: the new samp client """ while True: try: client = SAMPIntegratedClient("PhotometryTool") client.connect() except SAMPHubError: time.sleep(0.5) else: return client
def send_map_layers_to_samp(maps, defer_cleanup_s=5): client = SAMPIntegratedClient() client.connect() params = {} message = {"samp.mtype": "jhv.load.image", "samp.params": params} tmp_files = [] for energy_band in maps: params["url"] = [] for i in range(len(maps[energy_band])): f = NamedTemporaryFile(delete=False, suffix=".fits") f.close() maps[energy_band][i].save(f.name) tmp_files.append(f.name) # use file:/// workaround for windows as JHV currently can't handle windows paths params["url"].append(("file:///" + f.name.replace("\\", "/") ) if f.name.find("\\") >= 0 else f.name) client.notify_all( message ) # message holds a reference to params which is updated in the loop client.disconnect() time.sleep( defer_cleanup_s ) # wait to make sure JHV could read the files before they're removed for filename in tmp_files: del_file(filename) # cleanup
def __init__(self, callback, check_connection_period=1): self.callback = callback self.dirname = os.path.dirname(os.path.abspath(__file__)) self.timer = None self.samp_hub = None self.samp_client = None self.metadata = { 'samp.name': 'iSpec', 'samp.description.text': 'iSpec', 'samp.icon.url': 'file://' + self.dirname + '/images/iSpec.png', } self.samp_client = SAMPIntegratedClient(metadata=self.metadata, addr='localhost') self.check_connection_period = check_connection_period # seconds self.__check_connection() signal.signal(signal.SIGINT, self.__signal_handler)
def __check_connection(self): status = "Status: " if not self.is_connected(): if self.samp_client is not None and self.samp_client.is_connected( ): # Destroy old client to completely reset the connection status del self.samp_client self.samp_client = SAMPIntegratedClient(metadata=self.metadata, addr='localhost') logging.info("SAMP Connection lost") status += "Disconnected" self.__connect() else: status += "Connected" pass logging.debug(status) self.timer = threading.Timer(self.check_connection_period, self.__check_connection) self.timer.start()
class SAMP4JHVClient: def __init__(self): self.client = SAMPIntegratedClient() self.tmp_files = [] def send_image_maps(self, maps): """ Takes a list of SunPy Map objects, saves them to disk one by one and sends the file-locations to JHV """ params = {} params["url"] = [] for m in maps: f = NamedTemporaryFile(delete=False, suffix=".fits") f.close() m.save(f.name) self.tmp_files.append(f.name) # use file:/// workaround for windows as JHV currently can't handle windows paths params["url"].append(("file:///" + f.name.replace("\\", "/") ) if f.name.find("\\") >= 0 else f.name) self.client.connect() self.client.notify_all({ "samp.mtype": "jhv.load.image", "samp.params": params }) self.client.disconnect() def remove_tmp_files(self): """ Removes temporary files that were created for JHV to be read. Mind that after calling this function, the images might not be available in JHV anymore due to JHVs internal memory management, that might require to re-read the files at some point. """ for f in self.tmp_files: del_file(f) # cleanup
class TestWebProfile(BaseTestStandardProfile): def setup_method(self, method): self.dialog = AlwaysApproveWebProfileDialog() t = threading.Thread(target=self.dialog.poll) t.start() self.tmpdir = tempfile.mkdtemp() lockfile = os.path.join(self.tmpdir, '.samp') self.hub = SAMPHubServer(web_profile_dialog=self.dialog, lockfile=lockfile, web_port=0, pool_size=1) self.hub.start() self.client1 = SAMPIntegratedClient() self.client1.connect(hub=self.hub, pool_size=1) self.client1_id = self.client1.get_public_id() self.client1_key = self.client1.get_private_key() self.client2 = SAMPIntegratedWebClient() self.client2.connect(web_port=self.hub._web_port, pool_size=2) self.client2_id = self.client2.get_public_id() self.client2_key = self.client2.get_private_key() def teardown_method(self, method): if self.client1.is_connected: self.client1.disconnect() if self.client2.is_connected: self.client2.disconnect() self.hub.stop() self.dialog.stop() # The full communication tests are run since TestWebProfile inherits # test_main from TestStandardProfile def test_web_profile(self): # Check some additional queries to the server with get_readable_fileobj('http://localhost:{0}/crossdomain.xml'.format(self.hub._web_port)) as f: assert f.read() == CROSS_DOMAIN with get_readable_fileobj('http://localhost:{0}/clientaccesspolicy.xml'.format(self.hub._web_port)) as f: assert f.read() == CLIENT_ACCESS_POLICY # Check headers req = Request('http://localhost:{0}/crossdomain.xml'.format(self.hub._web_port)) req.add_header('Origin', 'test_web_profile') resp = urlopen(req) assert resp.getheader('Access-Control-Allow-Origin') == 'test_web_profile' assert resp.getheader('Access-Control-Allow-Headers') == 'Content-Type' assert resp.getheader('Access-Control-Allow-Credentials') == 'true'
def setup_method(self, method): self.dialog = AlwaysApproveWebProfileDialog() t = threading.Thread(target=self.dialog.poll) t.start() self.tmpdir = tempfile.mkdtemp() lockfile = os.path.join(self.tmpdir, '.samp') self.hub = SAMPHubServer(web_profile_dialog=self.dialog, lockfile=lockfile, web_port=0, pool_size=1) self.hub.start() self.client1 = SAMPIntegratedClient() self.client1.connect(hub=self.hub, pool_size=1) self.client1_id = self.client1.get_public_id() self.client1_key = self.client1.get_private_key() self.client2 = SAMPIntegratedWebClient() self.client2.connect(web_port=self.hub._web_port, pool_size=2) self.client2_id = self.client2.get_public_id() self.client2_key = self.client2.get_private_key()
def SAMP_conn(): """a context manager to give the controlled block a SAMP connection. The program will disconnect as the controlled block is exited. """ client = SAMPIntegratedClient(name="serialquery", description="A serial SCS querier.") client.connect() try: yield client finally: client.disconnect()
def connection( client_name="pyvo client", description="A generic PyVO client", **kwargs ): """ a context manager to give the controlled block a SAMP connection. The program will disconnect as the controlled block is exited. """ client = SAMPIntegratedClient( name=client_name, description=description, **kwargs) client.connect() try: yield client finally: client.disconnect()
def capCommand(self, *args, **kwargs): MSG=self.MSG self.cli = SAMPIntegratedClient() self.cli.connect() self.r = Receiver(self.cli) MSG( 'Binding methods' ) #=> case MTYPE: qgis.message def qMessage(): MSG( 'Message: ' + self.r.params['script']) #=> case MTYPE: qgis.load.vectorlayer def qLoadVectorlayer(): # case MTYPE: qgis.load.vectorlayer self.LoadVectorLayer(self.r.params['url'], self.r.params['name']) #=> case MTYPE: table.load.votable def addVLayerToCanvas(self,vlayer): self.iface.mapCanvas().freeze() #QgsMapLayerRegistry.instance().addMapLayer(vlayer) # order is importaint here QgsProject.instance().addMapLayer(vlayer) # self.root.addLayer(vlayer) self.root.insertLayer(0,vlayer) #QgsMapLayerRegistry.instance().reloadAllLayers() QgsProject.instance().reloadAllLayers() self.iface.mapCanvas().freeze(False) def qLoadVotable(): loadWMS = lambda vot: VOTableLoaderHelper.loadWMS(vot, self.iface, self.root) makeComplFeat = VOTableLoaderHelper.makeComplFeat MSG('Loading VOtable\n from url: \n'+self.r.params['url']);say('SAMP Params are: ' + str(self.r.params)) ttime.sleep(2) vot = Table.read(download_file(self.r.params['url'],timeout=200)) #fixes timeout bug if 'access_format' in vot.colnames: say(str(vot.columns['access_format'][0])) #<+=== if b'application/x-wms'in vot.columns['access_format'][0]: try: loadWMS(vot) except Exception: self.MSG('OOPS something went wrong while loading WMS') tb=traceback.format_exc() say(tb) finally: return mURL = tempfile.mkdtemp() MSG("converting to GeoJSON");say('Number of features to write: '+ str(len(vot)) ) featList=[] for i in range(len(vot)): self.MSG('writing number' + str(i)) featList.append(makeComplFeat(vot, i)) with open(mURL + '/vot.geojson', 'w') as f: f.write(geojson.dumps({"type":"FeatureCollection","features":featList})) self.MSG('finished download, converting to SpatiaLite') try: self.MSG("vlayer") ttime.sleep(2) vlayer = QgsVectorLayer(mURL + '/vot.geojson',"mygeojson","ogr") except Exception: self.MSG("ops creating geojson") ttime.sleep(2) self.MSG('OOPS something went wrong while creating a vector layer from geojson') return say("writing to SpatiaLite") try: self.MSG("Writing...") #ttime.sleep(2) options = QgsVectorFileWriter.SaveVectorOptions() #options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer #options.EditionCapability = QgsVectorFileWriter.CanAddNewLayer #options.fileEncoding="utf-8" options.driverName="SQLite" options.layerName = vlayer.name() QgsVectorFileWriter.writeAsVectorFormat(vlayer, mURL +r"/vot.sqlite", options) except Exception as e: # #logf = open(r"/home/gnodj/test/download.log", "w") # self.MSG("201") # fname = r'/home/vhyradus/test/' # logging.basicConfig(filename=fname + 'log.log', level=logging.DEBUG,format='%(asctime)s %(levelname)s %(name)s %(message)s') # logger=logging.getLogger(__name__) # logger.error(e) # ttime.sleep(2) self.MSG('OOPS something went wrong while writing SQLite') #ttime.sleep(2) return say("loading SpatiaLite") try: self.MSG("Loading...") vlayer = QgsVectorLayer(mURL+r"/vot.sqlite",str(self.r.params['name']),"ogr") except Exception as e: # self.MSG("215") # ttime.sleep(2) # self.MSG('OOPS something went wrong while creating a vector Layer') # fname = r'/home/vhyradus/test/' # logging.basicConfig(filename=fname + 'log.log', level=logging.DEBUG,format='%(asctime)s %(levelname)s %(name)s %(message)s') # logger=logging.getLogger(__name__) # logger.error(e) # ttime.sleep(2) self.MSG('OOPS something went wrong while writing SQLite') # ttime.sleep(2) return # say(vot.meta['description']) #description is not available with complex queries # vlayer = QgsVectorLayer( mURL+r"/vot.sqlite",str(vot.meta['description']),"ogr") say("adding layer to canvas") try: self.MSG("Adding...") ttime.sleep(2) self.addVLayerToCanvas(vlayer) except Exception as e: # self.MSG("234") # fname = r'/home/vhyradus/test/' # logging.basicConfig(filename=fname + 'log.log', level=logging.DEBUG,format='%(asctime)s %(levelname)s %(name)s %(message)s') # logger=logging.getLogger(__name__) # logger.error(e) # ttime.sleep(2) # ttime.sleep(2) self.MSG('OOPS something went wrong while trying to add layer to canvas') return say("done") mTypeDict={'qgis.message':qMessage,'qgis.load.vectorlayer':qLoadVectorlayer,'table.load.votable':qLoadVotable} list(map(self.bindSamp, list(mTypeDict.keys()))) MSG("Disconnected") while self.connectionState: MSG("starting") self.r.received = False while not self.r.received and self.connectionState: MSG("waiting"); ttime.sleep(2) if self.connectionState: mTypeDict[self.r.mtype]() ttime.sleep(2)
class SAMPState(State): status = CallbackProperty('Not connected to SAMP Hub') connected = CallbackProperty(False) clients = CallbackProperty([]) highlight_is_selection = CallbackProperty(False) def __init__(self): super(SAMPState, self).__init__() self.hub = SAMPHubServer() self.client = SAMPIntegratedClient() self.add_callback('connected', self.on_connected) def start_samp(self): if not self.client.is_connected: try: self.client.connect() except SAMPHubError: try: self.hub.start() self.client.connect() except Exception: self.connected = False self.status = 'Could not connect to Hub' else: self.connected = True self.status = 'Connected to (glue) SAMP Hub' except: self.connected = False self.status = 'Could not connect to Hub' else: self.connected = True self.status = 'Connected to SAMP Hub' def stop_samp(self): if self.client.is_connected: self.client.disconnect() if self.hub.is_running: self.hub.stop() self.connected = False self.status = 'Not connected to SAMP Hub' def on_connected(self, *args): if self.connected: metadata = { 'author.email': '*****@*****.**', 'author.name': 'Thomas Robitaille', 'home.page': 'http://www.glueviz.org', 'samp.description.text': 'Multi-dimensional linked data exploration', 'samp.documentation.url': 'http://www.glueviz.org', 'samp.icon.url': 'file://' + ICON_PATH, 'samp.name': 'glueviz', 'glue.version': glue_version } self.client.declare_metadata(metadata) self.on_client_change() def on_client_change(self): clients = [] for client in self.client.get_registered_clients(): metadata = self.client.get_metadata(client) clients.append((client, metadata.get('samp.name', client))) self.clients = clients def send_data(self, layer=None, client=None): filename = tempfile.mktemp() message = {} message["samp.params"] = {} if isinstance(layer, Data): if layer.ndim == 1: table = data_to_astropy_table(layer) table.write(filename, format='votable') message["samp.mtype"] = "table.load.votable" if 'samp-table-id' not in layer.meta: layer.meta['samp-table-id'] = layer.label message["samp.params"]['table-id'] = layer.meta[ 'samp-table-id'] elif layer.ndim == 2: fits_writer(filename, layer) message["samp.mtype"] = "image.load.fits" if 'samp-image-id' not in layer.meta: layer.meta['samp-image-id'] = layer.label message["samp.params"]['image-id'] = layer.meta[ 'samp-image-id'] else: return message["samp.params"]['name'] = layer.label message["samp.params"]['url'] = 'file://' + os.path.abspath( filename) else: message['samp.mtype'] = 'table.select.rowList' if layer.ndim == 1: message["samp.params"]['table-id'] = layer.data.meta[ 'samp-table-id'] message["samp.params"]['row-list'] = np.nonzero( layer.to_mask())[0].astype(str).tolist() else: return if client is None: self.client.notify_all(message) else: # Make sure client is subscribed otherwise an exception is raised subscriptions = self.client.get_subscriptions(client) for mtype in subscriptions: if fnmatch(message['samp.mtype'], mtype): self.client.notify(client, message) return else: return
class SAMPManager(object): def __init__(self, callback, check_connection_period=1): self.callback = callback self.dirname = os.path.dirname(os.path.abspath(__file__)) self.timer = None self.samp_hub = None self.samp_client = None self.metadata = { 'samp.name': 'iSpec', 'samp.description.text': 'iSpec', 'samp.icon.url': 'file://' + self.dirname + '/images/iSpec.png', } self.samp_client = SAMPIntegratedClient(metadata=self.metadata, addr='localhost') self.check_connection_period = check_connection_period # seconds self.__check_connection() signal.signal(signal.SIGINT, self.__signal_handler) def is_connected(self): working_connection = False if self.samp_client is not None and self.samp_client.is_connected(): try: self.samp_client.ping() working_connection = True except: working_connection = False return working_connection def __check_connection(self): status = "Status: " if not self.is_connected(): if self.samp_client is not None and self.samp_client.is_connected( ): # Destroy old client to completely reset the connection status del self.samp_client self.samp_client = SAMPIntegratedClient(metadata=self.metadata, addr='localhost') logging.info("SAMP Connection lost") status += "Disconnected" self.__connect() else: status += "Connected" pass logging.debug(status) self.timer = threading.Timer(self.check_connection_period, self.__check_connection) self.timer.start() def __connect(self): # Before we start, let's kill off any zombies try: self.shutdown() except: pass # sampy seems to fall over sometimes if 'localhost' isn't specified, even though it shouldn't #self.samp_hub = sampy.SAMPHubServer(addr='localhost') #self.samp_hub.start() try: self.samp_client.connect() logging.info("SAMP Connection established") except Exception: pass else: #samp_client.bindReceiveNotification("*", self.__samp_receive_notification) #samp_client.bindReceiveCall("*", self.__samp_receive_call) self.samp_client.bind_receive_notification( "samp.hub.event.register", self.__samp_receive_notification) self.samp_client.bind_receive_notification( "samp.hub.event.metadata", self.__samp_receive_notification) self.samp_client.bind_receive_notification( "samp.hub.event.subscriptions", self.__samp_receive_notification) self.samp_client.bind_receive_notification( "samp.hub.event.unregister", self.__samp_receive_notification) self.samp_client.bind_receive_notification( "table.load.votable", self.__samp_receive_notification) self.samp_client.bind_receive_notification( "spectrum.load.ssa-generic", self.__samp_receive_notification) self.samp_client.bind_receive_call("table.load.votable", self.__samp_receive_call) self.samp_client.bind_receive_call("spectrum.load.ssa-generic", self.__samp_receive_call) def __samp_receive_notification(self, private_key, sender_id, mtype, params, extra): #print "Notification:", private_key, sender_id, mtype, params, extra if mtype == 'samp.hub.event.register': #print "Registered:", params['id'] pass elif mtype == 'samp.hub.event.metadata': #print "Metadata:", params['id'], "=", params['metadata']['samp.name'] pass elif mtype == 'samp.hub.event.subscriptions': if 'spectrum.load.ssa-generic' in list( params['subscriptions'].keys()): #print params['id'], "supports spectrum" pass if 'table.load.votable' in list(params['subscriptions'].keys()): #print params['id'], "supports votable" pass #print params elif mtype == 'samp.hub.event.unregister': #print params['id'], "unregistered" pass else: # For instance, VOSpec sends load votable/spectrum in form of notification # so we should try to process them also msg_id = None spectrum = self.__samp_receive_and_transform_spectrum( mtype, params) logging.info("Spectrum received via SAMP") self.callback(spectrum, "Received_spectrum") # Function called when a call is received def __samp_receive_call(self, private_key, sender_id, msg_id, mtype, params, extra): #print "Call:", private_key, sender_id, msg_id, mtype, params, extra spectrum = self.__samp_receive_and_transform_spectrum(mtype, params) self.samp_client.ereply(msg_id, sampy.SAMP_STATUS_OK, result={"txt": "printed"}) logging.info("Spectrum received via SAMP") self.callback(spectrum, "Received_spectrum") def __samp_receive_and_transform_spectrum(self, mtype, params): if mtype == 'table.load.votable': #print "Received votable", params['url'] votable = self.__read_votable(params['url']) spectrum = self.__votable_to_spectrum(votable) #print "Spectrum success" elif mtype == 'spectrum.load.ssa-generic': #print "Received spectrum", params['url'], "in format", params['meta']['Access.Format'] if params['meta']['Access.Format'] == 'application/votable': #print "- Votable" votable = self.__read_votable(params['url']) spectrum = self.__votable_to_spectrum(votable) #print "Spectrum success" elif params['meta']['Access.Format'] == 'application/fits': #print "- FITS" spectrum = self.__read_vofits(params['url']) #print "Spectrum success" else: raise Exception("Unknown format") else: raise Exception("Unknown action") return spectrum def __signal_handler(self, signal, frame): print('SIGTERM received (ctrl+c)') self.shutdown() def shutdown(self): if self.timer is not None: self.timer.cancel() if self.samp_client.is_connected(): try: self.samp_client.disconnect() except Exception: pass if self.samp_hub is not None and self.samp_hub._is_running: self.samp_hub.stop() sys.exit(0) def __get_target_client(self, target_client_name): neighbours = samp_client.get_registered_clients() for neighbour in neighbours: metadata = self.samp_client.get_metadata(neighbour) try: if (metadata['samp.name'] == target_client_name): return neighbour except KeyError: continue return None ########### [start] File operations def __votable_to_spectrum(self, votable): spectrum = None # Search for what it is required has_waveobs = False has_flux = False target_table = None waveobs_units = None for resource in votable.resources: for table in resource.tables: if len(table.array) > 0 and len(table.fields) >= 2: for field in table.fields: if field.name in ["wave", "waveobs"]: has_waveobs = True waveobs_units = field.unit elif field.name == "flux": has_flux = True if has_waveobs and has_flux: break if has_waveobs and has_flux: target_table = table break if has_waveobs and has_flux: break if target_table is not None: spectrum = np.recarray((len(target_table.array), ), dtype=[('waveobs', float), ('flux', float), ('err', float)]) if 'waveobs' in list(target_table.array.dtype.fields.keys()): spectrum['waveobs'] = target_table.array['waveobs'] elif 'wave' in list(target_table.array.dtype.fields.keys()): spectrum['waveobs'] = target_table.array['wave'] else: # the first column spectrum['waveobs'] = target_table.array[ target_table.array.dtype.names[0]] if 'flux' in list(target_table.array.dtype.fields.keys()): spectrum['flux'] = target_table.array['flux'] else: # the second column spectrum['flux'] = target_table.array[ target_table.array.dtype.names[1]] if 'err' in list(target_table.array.dtype.fields.keys()): spectrum['err'] = target_table.array['err'] elif 'error' in list(target_table.array.dtype.fields.keys()): spectrum['err'] = target_table.array['error'] elif 'errors' in list(target_table.array.dtype.fields.keys()): spectrum['err'] = target_table.array['errors'] if 'sigma' in list(target_table.array.dtype.fields.keys()): spectrum['err'] = target_table.array['sigma'] elif len(table.fields) >= 3: # the third column if exists spectrum['err'] = target_table.array[ target_table.array.dtype.names[2]] else: spectrum['err'] = 0.0 if target_table is None or spectrum is None: raise Exception("Table not compatible") return spectrum def __read_votable(self, url): votable = None if url.startswith('http://'): u = urllib.request.urlopen(url) tmp = tempfile.NamedTemporaryFile(mode="wt", suffix=".xml", delete=False, encoding='utf-8') tmp.write(u.read()) tmp.close() #print tmp.name votable = parse(tmp.name, pedantic=False) os.remove(tmp.name) elif url.startswith('file://localhost/'): filename = url[17:] if filename[0] != "/": filename = "/" + filename votable = parse(filename, pedantic=False) else: raise Exception("Unkown URL") return votable def __read_vofits(self, url): spectrum = None #print url if url.startswith('http://localhost/'): u = urllib.request.urlopen(url) tmp = tempfile.NamedTemporaryFile(mode="wt", suffix=".xml", delete=False, encoding='utf-8') tmp.write(u.read()) tmp.close() #print tmp.name hdulist = pyfits.open(tmp.name) os.remove(tmp) elif url.startswith('file://localhost/'): filename = url[17:] if filename[0] != "/": filename = "/" + filename hdulist = pyfits.open(filename) else: raise Exception("Unkown URL") # Find hdu containing data target_hdu = None for hdu in hdulist: if hdu.data is not None and len(hdu.data) > 0 and len( list(hdu.data.dtype.fields.keys())) >= 2: target_hdu = hdu spectrum = np.recarray((len(target_hdu.data), ), dtype=[('waveobs', float), ('flux', float), ('err', float)]) # the first column spectrum['waveobs'] = target_hdu.data[target_hdu.data.dtype.names[0]] # the second column spectrum['flux'] = target_hdu.data[target_hdu.data.dtype.names[1]] if len(list(hdu.data.dtype.fields.keys())) >= 3: # the third column if exists spectrum['err'] = target_hdu.data[target_hdu.data.dtype.names[2]] else: spectrum['err'] = 0.0 if target_hdu is None or spectrum is None: raise Exception("FITS not compatible") return spectrum def __spectrum_to_vofits(self, spectrum): t = pyfits.new_table(spectrum) t.header['TTYPE1'] = "WAVELENGTH" t.header['TTYPE2'] = "FLUX" t.header['TTYPE3'] = "SIGMA" fits = pyfits.HDUList(pyfits.PrimaryHDU()) fits.append(t) return fits def __spectrum_to_votable(self, spectrum): # Create a new VOTable file... votable = VOTableFile() # ...with one resource... resource = Resource() votable.resources.append(resource) # ... with one table table = Table(votable) resource.tables.append(table) # Define some fields waveobs = Field(votable, name="waveobs", datatype="double", unit="nm", ucd="em.wl") flux = Field(votable, name="flux", datatype="double", unit="Jy", ucd="phot.flux") err = Field(votable, name="err", datatype="double", ucd="stat.error;phot.flux") table.fields.extend([waveobs, flux, err]) table.groups.extend([Group([flux, err])]) #import ipdb #ipdb.set_trace() # Now, use those field definitions to create the numpy record arrays, with # the given number of rows table.create_arrays(len(spectrum)) # Now table.array can be filled with data table.array['waveobs'] = spectrum['waveobs'] table.array['flux'] = spectrum['flux'] table.array['err'] = spectrum['err'] #votable.set_all_tables_format('binary') # VOSpec does not understand binary format return votable ########### [end] File operations def get_subscribers(self): ids = [] names = [] as_tables = [] try: if self.samp_client.is_connected(): subscribers1 = self.samp_client.get_subscribed_clients( "table.load.votable") subscribers2 = self.samp_client.get_subscribed_clients( "spectrum.load.ssa-generic") subscribers = dict( list(subscribers1.items()) + list(subscribers2.items())) for subscriber in list(subscribers.keys()): metadata = self.samp_client.get_metadata(subscriber) name = "" if 'samp.name' in metadata: name = metadata['samp.name'] ids.append(subscriber) names.append(name) # Prefered form: "spectrum.load.ssa-generic" if subscriber in list(subscribers2.keys()): as_tables.append(False) else: as_tables.append(True) # If there are repeated names, add the identifier as a prefix uniq_names, uniq_names_index = np.unique(names, return_index=True) if len(names) != len(uniq_names): for i in np.arange(len(names)): # Only add a preffix to the repeated application names if i not in uniq_names_index: names[i] += " [" + ids[i] + "]" except Exception: pass return (ids, names, as_tables) # Broadcast a table file to TOPCAT def broadcast_spectrum(self, spectrum, spectrum_name, target_client, target_client_is_name=False, as_table=True, as_fits=False): if as_fits: suffix = ".fits" else: suffix = ".xml" tmp = tempfile.NamedTemporaryFile(mode="wt", suffix=suffix, delete=False, encoding='utf-8') tmp.close() if not as_fits: votable = self.__spectrum_to_votable(spectrum) votable.to_xml(tmp.name) else: fits = self.__spectrum_to_vofits(spectrum) fits.writeto(tmp.name, clobber=True) if as_table: mtype = 'table.load.votable' else: mtype = 'spectrum.load.ssa-generic' metadata = { 'samp.mtype': mtype, 'samp.params': { 'name': spectrum_name, 'table-id': spectrum_name, 'url': 'file://localhost/' + tmp.name } } if target_client_is_name: target_client_name = target_client target_client = self.__get_target_client(target_client_name) response = False if target_client is not None: try: response = self.samp_client.notify(target_client, metadata) logging.info("Spectrum sent via SAMP") except Exception: pass # Do not delete or the target client will not have time to read it #os.remove(tmp.name) return response
def __init__(self): self.sampClient = SAMPIntegratedClient( "A2P2 samp relay" ) # TODO get title from main program class instead of HardCoded value
class A2p2SampClient(): # TODO watch hub disconnection def __init__(self): self.sampClient = SAMPIntegratedClient( "A2P2 samp relay" ) # TODO get title from main program class instead of HardCoded value def __del__(self): self.disconnect() def connect(self): self.sampClient.connect() # an error is thrown here if no hub is present # TODO get samp client name and display it in the UI # Instantiate the receiver self.r = Receiver(self.sampClient) # Listen for any instructions to load a table self.sampClient.bind_receive_call("ob.load.data", self.r.receive_call) self.sampClient.bind_receive_notification("ob.load.data", self.r.receive_notification) def disconnect(self): self.sampClient.disconnect() def is_connected(self): # Workarround the 'non' reliable is_connected attribute # this helps to reconnect after hub connection lost try: return self.sampClient.is_connected and ( self.sampClient.ping() or self.sampClient.is_connected) except: # consider connection refused exception as not connected state return False def get_status(self): if self.is_connected(): return "connected [%s]" % (self.sampClient.get_public_id()) else: return "not connected" def get_public_id(self): return self.sampClient.get_public_id() def has_message(self): return self.is_connected() and self.r.received def clear_message(self): return self.r.clear() def get_ob_url(self): url = self.r.params['url'] if url.startswith("file:///"): return url[7:] elif url.startswith("file:/"): # work arround bugged file urls return url[5:] return url
def __init__(self): self._client = SAMPIntegratedClient()
class AladinViaSAMP(object): def __init__(self): self._client = SAMPIntegratedClient() def send_file(self, infile=str()): """Sending a file (image or table) to Aladin Sky Atlas using the SAMPIntegratedClient class. http://docs.astropy.org/en/stable/vo/samp/example_table_image.html """ self._client.connect() params = {} if sys.version > '3': params["url"] = urllib.parse.urljoin('file:', os.path.abspath(infile)) else: params["url"] = urlparse.urljoin('file:', os.path.abspath(infile)) message = {} message[ "samp.mtype" ] = "image.load.fits" message[ "samp.params" ] = params self._client.notify_all(message) self._client.disconnect() def move(self, script=str()): """Sending a script to Aladin Sky Atlas using the SAMPIntegratedClient class. http://docs.astropy.org/en/stable/vo/samp/example_table_image.html """ self._client.connect() params = {} message = {} message[ "samp.mtype" ] = "coord.pointAt.sky" message[ "samp.params" ] = { "script" : script } self._client.notify_all(message) self._client.disconnect() def send_script_command(self, script=str()): """Sending a script to Aladin Sky Atlas using the SAMPIntegratedClient class. http://docs.astropy.org/en/stable/vo/samp/example_table_image.html """ self._client.connect() params = {} message = {} message[ "samp.mtype" ] = "script.aladin.send" message[ "samp.params" ] = { "script" : script } self._client.notify_all(message) self._client.disconnect()
import os parser = argparse.ArgumentParser() parser.add_argument("-i", "--input", required=True, metavar="file", help="input JHV request file") parser.add_argument("-value", help="Send request as message value", action="store_true") args = parser.parse_args() input_file = os.path.abspath(args.input) client = SAMPIntegratedClient() client.connect() params = {} if args.value: with open(input_file, "r") as f: params["value"] = f.read() else: params["url"] = input_file message = {} message["samp.mtype"] = "jhv.load.request" message["samp.params"] = params client.notify_all(message)
class ClientRunner(object): #class ClientRunner(QThread): def __init__(self, iface, pinstance): self.iface = iface # self.dlg = VOScriptReceiverDialog() self.dlg = ClientRunnerDialog() self.MSG = self.dlg.label.setText self.ProjInstance = pinstance self.root = self.ProjInstance.layerTreeRoot() self.connectionState = False self.dlg.connectBtn.clicked.connect(self.switchCState) def capCommand(self, *args, **kwargs): MSG = self.MSG self.cli = SAMPIntegratedClient() self.cli.connect() self.r = Receiver(self.cli) MSG('Binding methods') #=> case MTYPE: qgis.message def qMessage(): MSG('Message: ' + self.r.params['script']) #=> case MTYPE: qgis.load.vectorlayer def qLoadVectorlayer(): # case MTYPE: qgis.load.vectorlayer self.LoadVectorLayer(self.r.params['url'], self.r.params['name']) #=> case MTYPE: table.load.votable def qLoadVotable(): loadWMS = lambda vot: VOTableLoaderHelper.loadWMS( vot, self.iface, self.root) makeComplFeat = VOTableLoaderHelper.makeComplFeat MSG('Loading VOtable\n from url: \n' + self.r.params['url']) say('SAMP Params are: ' + str(self.r.params)) vot = Table.read(download_file(self.r.params['url'], timeout=200)) #fixes timeout bug if 'access_format' in vot.colnames: say(str(vot.columns['access_format'][0])) #<+=== if b'application/x-wms' in vot.columns['access_format'][0]: try: loadWMS(vot) except Exception: self.MSG('OOPS something went wrong while loading WMS') tb = traceback.format_exc() say(tb) finally: return mURL = tempfile.mkdtemp() MSG("converting to GeoJSON") say('Number of features to write: ' + str(len(vot))) featList = [] for i in range(len(vot)): self.MSG('writing number' + str(i)) featList.append(makeComplFeat(vot, i)) with open(mURL + '/vot.geojson', 'w') as f: f.write( geojson.dumps({ "type": "FeatureCollection", "features": featList })) self.MSG('finished download, converting to SpatiaLite') try: vlayer = QgsVectorLayer(mURL + '/vot.geojson', "mygeojson", "ogr") except Exception: self.MSG( 'OOPS something went wrong while creating a vector layer from geojson' ) return say("writing to SpatiaLite") try: QgsVectorFileWriter.writeAsVectorFormat( vlayer, mURL + r"/vot.sqlite", "utf-8", None, "SpatiaLite") except Exception: self.MSG('OOPS something went wrong while writing SQLite') return say("loading SpatiaLite") try: vlayer = QgsVectorLayer(mURL + r"/vot.sqlite", str(self.r.params['name']), "ogr") except Exception: self.MSG( 'OOPS something went wrong while creating a vector Layer') return # say(vot.meta['description']) #description is not available with complex queries # vlayer = QgsVectorLayer( mURL+r"/vot.sqlite",str(vot.meta['description']),"ogr") say("adding layer to canvas") try: self.addVLayerToCanvas(vlayer) except Exception: self.MSG( 'OOPS something went wrong while trying to add layer to canvas' ) return say("done") mTypeDict = { 'qgis.message': qMessage, 'qgis.load.vectorlayer': qLoadVectorlayer, 'table.load.votable': qLoadVotable } map(self.bindSamp, mTypeDict.keys()) MSG("Disconnected") while self.connectionState: MSG("starting") self.r.received = False while not self.r.received and self.connectionState: MSG("waiting") ttime.sleep(2) if self.connectionState: mTypeDict[self.r.mtype]() ttime.sleep(2) def switchCState(self, *args, **kwargs): sys.stdout.write('switching state') say("Switching connection state") self.connectionState = not self.connectionState say("New state is " + str(self.connectionState)) if self.connectionState: self.tc = threading.Thread(name="client", target=self.capCommand, args=(self, )) self.tc.start() else: self.cli.disconnect() self.MSG('Disconnected') def bindSamp(self, MType): self.cli.bind_receive_call(MType, self.r.receive_call) self.cli.bind_receive_notification(MType, self.r.receive_notification) def addVLayerToCanvas(self, vlayer): self.iface.mapCanvas().freeze() QgsMapLayerRegistry.instance().addMapLayer( vlayer) # order is importaint here # self.root.addLayer(vlayer) self.root.insertLayer(0, vlayer) QgsMapLayerRegistry.instance().reloadAllLayers() self.iface.mapCanvas().freeze(False) def run(self): self.dlg.show() # self.MSG("hello") self.MSG("Disconnected") result = self.dlg.exec_() if self.connectionState: self.cli.disconnect( ) # if user closes window - call disconnect to make sure
def capCommand(self, *args, **kwargs): MSG = self.MSG self.cli = SAMPIntegratedClient() self.cli.connect() self.r = Receiver(self.cli) MSG('Binding methods') #=> case MTYPE: qgis.message def qMessage(): MSG('Message: ' + self.r.params['script']) #=> case MTYPE: qgis.load.vectorlayer def qLoadVectorlayer(): # case MTYPE: qgis.load.vectorlayer self.LoadVectorLayer(self.r.params['url'], self.r.params['name']) #=> case MTYPE: table.load.votable def qLoadVotable(): loadWMS = lambda vot: VOTableLoaderHelper.loadWMS( vot, self.iface, self.root) makeComplFeat = VOTableLoaderHelper.makeComplFeat MSG('Loading VOtable\n from url: \n' + self.r.params['url']) say('SAMP Params are: ' + str(self.r.params)) vot = Table.read(download_file(self.r.params['url'], timeout=200)) #fixes timeout bug if 'access_format' in vot.colnames: say(str(vot.columns['access_format'][0])) #<+=== if b'application/x-wms' in vot.columns['access_format'][0]: try: loadWMS(vot) except Exception: self.MSG('OOPS something went wrong while loading WMS') tb = traceback.format_exc() say(tb) finally: return mURL = tempfile.mkdtemp() MSG("converting to GeoJSON") say('Number of features to write: ' + str(len(vot))) featList = [] for i in range(len(vot)): self.MSG('writing number' + str(i)) featList.append(makeComplFeat(vot, i)) with open(mURL + '/vot.geojson', 'w') as f: f.write( geojson.dumps({ "type": "FeatureCollection", "features": featList })) self.MSG('finished download, converting to SpatiaLite') try: vlayer = QgsVectorLayer(mURL + '/vot.geojson', "mygeojson", "ogr") except Exception: self.MSG( 'OOPS something went wrong while creating a vector layer from geojson' ) return say("writing to SpatiaLite") try: QgsVectorFileWriter.writeAsVectorFormat( vlayer, mURL + r"/vot.sqlite", "utf-8", None, "SpatiaLite") except Exception: self.MSG('OOPS something went wrong while writing SQLite') return say("loading SpatiaLite") try: vlayer = QgsVectorLayer(mURL + r"/vot.sqlite", str(self.r.params['name']), "ogr") except Exception: self.MSG( 'OOPS something went wrong while creating a vector Layer') return # say(vot.meta['description']) #description is not available with complex queries # vlayer = QgsVectorLayer( mURL+r"/vot.sqlite",str(vot.meta['description']),"ogr") say("adding layer to canvas") try: self.addVLayerToCanvas(vlayer) except Exception: self.MSG( 'OOPS something went wrong while trying to add layer to canvas' ) return say("done") mTypeDict = { 'qgis.message': qMessage, 'qgis.load.vectorlayer': qLoadVectorlayer, 'table.load.votable': qLoadVotable } map(self.bindSamp, mTypeDict.keys()) MSG("Disconnected") while self.connectionState: MSG("starting") self.r.received = False while not self.r.received and self.connectionState: MSG("waiting") ttime.sleep(2) if self.connectionState: mTypeDict[self.r.mtype]() ttime.sleep(2)
def __init__(self): self.client = SAMPIntegratedClient() self.tmp_files = []
def connect(self): self.__client = SAMPIntegratedClient(name=self.__server_name, metadata=self.sampMetadata()) self.__client.connect() self.bind_to_server()
class SAMPManager(): __client = None __received = False __params = {} __hub = None __server_name = "frastro server" __server_description = "frastro Web client" __server_description_html = "<h1>frastro Web client</h1>" __author = "Camilo E. Jimenez-Angel" __instritution = "IAC" __email_contact = "*****@*****.**" __url_icon = "http://localhost:8000/static/img/frastro_icon.jpg" def __init__(self, server_name=""): # Instantiate the client and connect to the hub self.__server_name = server_name if server_name != "" else self.__server_name self.connect() def starHubServer(self, web_profile=True): if self.__hub is None: self.__hub = SAMPHubServer(web_profile=web_profile, label=self.__server_name) self.__hub.start() def receive_call(self, private_key, sender_id, msg_id, mtype, params, extra): self.__params = params self.__received = True self.__client.reply(msg_id, { "samp.status": "samp.ok", "samp.result": {} }) def receive_notification(self, private_key, sender_id, mtype, params, extra): self.__params = params self.__received = True def bind_to_server(self): # Listen for any instructions to load a table self.__client.bind_receive_call("table.load.votable", self.receive_call) self.__client.bind_receive_notification("table.load.votable", self.receive_notification) def sampMetadata(self): meta = { "samp.name": self.__server_name, "samp.description.text": self.__server_description, "samp.description.html": self.__server_description_html, "samp.icon.url": self.__url_icon, "author.affiliation": self.__instritution, "author.name": self.__author, "author.email": self.__email_contact } return meta def getRegisteredClients(self): clients = self.__client.get_registered_clients() run_clients = {} for client in clients: client_data = self.getMetadata(client) run_clients[client] = client_data return run_clients def getMetadata(self, client_id): return self.__client.get_metadata(client_id) def sendTable(self, message, recipient="all"): if recipient == "all": self.__client.notify_all(message) else: self.__client.notify(recipient, message) def connect(self): self.__client = SAMPIntegratedClient(name=self.__server_name, metadata=self.sampMetadata()) self.__client.connect() self.bind_to_server() def sendImage(self, params, id=""): message = {} message["samp.mtype"] = "image.load.fits" message["samp.params"] = params if id == "" or id == "all": self.__client.notify_all(message) else: self.__client.notify(recipient_id=id, message=message) def sendMessage(self, params, id=""): message = {} message["samp.mtype"] = "table.load.votable" message["samp.params"] = params if id == "" or id == "all": self.__client.notify_all(message) else: self.__client.notify(recipient_id=id, message=message) def disconnect(self): self.__client.disconnect() def __del__(self): self.disconnect()
def __init__(self): super(SAMPState, self).__init__() self.hub = SAMPHubServer() self.client = SAMPIntegratedClient() self.add_callback('connected', self.on_connected)