Ejemplo n.º 1
0
class API:
    """API Class of Arche Framework"""
    def __init__(self, templates_dir="templates", static_dir="static"):
        self.routes = {}
        self.templates_env = Environment(
            loader=FileSystemLoader(os.path.abspath(templates_dir)))
        self.exception_handler = None
        self.whitenoise = WhiteNoise(self._wsgi_app, root=static_dir)
        self.middleware = Middleware(self)

    def add_route(self, path, handler):
        assert path not in self.routes, "A route already exists"
        self.routes[path] = handler

    def route(self, path):
        assert path not in self.routes, "A route already exists"

        def wrapper(handler):
            self.add_route(path, handler)
            return handler

        return wrapper

    def _wsgi_app(self, env, start_response):
        request = Request(env)
        response = self.handle_request(request)

        return response(env, start_response)

    def __call__(self, env, start_response):
        path_info = env["PATH_INFO"]
        if path_info.startswith("/static"):
            env["PATH_INFO"] = path_info[len("/static"):]
            return self.whitenoise(env, start_response)

        return self.middleware(env, start_response)

    def handle_request(self, request):
        response = Response()

        try:
            handler, kwargs = self.find_handler(request_path=request.path)

            if handler is not None:
                if inspect.isclass(handler):
                    handler = getattr(handler(), request.method.lower(), None)
                    if handler is None:
                        raise AttributeError("Method Not Allowed: ",
                                             request.method)
                handler(request, response, **kwargs)
            else:
                self.default_response(response)
        except Exception as e:
            if self.exception_handler is None:
                raise e
            else:
                self.exception_handler(request, response, e)

        return response

    def find_handler(self, request_path):
        for path, handler in self.routes.items():
            parse_result = parse(path, request_path)
            if parse_result is not None:
                return handler, parse_result.named

        return None, None

    def default_response(self, response):
        response.status_code = 404
        response.text = "OOPS! Your requested page is not Found."

    # TODO:
    def add_exception_handler(self, exception_handler):
        self.exception_handler = exception_handler

    def template(self, template_name, context=None):
        if context is None:
            context = {}

        return self.templates_env.get_template(template_name).render(**context)

    def add_middleware(self, middleware_cls):
        self.middleware.add(middleware_cls)

    # Test Session
    def test_session(self, base_url="http://testserver"):
        session = RequestSession()
        session.mount(prefix=base_url, adapter=RequestsWSGIAdapter(self))
        return session
Ejemplo n.º 2
0
class API:
    def __init__(self, templates_dir="templates", static_dir="static"):
        self.routes = {}
        self.exception_handler = None
        self.templates_env = Environment(loader=FileSystemLoader(
            searchpath=os.path.abspath(templates_dir)))
        self.whitenoise = WhiteNoise(application=self.wsgi_app,
                                     root=static_dir)
        self.middleware = Middleware(self)

    def __call__(self, environ, start_response):
        """ We need to distinguish if the request if for static files and use
        WhiteNoise, or for data and use the Middleware
        """
        path_info = environ["PATH_INFO"]
        if path_info.startswith("/static"):
            environ["PATH_INFO"] = path_info[len("/static"):]
            return self.whitenoise(environ, start_response)
        return self.middleware(environ, start_response)

    def wsgi_app(self, environ, start_response):
        request = Request(environ)
        response = self.handle_request(request)
        return response(environ, start_response)

    def test_session(self, base_url=BASE_URL):
        session = RequestsSession()
        session.mount(prefix=base_url, adapter=RequestsWSGIAdapter(self))
        return session

    def add_middleware(self, middleware_cls):
        self.middleware.add(middleware_cls)

    @staticmethod
    def default_response(response):
        response.status_code = 404
        response.text = "Not found."

    def add_exception_handler(self, exception_handler):
        self.exception_handler = exception_handler

    def find_handler(self, request_path):
        """ Look for the corresponding handler for the incoming path """
        for path, handler_data in self.routes.items():
            parsed_result = parse(path, request_path)
            if parsed_result is not None:
                return handler_data, parsed_result.named
        return None, None

    def handle_request(self, request):

        response = Response()
        handler_data, kwargs = self.find_handler(request_path=request.path)

        try:
            if handler_data:
                handler = handler_data["handler"]
                allowed_methods = handler_data["allowed_methods"]
                if inspect.isclass(handler):
                    handler = getattr(handler(), request.method.lower(), None)
                    if handler is None:
                        raise AttributeError("Method not allowed",
                                             request.method)
                else:
                    if request.method.lower() not in allowed_methods:
                        raise AttributeError("Method not allowed",
                                             request.method)
                handler(request, response, **kwargs)
            else:
                self.default_response(response)
        except Exception as e:
            if self.exception_handler is None:
                raise e
            else:
                self.exception_handler(request, response, e)
        return response

    def add_route(self, path, handler, allowed_methods=None):
        assert path not in self.routes, "Such route already exists."
        if allowed_methods is None:
            allowed_methods = [
                "get", "post", "put", "patch", "delete", "options"
            ]
        self.routes[path] = {
            "handler": handler,
            "allowed_methods": allowed_methods
        }

    def route(self, path, allowed_methods=None):
        if path in self.routes.keys():
            raise AssertionError("Duplicated route")

        def wrapper(handler):
            self.add_route(path, handler, allowed_methods)
            return handler

        return wrapper

    def template(self, template_name, context=None):
        context = {} or context
        return self.templates_env.get_template(name=template_name).render(
            **context)
