معرفی شرکت ها


bravaweb-0.0.9


Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر

توضیحات

BravaWeb Framework for ASGI Server
ویژگی مقدار
سیستم عامل -
نام فایل bravaweb-0.0.9
نام bravaweb
نسخه کتابخانه 0.0.9
نگهدارنده []
ایمیل نگهدارنده []
نویسنده Roberto Neves
ایمیل نویسنده robertonsilva@gmail.com
آدرس صفحه اصلی https://github.com/robertons/bravaweb
آدرس اینترنتی https://pypi.org/project/bravaweb/
مجوز MIT
# BravaWeb Framework for ASGI Server Framework para aplicações WEB baseada em Python3 ASGI (_Asynchronous Server Gateway Interfac_ em Uvicorn), com possibilidade de utilização de Template em Html (Mako Templates). Veja Documentação em: Uvicorn: https://www.uvicorn.org/ Mako Templates: https://www.makotemplates.org/ # Instalação Instalação utilizando Pip ```bash pip install bravaweb ``` Git/Clone ``` git clone https://github.com/robertons/bravaweb cd bravaweb pip install -r requirements.txt python setup.py install ``` # Primeiros Passos Inicie seu projeto conforme estrutura abaixo ```bash app ├── ... ├── configuration │ ├── __init__.py │ └── api.py └── server.py ``` O arquivo de configurações deve conter os seguintes dados: | variável | tipo | obrigatório | descrição | |-------------------|-------------|-------------|-------------------------------| | directory | string | sim | Caminho Projeto | | encoding | string | sim | Codificação | | date_format | string | sim | Formato data | | short_date_format | string | sim | Formato data curta | | token | string | sim | Token codificação Authorization Header | | domains | array | sim | Domínios autorizados a acessar| | access_exceptions | array | sim | Rotas e Exceções de acesso | | routes | array | sim | Rotas do Projeto | ```python configuration/__init__.py # -*- coding: utf-8 -*- from configuration import api ``` ```python configuration/api.py # -*- coding: utf-8 -*- import os # Directory directory = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir)) # Api Encoding encoding = "utf-8" # Date Format date_format = "%d/%m/%Y %H:%M:%S" short_date_format = "%d/%m/%Y" # Token Authorization token = "JWT-Token-Project" # Authorized Domains Origin/Referrer domains = [ "https://www.dominio.com.br", "https://alias.dominio.com.br", ] # Exceptions Routes access_exceptions = [ {'path': '(^/default/)','referer': '*'}, {'path': '(/rota/especifica/)','referer': '(^https://dominio.especifico.com.br/)'}, {'path': '*', 'referer': "(^https://outro.dominio.com.br/)|(^https://adicional.dominio.com.br/)"}, ] routes = [ ("{controller}/{area}/{module}/{action}/{id}", '(^/admin/)|(^/panel/)', ("{controller}/{module}/{action}/{id}", ""), ] ``` **Definições:** **domains**: lista array de strings, com domínios que tem acesso a api, o teste é feito baseado no origin e/ou referrer de cada requisição. **access_exceptions**: é possivel que algumas rotas sejam abertas para qualquer requisição, ou mesmo que alguma rota seja especifica para algum domínio. A lista deve conter um dicionário com as chaves path e referer onde: path: é referente ao caminho da rota referer: origem da requisição Ambos os valores aceitam * para todos ou expressão regular para teste de string. **routes**: lista com tuplas que definem as rotas padrões do projeto. Bravaweb esta preparado para até 4 níveis de profundidade que definem, Controlador, Area, Modulo, Ação e mais um nível **opcional** para captação de ID, a prioridade das regras é sequencial, portanto as regras específicas devem vir primeiro. A tupla é definida assim: 0: a captação de cada parte da profundidade para carregamento 1: expressão regular para identificar a regra Por padrão os valores de rota do ambiente são: controller = None area = None module = "default" action="index" id = None Por fim vamos criar a execução do projeto que vai tratar as requisições e processar as rotas. O arquivo `server.py` na raiz deve ficar assim: ```python #-*- coding: utf-8 -*- import sys import configuration from bravaweb import App as application ``` Acesse o diretório do seu projeto, e execute o comando de serviço do ASGI, conforme documentação do Uvicorn, no exemplo abaixo ativamos o ambiente virtual onde os pacotes estão instalados: ```bash\ source ../env/bin/activate uvicorn server:application --port 8080 --interface=asgi3 --workers 7 --proxy-headers --lifespan off --reload ``` O Resultado então será: ```bash\ INFO: Uvicorn running on http://127.0.0.1:8080 (Press CTRL+C to quit) INFO: Started reloader process [82503] using statreload INFO: Started server process [82505] . . . ``` Neste momento sua aplicação estará em execução. Nós configuramos as rotas mas não desenvolvemos nenhuma delas portanto qualquer requisição na url http://127.0.0.1:8080 irá retornar 404. # Hello World Vamos iniciar aplicando a rota default, a pasta do projeto nesse momento deverá estar assim: ```bash app ├── ... ├── configuration │ ├── __init__.py │ └── api.py ├── controllers │ └── default.py └── server.py ``` Conforme exemplificado a rota default(padrão) é controller = None area = None module = "default" action="index" id = None O arquivo ficará assim: ```python controllers/default.py # -*- coding: utf-8 -*- from bravaweb.controller import * class DefaultController(Controller): @get async def index(self) -> Json: await View(self.enviroment, data={"mensagem": 'Olá Mundo'}) ``` **Analisando a rota default:** Nome do Controlador é default, por isso nome da classe é **Default**Controller, herdando o controlador do framework (Controller) O metodo de request aceito para esta rota é o GET (*@get*) , mas POST (*@post*) , PUT(*@put*) e DELETE(*@delete*) também são aceitos. Uma requisição diferente do permitido para rota retorna Erro *405: Method not allowed* O Framwork é baseado em ASGI (_Asynchronous Server Gateway Interface_) por isso ação index é assíncrona (async) . A anotação é o tipo de resultado que essa rota irá retornar, posteriormente veremos sobre os tipos, no exemplo acima utilizamos Json. Todos os dados da requisição, estão na *enviroment*, veremos mais logo a seguir. Para melhor compreenção sobre as rotas , vejamos os exemplos abaixo baseado no arquivo de configuração acima: # Criando e Configurando Rotas Os padrões de rota é configurado no arquivo de configurações em routes. Você provavelmente fará isso somente uma vez, ou quando for necessária a criação de rotas específicas em seu projeto. Abaixo segue alguns exemplos baseado na configuração que apresentamos. ## Exemplo 1 GET -> api.dominio.com.br/admin/catalog/products/list A regra identificada é a primeira da lista, pois o path da request inicia com */admin/* conforme expressão regular da posição [1] da tupla em *configuration.api.routes*: ("{controller}/{area}/{module}/{action}/{id}", '(^/admin/)|(^/panel/)' O resultado da captação da rota conforme posição [0] da tupla será: controller = 'admin' area = 'catalog' module = 'products' action = 'list' A estrutura para processamento desta rota devera ser: ```bash app ├── ... ├── controllers │ └── admin │ │ └── catalog │ │ | └── products.py ``` O arquivo : ```python controllers/admin/catalog/products.py # -*- coding: utf-8 -*- from bravaweb.controller import * class ProductsController(Controller): @get async def list(self) -> Json: await View(self.enviroment, data=[{"prod_nome": 'Exemplo'}]) ``` ## Exemplo 2 POST -> api.dominio.com.br/site/product/like/110 A regra identificada é a default (segunda da lista), pois o path da request **não** contempla as expressões regulares anteriores : ("{controller}/{module}/{action}/{id}", "") O resultado da captação da rota conforme posição [0] da tupla será: controller = 'site' area = None module = 'product' action = 'like' id = 110 A estrutura para processamento desta rota devera ser: ```bash app ├── ... ├── controllers │ └── site │ │ └── product.py ``` O arquivo: ```python controllers/site/products.py # -*- coding: utf-8 -*- from bravaweb.controller import * class ProductController(Controller): @post async def like(self) -> Json: await View(self.enviroment, data=[{"likes": 535}]) ``` # Ambiente / Enviroment A qualquer momento dentro do controlador é possivel acessar os dados da requisição através de *self.enviroment* os dados disponíves são: |Campo | Tipo | descrição | |--|--|--| | origin | string | Origem ou Referrer da Requisição| | remote_ip | string | Ip do usuário| | remote_uuid | string | UUID se informado no header | | browser | string | Browser do usuário | | accept_encoding | string | tipos de codificação aceito pelo browser | | method | string | metodo da requisição (GET, POST, PUT ou DELETE) | | response_type| string | tipo de resposta esperada para requisição| | authorization| string | Token JWT - Bearer enviado no Header| | bearer| string | Token JWT decodificado | | content_length| int | Tamanho da requisição | | get| dict | Dados enviados por querystring | | post| dict | Dados enviados por post | | body | bytes | Bytes do corpo da requisição | | route | string | rota | | controller | string | nome controlador | | area | string | nome area do controlador | | module | string | nome modulo do controlador | | action | string | nome da ação do modulo | | id | string | identificador da requisição | Há disponível também, para casos de manipulação específica os dados brutos do ASGI: |Campo | descrição | |--|--| | headers | cabeçalho da requisição | | scope | escopo da requisição | | send | conexão com navegador | | receive | dados recebidos | # Entradas e Pré-condições Para maior segurança no processamento das rotas é possível e **recomendável** estabelecer as pré-condições daquela rota específica. Caso a requisição não tenha o objeto ou objeto informado seja inválido, haverá erro de resposta com erro *412: Precondition Failed* ```python @post async def comment(self, id_product:int, comment:string ) -> Json: sql_query = f"INSERT INTO products_comments (prod_comment, id_product) VALUES ('{comment}',{id_product})"; . . . await View(self.enviroment, data=[{"added": true}]) ``` Caso a request não contenha os parametros acima, a ação não será executada. É possível requerer objetos específicos, Bravaweb realiza o cast automático dos dados enviados, no caso datetime o parametro de conversão esta estabelecido no arquivo de configuração nos campos *date_format* e *short_date_format*. ```python from datetime import datetime from decimal import Decimal . @post async def comment(self, id_product:int, comment:string, date:datetime, stars:Decimal) -> Json: . . . . . . await View(self.enviroment, data=[{"added": true}]) ``` # View Toda rota deve retornar uma view, que será baseada na anotação a action. ```python await View(self.enviroment, data=_response_data) ``` Bravaweb possui tratamento específico para respostas Json e HTML, ambos possuem um modelo ou carregamento de template para resposta. A View possui os seguintes campos de entrada | entrada | obrigatório | tipo | descrição |--|--|--|--| | enviorment | sim | bravaweb.enviroment | ambiente da requisição | data | sim | bytes-like, dict, list, string | dados da resposta de acordo com anotação | success | não | boolean | sucesso na execução da action | token | não | string | auth token, caso não informado, havendo token no enviroment, o mesmo se repetirá | task | não | dict, list, string | dados sobre execução em segundo plano | error | não | dict, list, string | mensagem de erro # Anotações e Tipos de Resposta |tipo | Entrada | |--|--| | Html | dict | | Css | bytes-like object | | Csv | bytes-like object | | JavaScript | bytes-like object | | Jpg | bytes-like object | | Json | dict, list, string | | Mp4 |bytes-like object | | Pdf | bytes-like object | | Png | bytes-like object| | TextPlain | bytes-like object | | Xml | bytes-like object | # Json O template Json é composto da seguinte forma: Json = { "token": "", "success": True, "date": "", "itens": 0, "data": [], } Onde os dados respondidos estarão dentro de "data". ```python @get async def index(self) -> Json: await View(self.enviroment, data=[{"added": true}]) ``` # HTML e Template Mako Para mais informações sobre a criação de templates Mako acesse: https://www.makotemplates.org/ A estrutura das Views HTML desenvolvidas em Mako devem estar assim: ```bash app ├── ... ├── configuration ├── controllers ├── views │ └── shared │ | └── default.html └── server.py ``` Quando não há uma view definida para rota, o template padrão a ser carregado será o default. é possível criar views específicas para cada rota conforme exemplo abaixo: Rota: **/product/detail** ```python @get async def index(self) -> Html: await View(self.enviroment, data=[{"added": true}]) ``` **Template:** ```bash app ├── ... ├── configuration ├── controllers ├── views │ └── product │ | └── detail │ | | └── index.html │ └── shared └── server.py ``` # Decoradores Bravaweb é compatível com encapsulamento através de decorador e a criação deve seguir o modelo abaixo: **Decorador de Método Síncrono:** ```python def decorator_example(f): def example_decorator(cls, **args) -> f: return f(cls, **args) return example_decorator ``` **Decorador de Método Assíncrono:** ```python def decorator_example_async(f): async def example_decorator(cls, **args) -> f: return await f(cls, **args) return example_decorator ``` **O uso do decorador em um método síncrono ficaria assim:** ```python @decorator_example def __init__(self): . . ``` **O uso do decorador em uma rota ficaria assim:** ```python @decorator_example_async async def index(self) -> Html: await View(self.enviroment, data=_response_data) ``` **É possível também criar decorar para um controlador inteiro, a função "decora" todos os métodos executáveis, observe que os métodos padrões de classe __init__ e __del__ são métodos síncronos e por isso o decorador síncrono, e demais métodos (actions) com decorador assíncrono.** ```python def decorator_example_klass(): def decorate(cls): for attr in cls.__dict__: _method = getattr(cls, attr) if hasattr(_method, '__call__'): if attr == "__init__" or attr == "__del__": setattr(cls, attr, example_decorator(_method)) else: setattr(cls, attr, decorator_example_async(_method)) return cls return decorate ``` # Erros: A qualquer momento no processamento da sua rota é possível responder com as seguintes mensagens de erro: | Metoto | Código de Resposta | Mensagem | |--|--|--| | NoContent | 204 | 204: No Content | Unauthorized | 401 | 401: Unauthorized | NotFound | 404 | 404: Not Found | NotAllowed | 405 | 405: Method not allowed | PreconditionFailed | 412 | 412: Precondition Failed | InternalError | 500 | 500: Internal Error **Exemplo requisição de um arquivo pdf:** ```python import os.path @get async def index(self, file_path:str) -> Pdf: if os.path.exists(file_path): _file_data = open(file_path,'r') await View(self.enviroment, data = _file_data.read()) else: self.NotFound() ``` ## License MIT


نحوه نصب


نصب پکیج whl bravaweb-0.0.9:

    pip install bravaweb-0.0.9.whl


نصب پکیج tar.gz bravaweb-0.0.9:

    pip install bravaweb-0.0.9.tar.gz