Example #1
0
 def run(self, result=None):
     # argv is rosargs but these have no effect on client, so no need to pass anything here
     with pyros.pyros_ctx(name='rostful',
                          argv=[],
                          mock_client=True,
                          base_path=os.path.join(os.path.dirname(__file__),
                                                 '..', '..',
                                                 '..')) as node_ctx:
         self.node_ctx = node_ctx
         set_pyros_client(self.node_ctx.client)
         super(TestTopicsPyros, self).run(result)
Example #2
0
def run(host, port, server, config, logfile, ros_args):
    """
    Start rostful server.
    :param host: the local IP on which to serve rostful (0.0.0.0 for all)
    :param port: the local port on which to serve rostful
    :param server: the server to run our WSGI app (flask or tornado)
    :param config: the config file path, absolute, or relative to working directory
    :param logfile: the logfile path, absolute, or relative to working directory
    :param ros_args: the ros arguments (useful to absorb additional args when launched with roslaunch)
    TODO : get doctests to work here
    >>> run('127.0.0.1', '8888', False, 'flask', None, None)
    []
    >>> run('127.0.0.1', '8888', True, 'flask', None, None)
    >>> run('127.0.0.1', '4444', False, 'tornado', None, None)
    >>> run()

    """
    if port and isinstance(port, (str, unicode)):
        port = int(port)

    app = create_app(configfile_override=config, logfile=logfile)

    # Some logic for defaults value (might depend on config)
    server = server or app.config.get('SERVER_TYPE', 'tornado')

    app.logger.info(
        'rostful started with : host {host} port {port} config {config} logfile {logfile} ros_args {ros_args}'
        .format(host=host,
                port=port,
                config=config,
                logfile=logfile,
                ros_args=ros_args))

    # Starting pyros with latest config
    # TODO : move this out of here and let the user do it :
    # in ROS case : it should be done in launch file, and connect on user request (maybe even pass the zmq socket url)
    # in pyzmp case : it should be done dynamically, as much as possible outside of here.
    with pyros_start(config=app.config, ros_args=ros_args) as node_ctx:

        set_pyros_client(app, node_ctx.client)

        # configure logger

        # add log handler for warnings and more to sys.stderr.
        app.logger.addHandler(logging.StreamHandler())
        app.logger.setLevel(logging.WARN)

        import socket  # just to catch the "Address already in use" error
        port_retries = 5
        while port_retries > 0:  # keep trying
            try:
                # default server should be solid and production ready
                if server == 'flask':

                    log = logging.getLogger('werkzeug')
                    log.setLevel(logging.DEBUG)

                    app.logger.info(
                        'Starting Flask server on port {0}'.format(port))
                    # debug is needed to investigate server errors.
                    # use_reloader set to False => killing the ros node also kills the server child.
                    app.run(
                        host=host,
                        port=port,
                        debug=True,
                        use_reloader=False,
                    )
                elif server == 'tornado':

                    # Only import if needed
                    from tornado.wsgi import WSGIContainer
                    from tornado.httpserver import HTTPServer
                    from tornado.ioloop import IOLoop
                    from tornado.log import enable_pretty_logging

                    port = port or '5000'  # same default as flask
                    host = host or '127.0.0.1'  # same default as flask

                    app.logger.info(
                        'Starting Tornado server on {0}:{1}'.format(
                            host, port))
                    # enable_pretty_logging()  # enable this for debugging during development
                    http_server = HTTPServer(WSGIContainer(app))
                    http_server.listen(port)
                    IOLoop.instance().start()
                # TODO : support more wsgi server setup : http://www.markjberger.com/flask-with-virtualenv-uwsgi-nginx/
                break
            except socket.error as msg:
                port_retries -= 1
                port += 1
                app.logger.error('Socket Error : {0}'.format(msg))
Example #3
0
    def launch(self, host=None, port=None, ros_args='', serv_type='tornado', pyros_ctx_impl=None):
        """
        Launch the current WSGI app in a web server (tornado or flask simple server)
        Will block until server is killed.

        :param host: the local ip to listen for connection on
        :param port: the local port to listen for connection on
        :param ros_args: the provided ros arguments that will be passed onto pyros node
        :param serv_type: the server type (tornado or flask)
        :param pyros_ctx_impl: the implementation of pyros context manager ( if different from normal module ).
                               This is useful for mocking it.
        :return: None
        """

        # default to real module, if no other implementation passed as parameter (used for mock)
        pyros_ctx_impl = pyros_ctx_impl or pyros_ctx

        if port and isinstance(port, (str, unicode)):
            port = int(port)

        # implementing Config.get_namespace() for flask version < 1.0:
        namespace = 'PYROS_'
        trim_namespace = True
        lowercase = False
        rv = {}
        for k, v in six.iteritems(self.app.config):
            if not k.startswith(namespace):
                continue
            if trim_namespace:
                key = k[len(namespace):]
            else:
                key = k
            if lowercase:
                key = key.lower()
            rv[key] = v
        # rv should now contain a dictionary of namespaced key:value from self.app.config

        # One PyrosNode is needed for Flask.
        # TODO : check everything works as expected, even if the WSGI app is used by multiple processes

        try:
            node_ctx_gen = pyros_ctx_impl(name='rostful', argv=ros_args, pyros_config=rv)
        except TypeError as te:
            # bwcompat trick
            node_ctx_gen = pyros_ctx_impl(name='rostful', argv=ros_args,
                                base_path=os.path.join(os.path.dirname(__file__), '..', '..', '..'))

        with node_ctx_gen as node_ctx:
            set_pyros_client(node_ctx.client)

            # configure logger
            #if not debug:
            # add log handler for warnings and more to sys.stderr.
            #    self.logger.addHandler(logging.StreamHandler())
            #    self.logger.setLevel(logging.WARN)

            import socket  # just to catch the "Address already in use" error
            port_retries = 5
            while port_retries > 0:  # keep trying
                try:
                    # default server should be solid and production ready
                    serv_type = serv_type or self.app.config.get('SERVER_TYPE', 'tornado')
                    if serv_type == 'flask':

                        log = logging.getLogger('werkzeug')
                        log.setLevel(logging.DEBUG)

                        self.app.logger.info('Starting Flask server on port {0}'.format(port))
                        # debug is needed to investigate server errors.
                        # use_reloader set to False => killing the ros node also kills the server child.
                        self.app.run(
                            host=host,
                            port=port,
                            debug=True,
                            use_reloader=False,
                        )
                    elif serv_type == 'tornado':

                        port = port or '5000'  # same default as flask
                        host = host or '127.0.0.1'  # same default as flask

                        self.app.logger.info('Starting Tornado server on {0}:{1}'.format(host, port))
                        # enable_pretty_logging()  # enable this for debugging during development
                        http_server = HTTPServer(WSGIContainer(self.app))
                        http_server.listen(port)
                        IOLoop.instance().start()
                    # TODO : support more wsgi server setup : http://www.markjberger.com/flask-with-virtualenv-uwsgi-nginx/
                    break
                except socket.error as msg:
                    port_retries -= 1
                    port += 1
                    self.app.logger.error('Socket Error : {0}'.format(msg))
