Skip to content

Commit

Permalink
Merge pull request #178 from lona-web-org/fscherf/1.8-release
Browse files Browse the repository at this point in the history
prepare 1.8 release
  • Loading branch information
fscherf authored Nov 11, 2021
2 parents 63ff0c0 + 7aa6646 commit 64941fb
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 204 deletions.
46 changes: 44 additions & 2 deletions doc/content/end-user-documentation/views.rst
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,48 @@ JSON Responses
}
Binary Responses
~~~~~~~~~~~~~~~~

.. note::

Binary responses are only available in non interactive views

.. code-block:: python
from lona import LonaView
class MyLonaView(LonaView):
def handle_request(self, request):
return {
'content_type': 'application/pdf',
'body': open('foo.pdf', 'rb').read(),
}
Custom Headers
~~~~~~~~~~~~~~

.. note::

Custom headers are only available in non interactive views

.. code-block:: python
from lona import LonaView
class MyLonaView(LonaView):
def handle_request(self, request):
return {
'headers': {
'foo': 'bar',
},
'text': 'foo',
}
View Hooks
----------

Expand Down Expand Up @@ -1106,8 +1148,8 @@ Server.get_view_class\(route=None, import_string=None, url=None\)
Only one argument can be set at a time.


Server.reverse\(url_name, \*\*url_args\)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Server.reverse\(route_name, \*\*url_args\)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Returns a routing reverse match as string.

Expand Down
9 changes: 9 additions & 0 deletions lona/html/node_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ def append(self, node):
],
)

def extend(self, nodes):
with self._node.lock:
for node in nodes:
self.append(node)

def remove(self, node):
with self._node.lock:
self._nodes.remove(node)
Expand Down Expand Up @@ -113,6 +118,10 @@ def clear(self):
payload=[],
)

def index(self, node):
with self._node.lock:
return self._nodes.index(node)

def __getitem__(self, index):
with self._node.lock:
return self._nodes[index]
Expand Down
6 changes: 6 additions & 0 deletions lona/html/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,18 @@ def insert(self, *args, **kwargs):
def append(self, *args, **kwargs):
return self.nodes.append(*args, **kwargs)

def extend(self, *args, **kwargs):
return self.nodes.extend(*args, **kwargs)

def remove(self, *args, **kwargs):
return self.nodes.remove(*args, **kwargs)

def clear(self, *args, **kwargs):
return self.nodes.clear(*args, **kwargs)

def index(self, *args, **kwargs):
return self.nodes.index(*args, **kwargs)

def __getitem__(self, *args, **kwargs):
return self.nodes.__getitem__(*args, **kwargs)

Expand Down
5 changes: 4 additions & 1 deletion lona/response_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,17 @@ def render_response_dict(self, raw_response_dict, view_name):
response_dict = {
'status': 200,
'content_type': 'text/html',
'text': '',
'text': None,
'body': None,
'headers': None,
'file': '',
'redirect': '',
'http_redirect': '',
}

