Source code for feretui.request

# This file is a part of the FeretUI project
#
#    Copyright (C) 2024 Jean-Sebastien SUZANNE <js.suzanne@gmail.com>
#
# This Source Code Form is subject to the terms of the Mozilla Public License,
# v. 2.0. If a copy of the MPL was not distributed with this file,You can
# obtain one at http://mozilla.org/MPL/2.0/.
"""Module feretui.request.

It is the request object used by feretui. FeretUI can't decode any request
from any web-server.

The adapter to connect the web-server with this request must be write by
another libray or by the developper.

Example with bottle::

    from bottle import request, route
    from feretui import FeretUI, Request, Session

    myferet = FeretUI()
    session = Session()

    @route('/feretui/action/<action>', method=['GET', 'POST'])
    def call_action(action):
        frequest = Request(
            method=getattr(Request, request.method),
            querystring=request.query_string,
            form=MultiDict(request.forms),
            params=request.params.dict,
            headers=dict(request.headers),
            session=session,
        )
        res = myferet.do_action(frequest, action)
        ...
"""

import urllib
from typing import Any

from multidict import MultiDict

from feretui.exceptions import (
    RequestFormError,
    RequestNoSessionError,
    RequestWrongSessionError,
)
from feretui.session import Session


[docs] class RequestMethod: """RequestMethod.""" def __init__(self: "RequestMethod", method: str) -> None: """RequestMethod Constructor.""" self.method: str = method def __str__(self: "RequestMethod") -> str: """Return the method.""" return self.method def __repr__(self: "RequestMethod") -> str: """Return the method.""" return self.method
[docs] class Request: """Description of the request. This object is just a description of the web-server request. :param session: User session :type session: Session :param method: [Request.POST], the request method :type method: RequestMethod :param form: [None] :type form: MultiDict_ :param querystring: [None] :type querystring: str :param params: [None] :type params: dict :param headers: [None] :type headers: dict[str, str] :exception: :class:`feretui.exceptions.RequestFormError` :exception: :class:`feretui.exceptions.RequestNoSessionError` :exception: :class:`feretui.exceptions.RequestWrongSessionError` """ DELETE = RequestMethod("DELETE") """DELETE request method""" GET = RequestMethod("GET") """GET request method""" PATCH = RequestMethod("PATCH") """PATCH request method""" POST = RequestMethod("POST") """Post request method""" PUT = RequestMethod("PUT") """PUT request method""" def __init__( self: "Request", session: Session = None, method: RequestMethod = POST, form: MultiDict = None, params: MultiDict = None, querystring: str = None, headers: dict[str, str] = None, ) -> "Request": """Request object.""" if headers is None: headers = {} self.session = session self.method = method self.form = form self.params = params self.raw_querystring = querystring self.headers = headers self.query = {} if querystring: self.query = urllib.parse.parse_qs(querystring) if form and not isinstance(form, MultiDict): raise RequestFormError("The form must be a MultiDict") if session is None: raise RequestNoSessionError("the session is required") if not isinstance(session, Session): raise RequestWrongSessionError( "the session must be an instance of FeretUI Session", )
[docs] def get_url_from_dict( self: "Request", base_url: str = "/", querystring: dict[str, Any] = None, ) -> str: """Return an url. The url is built in function the ain_url and the querystring. :param base_url: [/], the base url before the querystring. :type base_url: str :param querystring: [None], the querystring. :type querystring: dict[str, Any] :return: Return the URL. :rtype: str """ if not querystring: return base_url return f"{base_url}?{urllib.parse.urlencode(querystring, doseq=True)}"
[docs] def get_query_string_from_current_url( self: "Request", ) -> dict[str, list[str]]: """Get the querystring from the current client URL. :return: The converted querystring. :rtype: dict[str, list[str]] """ url = self.headers["Hx-Current-Url"] url = urllib.parse.urlparse(url) return urllib.parse.parse_qs(url.query)
[docs] def get_base_url_from_current_url(self: "Request") -> dict[str, list[str]]: """Get the querystring from the current client URL. :return: The converted querystring. :rtype: dict[str, list[str]] """ url = self.headers["Hx-Current-Url"] url = urllib.parse.urlparse(url) return url.path