Ejemplo n.º 3
0
class API:
    def __init__(self, templates_dir="templates", static_dir="static"):
        self.routes = {}
        self.templates_env = Environment(
            loader=FileSystemLoader(os.path.abspath(templates_dir)))
        self.exception_handler = None
        self.whitenoise = WhiteNoise(self.wsgi_app, root=static_dir)
        self.static_dir = os.path.abspath(static_dir)
        self._static_root = "/static"

        self.middleware = Middleware(self)

    def wsgi_app(self, environ, start_response):
        request = Request(environ)
        response = self.handle_request(request)

        return response(environ, start_response)

    def __call__(self, environ, start_response):
        path_info = environ["PATH_INFO"]

        if request_for_static(path_info, self._static_root):
            environ["PATH_INFO"] = cut_static_root(path_info,
                                                   self._static_root)
            return self.whitenoise(environ, start_response)

        return self.middleware(environ, start_response)

    def add_middleware(self, middleware_cls):
        self.middleware.add(middleware_cls)

    def route(self, path):
        def wrapper(handler):
            self.add_route(path, handler)
            return handler

        return wrapper

    def add_route(self, path, handler):
        assert path not in self.routes, f"{path} already exists."

        self.routes[path] = handler

    def test_session(self, base_url="http:''testserver"):
        session = RequestsSession()
        session.mount(prefix=base_url, adapter=RequestsWSGIAdapter(self))
        return session

    def handle_request(self, request):
        response = Response()

        handler, kwargs = self.find_handler(request_path=request.path)

        try:
            if handler is not None:
                if inspect.isclass(handler):
                    handler = getattr(handler(), request.method.lower(), None)
                    if handler is None:
                        raise AttributeError("Method in not allowed",
                                             request.method)
                handler(request, response, **kwargs)
            else:
                self.default_response(response)
        except Exception as e:
            if self.exception_handler is None:
                raise e
            else:
                self.exception_handler(request, response, e)

        return response

    def default_response(self, response):
        response.status_code = 404
        response.text = "Not found"

    def find_handler(self, request_path):
        for path, handler in self.routes.items():
            parse_result = parse(path, request_path)
            if parse_result is not None:
                return handler, parse_result.named

        return None, None

    def template(self, template_name, context=None):
        if context is None:
            context = {}

        return self.templates_env.get_template(template_name).render(**context)

    def add_exception_handler(self, exception_handler):
        self.exception_handler = exception_handler