key_words = {
'text',
'body',
'redirect',
'http_redirect',
'template',
Expand Down
19 changes: 14 additions & 5 deletions lona/routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,15 @@ def clear_reverse_cache_info(self):

# routes ##################################################################
def add_route(self, route):
# check if route name already exists
if route.name:
for _route in self.routes:
if route.name == _route.name:
logger.warning(
"route name '%s' already exists",
route.name,
)

self.routes.append(route)

def add_routes(self, *routes):
Expand All @@ -160,17 +169,17 @@ def resolve(self, *args, **kwargs):
return self._resolve_lru_cache(*args, **kwargs)

# reverse #################################################################
def _reverse(self, name, *args, **kwargs):
def _reverse(self, route_name, *args, **kwargs):
route = None

for i in self.routes:
if i.name == name:
route = i
for _route in self.routes:
if _route.name == route_name:
route = _route

break

if not route:
raise ValueError(f"no route named '{name}' found")
raise ValueError(f"no route named '{route_name}' found")

if route.path:
return route.path
Expand Down
18 changes: 8 additions & 10 deletions lona/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from lona.templating import TemplatingEngine
from lona.imports import acquire as _acquire
from lona.server_state import ServerState
from lona.shell.shell import embed_shell
from lona.view_loader import ViewLoader
from lona.connection import Connection
from lona.settings import Settings
Expand Down Expand Up @@ -305,14 +304,20 @@ def _render_response(self, response_dict):
if response_dict['http_redirect']:
return HTTPFound(response_dict['http_redirect'])

default_headers = {
'Cache-Control': 'no-cache, no-store, must-revalidate',
}

headers = response_dict['headers'] or default_headers

response = Response(
status=response_dict['status'],
content_type=response_dict['content_type'],
text=response_dict['text'],
body=response_dict['body'],
headers=headers,
)

response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'

return response

# handle http requests ####################################################
Expand Down Expand Up @@ -525,13 +530,6 @@ def state(self):
return self._state

# helper ##################################################################
def embed_shell(self, _locals=None):
if _locals is None:
_locals = {}
_locals['server'] = self

return embed_shell(self, locals=_locals)

def get_running_views_count(self, *args, **kwargs):
return self.view_runtime_controller.get_running_views_count(
*args,
Expand Down
50 changes: 1 addition & 49 deletions lona/view.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
from __future__ import annotations

from typing import TYPE_CHECKING, overload, TypeVar, Union, cast
from collections.abc import Awaitable, Iterator, Callable
from concurrent.futures import CancelledError
from collections.abc import Awaitable, Callable
import threading
import warnings
import asyncio

from typing_extensions import Literal
from jinja2.nodes import Template

from lona.view_runtime import VIEW_RUNTIME_STATE, ViewRuntime
from lona.exceptions import ServerStop, UserAbort
from lona.html.abstract_node import AbstractNode
from lona.events.input_event import InputEvent
from lona.static_files import StaticFile
from lona.shell.shell import embed_shell
from lona.connection import Connection
from lona.errors import ClientError
from lona.request import Request

# avoid import cycles
Expand All @@ -33,8 +28,6 @@
class LonaView:
STATIC_FILES: list[StaticFile] = []

_server: LonaServer # TODO: remove after 1.8

def __init__(
self,
server: LonaServer,
Expand All @@ -45,24 +38,6 @@ def __init__(
self._view_runtime: ViewRuntime = view_runtime
self._request: Request = request

# objects #################################################################
@classmethod
def iter_objects(cls: type[V]) -> Iterator[V]:
# TODO: remove after 1.8

warnings.warn(
'LonaView.iter_objects() will be removed in 1.8',
category=DeprecationWarning,
)

view_runtime_controller = cls._server.view_runtime_controller

for view_runtime in view_runtime_controller.iter_view_runtimes():
if view_runtime.view_class != cls:
continue

yield view_runtime.view

# properties ##############################################################
@property
def server(self) -> LonaServer:
Expand Down Expand Up @@ -315,14 +290,6 @@ def ping(self) -> Literal['pong']:

return 'pong'

# helper ##################################################################
def embed_shell(self, _locals: None | dict = None) -> None:
if _locals is None:
_locals = {}
_locals['self'] = self

embed_shell(server=self.server, locals=_locals)

# hooks ###################################################################
def handle_request(self, request: Request) -> None | str | AbstractNode | dict: # NOQA: LN001
return ''
Expand All @@ -344,21 +311,6 @@ def handle_input_event(
def on_view_event(self, view_event: 'ViewEvent') -> dict | None:
pass

def on_shutdown(
self,
reason: Union[
None,
UserAbort,
ServerStop,
CancelledError,
ClientError,
Exception,
],
) -> None:
# TODO: remove after 1.8

pass

def on_stop(self, reason: Exception | None) -> None:
pass

Expand Down
15 changes: 0 additions & 15 deletions lona/view_loader.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import annotations

from typing import Type, cast
import warnings
import logging
import inspect
import asyncio
Expand Down Expand Up @@ -49,7 +48,6 @@ def _run_checks(self, route: Route, view: type[LonaView]) -> None:
'handle_input_event_root',
'handle_input_event',
'on_view_event',
'on_shutdown',
'on_stop',
'on_cleanup',
]
Expand All @@ -66,15 +64,6 @@ def _run_checks(self, route: Route, view: type[LonaView]) -> None:
hook_name,
)

# TODO: remove after 1.8
if(isinstance(view, type) and
view.on_shutdown is not LonaView.on_shutdown):

warnings.warn(
'LonaView.on_shutdown() will be removed in 1.8',
category=DeprecationWarning,
)

def _generate_acquiring_error_view(
self,
exception: Exception,
Expand Down Expand Up @@ -108,10 +97,6 @@ def _cache_view(

view_class = self._acquire(view)

# TODO: remove after 1.8
if isinstance(view_class, type) and issubclass(view_class, LonaView):
view_class._server = self.server

if route:
self._run_checks(route, view_class)

Expand Down
31 changes: 4 additions & 27 deletions lona/view_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,29 +236,6 @@ def run_middlewares(self, connection, window_id, url):
)

# start and stop ##########################################################
def run_shutdown_hook(self):
# TODO: remove after 1.8

logger.debug(
'running %s with stop reason %s',
self.view.on_shutdown,
self.stop_reason,
)

stop_reason = self.stop_reason

if not isinstance(stop_reason, (ServerStop, CancelledError)):
stop_reason = None

try:
self.view.on_shutdown(stop_reason)

except Exception:
logger.exception(
'Exception raised while running %s',
self.view.on_shutdown,
)

def run_stop_hook(self):
logger.debug(
'running %s with stop reason %s',
Expand Down Expand Up @@ -336,10 +313,12 @@ def start(self):
if(self.route and self.route.interactive and
isinstance(raw_response_dict, dict) and (
'json' in raw_response_dict or
'file' in raw_response_dict)):
'file' in raw_response_dict or
'headers' in raw_response_dict or
'body' in raw_response_dict)):

raise RuntimeError(
'JSON and file responses are only available in non-interactive mode',
'JSON, binary and file responses and headers are only available in non-interactive mode',
)

return self.handle_raw_response_dict(raw_response_dict)
Expand Down Expand Up @@ -398,8 +377,6 @@ def start(self):
self.send_view_stop()
self.run_stop_hook()

self.run_shutdown_hook()

def stop(self, reason=UserAbort, clean_up=True):
self.stop_reason = reason

Expand Down
Loading

0 comments on commit 64941fb

Please sign in to comment.