Example #4
0
 def run(self, result=None):
     # argv is rosargs but these have no effect on client, so no need to pass anything here
     with pyros.pyros_ctx(name='rostful', argv=[], mock_client=True, base_path=os.path.join(os.path.dirname(__file__), '..', '..', '..')) as node_ctx:
         self.node_ctx = node_ctx
         set_pyros_client(self.node_ctx.client)
         super(TestServicesPyros, self).run(result)
Example #5
0
def run(host, port, server, config, logfile, ros_args):
    """
    Start rostful server.
    :param host: the local IP on which to serve rostful (0.0.0.0 for all)
    :param port: the local port on which to serve rostful
    :param server: the server to run our WSGI app (flask or tornado)
    :param config: the config file path, absolute, or relative to working directory
    :param logfile: the logfile path, absolute, or relative to working directory
    :param ros_args: the ros arguments (useful to absorb additional args when launched with roslaunch)
    TODO : get doctests to work here
    >>> run('127.0.0.1', '8888', False, 'flask', None, None)
    []
    >>> run('127.0.0.1', '8888', True, 'flask', None, None)
    >>> run('127.0.0.1', '4444', False, 'tornado', None, None)
    >>> run()

    """
    if port and isinstance(port, (str, unicode)):
        port = int(port)

    app = create_app(configfile_override=config, logfile=logfile)

    # Some logic for defaults value (might depend on config)
    server = server or app.config.get('SERVER_TYPE', 'tornado')

    app.logger.info(
        'rostful started with : host {host} port {port} config {config} logfile {logfile} ros_args {ros_args}'.format(
            host=host, port=port, config=config, logfile=logfile, ros_args=ros_args))

    # Starting pyros with latest config
    # TODO : move this out of here and let the user do it :
    # in ROS case : it should be done in launch file, and connect on user request (maybe even pass the zmq socket url)
    # in pyzmp case : it should be done dynamically, as much as possible outside of here.
    with pyros_start(config=app.config, ros_args=ros_args) as node_ctx:

        set_pyros_client(app, node_ctx.client)

        # configure logger

        # add log handler for warnings and more to sys.stderr.
        app.logger.addHandler(logging.StreamHandler())
        app.logger.setLevel(logging.WARN)

        import socket  # just to catch the "Address already in use" error
        port_retries = 5
        while port_retries > 0:  # keep trying
            try:
                # default server should be solid and production ready
                if server == 'flask':

                    log = logging.getLogger('werkzeug')
                    log.setLevel(logging.DEBUG)

                    app.logger.info('Starting Flask server on port {0}'.format(port))
                    # debug is needed to investigate server errors.
                    # use_reloader set to False => killing the ros node also kills the server child.
                    app.run(
                        host=host,
                        port=port,
                        debug=True,
                        use_reloader=False,
                    )
                elif server == 'tornado':

                    # Only import if needed
                    from tornado.wsgi import WSGIContainer
                    from tornado.httpserver import HTTPServer
                    from tornado.ioloop import IOLoop
                    from tornado.log import enable_pretty_logging

                    port = port or '5000'  # same default as flask
                    host = host or '127.0.0.1'  # same default as flask

                    app.logger.info('Starting Tornado server on {0}:{1}'.format(host, port))
                    # enable_pretty_logging()  # enable this for debugging during development
                    http_server = HTTPServer(WSGIContainer(app))
                    http_server.listen(port)
                    IOLoop.instance().start()
                # TODO : support more wsgi server setup : http://www.markjberger.com/flask-with-virtualenv-uwsgi-nginx/
                break
            except socket.error as msg:
                port_retries -= 1
                port += 1
                app.logger.error('Socket Error : {0}'.format(msg))
Example #6
0
 def run(self, result=None):
     # argv is rosargs but these have no effect on client, so no need to pass anything here
     with pyros.pyros_ctx(name='rostful', argv=[], mock_client=True) as node_ctx:
         self.node_ctx = node_ctx
         set_pyros_client(self.node_ctx.client)
         super(TestAppPyros, self).run(result)
Example #7
0
 def setUp(self):
     super(TestAppPyros, self).setUp()
     set_pyros_client(self.app, self.node_ctx.client)
Example #8
0
 def setUp(self):
     super(TestAppPyros, self).setUp()
     set_pyros_client(self.app, self.node_ctx.client)