Skip to content

Commit

Permalink
Merge branch 'master' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
gi0baro committed Jun 22, 2023
2 parents 0856517 + 328cc9a commit c9b5f7c
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 31 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ db.define_models(Task)
app.pipeline = [db.pipe]

def is_authenticated():
return request.headers["Api-Key"] == "foobar"
return request.headers.get("api-key") == "foobar"

def not_authorized():
response.status = 401
return {'error': 'not authorized'}

@app.route(methods='get')
@service.json
@requires(is_authenticated, otherwise=not_authorized)
@service.json
async def todo():
page = request.query_params.page or 1
tasks = Task.where(
Expand Down
2 changes: 1 addition & 1 deletion emmett/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "2.5.2"
__version__ = "2.5.3"
8 changes: 6 additions & 2 deletions emmett/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,9 @@ def develop_command(
@click.option(
'--loop', type=click.Choice(['auto', 'asyncio', 'uvloop']), default='auto',
help='Event loop implementation.')
@click.option(
'--opt/--no-opt', is_flag=True, default=False,
help='Enable loop optimizations.')
@click.option(
'--log-level', type=click.Choice(LOG_LEVELS.keys()), default='info',
help='Logging level.')
Expand All @@ -332,8 +335,8 @@ def develop_command(
'--ssl-keyfile', type=str, default=None, help='SSL key file')
@pass_script_info
def serve_command(
info, host, port, workers, threads, threading_mode, interface, ws, loop, log_level,
backlog, ssl_certfile, ssl_keyfile
info, host, port, workers, threads, threading_mode, interface, ws, loop, opt,
log_level, backlog, ssl_certfile, ssl_keyfile
):
app_target = info._get_import_name()
sgi_run(
Expand All @@ -342,6 +345,7 @@ def serve_command(
host=host,
port=port,
loop=loop,
loop_opt=opt,
log_level=log_level,
workers=workers,
threads=threads,
Expand Down
8 changes: 4 additions & 4 deletions emmett/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,10 +547,10 @@ def selected(k):
_id=_id or field.name
)

#: TO-DO
#@staticmethod
#def widget_list(attr, field, value, _class="", _id=None):
# return ""
@staticmethod
def widget_list(field, value):
options, _ = FormStyle._field_options(field)
return FormStyle.widget_multiple(None, field, value, options)

@staticmethod
def widget_upload(attr, field, value, _class="upload", _id=None):
Expand Down
67 changes: 65 additions & 2 deletions emmett/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

from email.utils import formatdate
from hashlib import md5
from typing import Any, BinaryIO, Dict, Generator, Tuple
from typing import Any, AsyncIterable, BinaryIO, Dict, Generator, Iterable, Tuple

from granian.rsgi import HTTPProtocol

Expand Down Expand Up @@ -284,14 +284,77 @@ async def asgi(self, scope, send):
async def _send_body(self, send):
more_body = True
while more_body:
chunk = await self.io_stream.read(self.chunk_size)
chunk = self.io_stream.read(self.chunk_size)
more_body = len(chunk) == self.chunk_size
await send({
'type': 'http.response.body',
'body': chunk,
'more_body': more_body,
})

def rsgi(self, protocol: HTTPProtocol):
protocol.response_bytes(
self.status_code,
list(self.rsgi_headers),
self.io_stream.read()
)


class HTTPIter(HTTPResponse):
def __init__(
self,
iter: Iterable[bytes],
headers: Dict[str, str] = {},
cookies: Dict[str, Any] = {}
):
super().__init__(200, headers=headers, cookies=cookies)
self.iter = iter

async def _send_body(self, send):
for chunk in self.iter:
await send({
'type': 'http.response.body',
'body': chunk,
'more_body': True
})
await send({'type': 'http.response.body', 'body': b'', 'more_body': False})

async def rsgi(self, protocol: HTTPProtocol):
trx = protocol.response_stream(
self.status_code,
list(self.rsgi_headers)
)
for chunk in self.iter:
await trx.send_bytes(chunk)


class HTTPAiter(HTTPResponse):
def __init__(
self,
iter: AsyncIterable[bytes],
headers: Dict[str, str] = {},
cookies: Dict[str, Any] = {}
):
super().__init__(200, headers=headers, cookies=cookies)
self.iter = iter

async def _send_body(self, send):
async for chunk in self.iter:
await send({
'type': 'http.response.body',
'body': chunk,
'more_body': True
})
await send({'type': 'http.response.body', 'body': b'', 'more_body': False})

async def rsgi(self, protocol: HTTPProtocol):
trx = protocol.response_stream(
self.status_code,
list(self.rsgi_headers)
)
async for chunk in self.iter:
await trx.send_bytes(chunk)


def redirect(location: str, status_code: int = 303):
response = current.response
Expand Down
1 change: 0 additions & 1 deletion emmett/orm/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

from functools import wraps

from pydal.adapters import adapters
from pydal.adapters.base import SQLAdapter
from pydal.adapters.mssql import (
MSSQL1,
Expand Down
3 changes: 2 additions & 1 deletion emmett/rsgi/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ async def __call__(
self.app.log.warn(
f"Timeout sending response: ({scope.path})"
)
http.rsgi(protocol)
if coro := http.rsgi(protocol):
await coro

@cachedprop
def error_handler(self) -> Callable[[], Awaitable[str]]:
Expand Down
2 changes: 2 additions & 0 deletions emmett/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def run(
host='127.0.0.1',
port=8000,
loop='auto',
loop_opt=False,
log_level=None,
workers=1,
threads=1,
Expand All @@ -40,6 +41,7 @@ def run(
pthreads=threads,
threading_mode=threading_mode,
loop=loop,
loop_opt=loop_opt,
websockets=enable_websockets,
backlog=backlog,
log_level=log_level,
Expand Down
40 changes: 24 additions & 16 deletions emmett/wrappers/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,16 @@ def _load_params_form_urlencoded(self, data):
def _multipart_headers(self):
return self.headers

@staticmethod
def _file_param_from_field(field):
return FileStorage(
BytesIO(field.file.read()),
field.filename,
field.name,
field.type,
field.headers
)

def _load_params_form_multipart(self, data):
params, files = sdict(), sdict()
field_storage = FieldStorage(
Expand All @@ -104,23 +114,21 @@ def _load_params_form_multipart(self, data):
field = field_storage[key]
if isinstance(field, list):
if len(field) > 1:
params[key] = []
for element in field:
params[key].append(element.value)
pvalues, fvalues = [], []
for item in field:
if item.filename is not None:
fvalues.append(self._file_param_from_field(item))
else:
pvalues.append(item.value)
if pvalues:
params[key] = pvalues
if fvalues:
files[key] = fvalues
continue
else:
params[key] = field[0].value
elif (
isinstance(field, FieldStorage) and
field.filename is not None
):
files[key] = FileStorage(
BytesIO(field.file.read()),
field.filename,
field.name,
field.type,
field.headers
)
continue
field = field[0]
if field.filename is not None:
files[key] = self._file_param_from_field(field)
else:
params[key] = field.value
return params, files
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "emmett"
version = "2.5.2"
version = "2.5.3"
description = "The web framework for inventors"
authors = ["Giovanni Barillari <[email protected]>"]
license = "BSD-3-Clause"
Expand Down Expand Up @@ -43,7 +43,7 @@ emmett = "emmett.cli:main"
[tool.poetry.dependencies]
python = "^3.8"
click = ">=6.0"
granian = "~0.4.2"
granian = "~0.5.0"
emmett-crypto = "~0.3"
pendulum = "~2.1.2"
pyDAL = "17.3"
Expand Down

0 comments on commit c9b5f7c

Please sign in to comment.