Ejemplo n.º 4
0
class API(object):
    def __init__(self, templates_dir="templates", static_dir="static"):
        self.templates_dir = templates_dir
        self.static_dir = static_dir
        # url路由
        self.routes = {}
        # html文件夹
        self.templates_env = Environment(
            loader=FileSystemLoader(os.path.abspath(self.templates_dir)))
        # css、JavaScript文件夹
        self.whitenoise = WhiteNoise(self.wsgi_app, root=static_dir)
        # 自定义错误
        self.exception_handler = None
        # 请求中间件,将api对象传入
        self.middleware = Middleware(self)

    def template(self, template_name, context=None):
        """返回模板内容"""
        if context is None:
            context = {}
        return self.templates_env.get_template(template_name).render(**context)

    # 不用webob只能直接返回二进制数据
    # def __call__(self, environ, start_response):
    #     response_body = b'Hello, World!'
    #     status = '200 OK'
    #     start_response(status, headers=[])
    #     return iter([response_body])

    def wsgi_app(self, environ, start_response):
        """通过 webob 将请求的环境信息转为request对象"""
        request = Request(environ)
        response = self.handle_request(request)
        return response(environ, start_response)

    def __call__(self, environ, start_response):
        path_info = environ["PATH_INFO"]
        static = "/" + self.static_dir
        # 以 /static 开头 或 中间件为空
        if path_info.startswith(static) or not self.middleware:
            # "/static/index.css" -> 只取 /index.css, /static开头只是用于判断
            environ["PATH_INFO"] = path_info[len(static):]
            return self.whitenoise(environ, start_response)
        return self.middleware(environ, start_response)

    def handle_request(self, request):
        """请求调度"""
        response = Response()
        handler, kwargs = self.find_handler(request.path)

        try:
            if handler is not None:
                if inspect.isclass(handler):  # 如果是类,则获取其中的方法
                    handler = getattr(handler(), request.method.lower(), None)
                    if handler is None:  # 类中该方法不存在,则该类不支持该请求类型
                        raise AttributeError("Method now allowed",
                                             request.method)
                handler(request, response, **kwargs)
            else:
                self.defalut_response(response)
        except Exception as e:
            if self.exception_handler is None:
                raise e
            else:
                # 自定义错误返回形式
                self.exception_handler(request, response, e)
        return response

    def find_handler(self, request_path):
        for path, handler in self.routes.items():
            parse_result = parse(path, request_path)
            if parse_result is not None:
                return handler, parse_result.named
        return None, None

    def defalut_response(self, response):
        response.status_code = 404
        response.text = "Not Found"

    def route(self, path):
        # 添加路由的装饰器
        def wrapper(handler):
            self.add_route(path, handler)
            return handler

        return wrapper

    def add_route(self, path, handler):
        # 相同路径不可重复添加
        assert path not in self.routes, "Such route already exists"
        self.routes[path] = handler

    def add_exception_handler(self, exception_handler):
        # 添加自定义error handler
        self.exception_handler = exception_handler

    def add_middleware(self, middleware_cls):
        # 添加中间件
        self.middleware.add(middleware_cls)
