Exemplo n.º 1
0
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
Exemplo n.º 2
0
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
Exemplo n.º 3
0
 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)
Exemplo n.º 4
0
    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()
Exemplo n.º 5
0
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()
Exemplo n.º 8
0
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()
Exemplo n.º 9
0
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()
Exemplo n.º 10
0
    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)
Exemplo n.º 11
0
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
Exemplo n.º 12
0
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
Exemplo n.º 13
0
 def __init__(self):
     self.sampClient = SAMPIntegratedClient(
         "A2P2 samp relay"
     )  # TODO get title from main program class instead of HardCoded value
Exemplo n.º 14
0
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
Exemplo n.º 15
0
 def __init__(self):
     self._client = SAMPIntegratedClient()
Exemplo n.º 16
0
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()
Exemplo n.º 17
0
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)
Exemplo n.º 18
0
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
Exemplo n.º 19
0
    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)
Exemplo n.º 20
0
 def __init__(self):
     self.client = SAMPIntegratedClient()
     self.tmp_files = []
Exemplo n.º 21
0
 def connect(self):
     self.__client = SAMPIntegratedClient(name=self.__server_name,
                                          metadata=self.sampMetadata())
     self.__client.connect()
     self.bind_to_server()
Exemplo n.º 22
0
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()
Exemplo n.º 23
0
 def __init__(self):
     super(SAMPState, self).__init__()
     self.hub = SAMPHubServer()
     self.client = SAMPIntegratedClient()
     self.add_callback('connected', self.on_connected)