Ejemplo n.º 5
0
class API:
    def __init__(self, templates_directory="templates", static_dir="static"):
        self.routes = {} #paths are the keys and handlers (functions or classes) are the values

        self.templates_environment = Environment(
            loader=FileSystemLoader(os.path.abspath(templates_directory))
        )

        self.exception_handler = None

        self.whitenoise = WhiteNoise(self.wsgi_application, root=static_dir) #wrap wsgi application to serve static files
        
        self.middleware = Middleware(self)

    def __call__(self, environ, start_response):
       """
       Compatible WSGI server will call for each client HTTP request. 
       Request for static files are treated differently from other request.
       """
       
       print("Callable was triggered due to request from client application at time: " + str(time.time()))
       
       path_info = environ["PATH_INFO"]

       if path_info.startswith("/static"):
           environ["PATH_INFO"] = path_info[len("/static"):]
           print(environ["PATH_INFO"])
           return self.whitenoise(environ, start_response)
       else:
           return self.middleware(environ, start_response)

    def wsgi_application(self, environ, start_response):
        request = Request(environ)

        response = self.handle_request(request)

        return response(environ, start_response)

    """
    Middleware
    """
    def add_middleware(self, middleware_cls):
        self.middleware.add(middleware_cls)

    """
    TEST CLIENT
    """
    def test_session(self, base_url="http://testserver"):
        """
        Creates a test client associated with the given a url.
        The test session will be a requests session to be able to
        emulate a client in the browser.
        """
        session = RequestsSession()
        session.mount(prefix=base_url, adapter=RequestsWSGIAdapter(self))
        return session

    """
    ROUTING
    """
    def add_route(self, path, handler):
        """
        Adds a route which is a key-value pair.
        The key is the url path and the value is either
        a function handler or a class-based route.
        """
        if path in self.routes:
            raise AssertionError("Failed. Such a route already exists.")

        self.routes[path] = handler

    def route(self, path):
        """
        Adds a route via a decorator function.
        """
        def wrapper(handler):
            self.routes[path] = handler
            return handler

        return wrapper

    """
    TEMPLATING
    """
    def get_template(self, template_name, context=None):
        """
        Gets the template based on the template name
        """
        if context is None: 
            context = {}
        
        return self.templates_environment.get_template(template_name).render(**context)

    """
    HANDLING
    """
    def handle_request(self, request):
        """
        Handles the client request, which is an webob object.
        """
        response = Response()

        handler, kwargs = self.lookup_handler(request_path=request.path)

        try:
            if handler is not None:
                if inspect.isclass(handler):
                    handler_method = self.get_class_method(handler, request)
                    if handler_method is None:
                        raise AttributeError("Method not allowed", request.method)
                    
                    handler_method(request, response, **kwargs)
                else:
                    handler(request, response, **kwargs)
            else:
                self.default_response(response)
        except Exception as exception:
            if self.exception_handler is None:
                raise exception
            else:
                self.exception_handler(request, response, exception)

        return response
    
    def get_class_method(self, handler, request):
        """
        Gets the method associated with the requested path.
        This function is used with class based routes.
        """
        handler_method = getattr(handler(),request.method.lower(), None)
        
        return handler_method

    def lookup_handler(self, request_path):
        """
        Finds the function handler associated with the requested path
        """
        for path, handler in self.routes.items():
            parse_result = parse(path, request_path)
            if parse_result is not None:
                return handler, parse_result.named
        
        return None, None
    
    def add_exception_handler(self, exception_handler):
        """
        Adds a function to the application that handle exceptions
        """
        self.exception_handler = exception_handler

    """
    RESPONSES
    """
    def default_response(self, response):
        response.status_code = 404
        response.text = "Requested path not found."
Ejemplo n.º 6
0
class AppFactory:
    def __init__(self, templates_dir='templates', static_dir='static'):
        self.routes = {}
        self.templates_env = Environment(
            loader=FileSystemLoader(os.path.abspath(templates_dir)))
        self.exception_handler = None
        self.whitenoise = WhiteNoise(self.wsgi_app, root=static_dir)
        self.middleware = Middleware(self)

    def wsgi_app(self, environ, start_response):
        request = Request(environ)

        response = self.handle_request(request)

        return response(environ, start_response)

    def __call__(self, environ, start_response):
        path_info = environ['PATH_INFO']

        if path_info.startswith('/static'):
            environ['PATH_INFO'] = path_info[len('/static'):]
            return self.whitenoise(environ, start_response)
        return self.middleware(environ, start_response)

    def add_route(self, route, handler):
        assert route not in self.routes, "Route already exists"

        self.routes[route] = handler

    def route(self, path):
        def wrapper(handler):
            self.add_route(path, handler)
            return handler

        return wrapper

    def default_response(self, response):
        response.status_code = 404
        response.text = "Not Found"

    def get_handler(self, request_route):
        for path, handler in self.routes.items():
            parse_params = parse(path, request_route)
            if parse_params:
                return handler, parse_params.named

        return None, None

    def handle_request(self, request):
        response = Response()

        handler, params = self.get_handler(request.path)

        try:
            if handler:
                if inspect.isclass(handler):
                    handler = getattr(handler(), request.method.lower(), None)
                    if not handler:
                        raise AttributeError("Method not allowed",
                                             request.method)

                handler(request, response, **params)
            else:
                self.default_response(response)

        except Exception as e:
            if self.exception_handler is None:
                raise e
            else:
                self.exception_handler(request, response, e)

        return response

    def test_client(self, base_url='http://testserv'):
        session = RequestsSession()
        session.mount(prefix=base_url, adapter=RequestsWSGIAdapter(self))
        return session

    def template(self, template_name, context=None):
        context = context if context else {}

        return self.templates_env.get_template(template_name).render(**context)

    def add_exception_handler(self, exception_handler):
        self.exception_handler = exception_handler

    def add_middleware(self, middleware_cls):
        self.middleware.add(middleware_cls)