Skip to content

Commit

Permalink
Introducing MetaLocal and support for session.key = value
Browse files Browse the repository at this point in the history
  • Loading branch information
mdipierro committed May 27, 2024
1 parent c66f179 commit 30a558f
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 228 deletions.
281 changes: 156 additions & 125 deletions py4web/core.py

Large diffs are not rendered by default.

4 changes: 0 additions & 4 deletions py4web/utils/url_signer.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,6 @@ def anotherpath():
assert "_signature" not in self.variables_to_sign
self.algo = algo or hashlib.sha256

@property
def local(self):
return self._safe_local

def on_request(self, context):
"""Creates the signing key if necessary."""
if self.session is not None and self.session.get("_signature_key") is None:
Expand Down
5 changes: 2 additions & 3 deletions tests/test_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import requests

from py4web import DAL, HTTP, Cache, Condition, Field, Session, abort, action
from py4web.core import Fixture, bottle, error404, request
from py4web.core import Fixture, MetaLocal, bottle, error404, request

os.environ["PY4WEB_APPS_FOLDER"] = os.path.sep.join(
os.path.normpath(__file__).split(os.path.sep)[:-2]
Expand Down Expand Up @@ -76,7 +76,7 @@ def on_error(self, context):

@action("abort_caught")
@action.uses(corrector)
def abort_response():
def abort_response_corrected():
abort(400)


Expand Down Expand Up @@ -127,7 +127,6 @@ def test_error(self):
def test_local(self):
# for test coverage
request.app_name = "example"
Session.__init_request_ctx__() # mimic before_request-hook
index()

def test_error_page(self):
Expand Down
31 changes: 17 additions & 14 deletions tests/test_auth.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import io
import os
import unittest
import uuid

from py4web.core import (DAL, HTTP, Field, Session, _before_request, bottle,
request)
from py4web.core import DAL, HTTP, Field, MetaLocal, Session, bottle, request, safely
from py4web.utils.auth import Auth, AuthAPI

SECRET = str(uuid.uuid4())
Expand All @@ -12,10 +12,8 @@
class TestAuth(unittest.TestCase):
def setUp(self):
os.environ["PY4WEB_APPS_FOLDER"] = "apps"
_before_request() # mimic before_request bottle-hook
self.db = DAL("sqlite:memory")
self.session = Session(secret=SECRET, expiration=10)
self.session.initialize()
self.auth = Auth(
self.session, self.db, define_tables=True, password_complexity=None
)
Expand All @@ -24,30 +22,36 @@ def setUp(self):
request.app_name = "_scaffold"

def tearDown(self):
# this is normally done by @action
safely(lambda: MetaLocal.local_delete(self.session))
bottle.app.router.remove("/*")

def action(self, name, method, query, data):
request.environ["REQUEST_METHOD"] = method
request.environ["ombott.request.query"] = query
request.environ["ombott.request.json"] = data
request.environ["wsgi.input"] = io.BytesIO()
# we break a symmetry below. should fix in auth.py
if name.startswith("api/"):
return getattr(AuthAPI, name[4:])(self.auth)
else:
return getattr(self.auth.form_source, name)()

def on_request(self, context={}, keep_session=False):
storage = self.session._safe_local

# mimic before_request bottle-hook
_before_request()

# mimic action.uses()
self.session.initialize()
# store the current session
try:
storage = self.session.local.__dict__
except RuntimeError:
storage = None
# reinitialize everything
safely(lambda: MetaLocal.local_delete(self.session))
safely(lambda: MetaLocal.local_delete(self.auth.flash))
self.session.on_request(context)
self.auth.flash.on_request(context)
self.auth.on_request(context)
if keep_session:
self.session._safe_local = storage
# restore the previous session
if keep_session and storage:
self.session.local.__dict__.update(storage)

def test_extra_fields(self):
db = DAL("sqlite:memory")
Expand Down Expand Up @@ -101,7 +105,6 @@ def test_register(self):
{"status": "error", "message": "Invalid Credentials", "code": 400},
)

self.on_request()
self.on_request()
body = {"email": "[email protected]", "password": "123456789"}
self.assertEqual(
Expand Down
36 changes: 14 additions & 22 deletions tests/test_fixture.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,40 @@

import pytest

from py4web.core import Fixture

result = {"seq": []}
from py4web.core import Fixture, MetaLocal


def run_thread(func, *a):
t = threading.Thread(target=func, args=a)
return t


class Foo(Fixture):
def on_request(self):
self._safe_local = SimpleNamespace()
class Foo(Fixture, MetaLocal):
def on_request(self, context):
MetaFixture.local_initialize(self)

@property
def bar(self):
return self._safe_local.a
return self.local.a

@bar.setter
def bar(self, a):
self._safe_local.a = a
self.local.a = a


results = {}
foo = Foo()


def before_request():
Fixture.__init_request_ctx__()


@pytest.fixture
def init_foo():
def init(key, a, evnt_done=None, evnt_play=None):
result["seq"].append(key)
before_request()
foo.on_request()
MetaLocal.local_initialize(foo)
foo.bar = a
evnt_done and evnt_done.set()
evnt_play and evnt_play.wait()
result[key] = foo.bar
results[key] = foo.bar
MetaLocal.local_delete(foo)
return foo

return init
Expand All @@ -60,16 +54,14 @@ def test_fixture_local_storage(init_foo):
t3.join()
evnt_play.set()
t2.join()
assert foo.bar == "a1"
assert result["t2"] == "a2"
assert result["t3"] == "a3"
assert ",".join(result["seq"]) == "t1,t2,t3"
assert results["t1"] == "a1"
assert results["t2"] == "a2"
assert results["t3"] == "a3"


def test_fixture_error():
before_request()
# attempt to access _safe_local prop without on_request-call
with pytest.raises(RuntimeError) as err:
foo.bar
assert "py4web hint" in err.value.args[0]
assert "not initialized" in err.value.args[0]
assert "Foo object" in err.value.args[0]
3 changes: 2 additions & 1 deletion tests/test_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ def setUp(self):

def test_form(self):
session = Session(secret=SECRET)
session.initialize()
session.on_request({})
table = [Field("name")]
form_name = "testing_form"
f = Form(table, form_name=form_name, csrf_session=session)
value = f.formkey
post_vars = dict(_formname=form_name, _formkey=value)
self.assertTrue(f._verify_form(post_vars))
session.on_success({})
26 changes: 13 additions & 13 deletions tests/test_get_error_snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ def test_get_error_snapshot(self):
except Exception:
snapshot = get_error_snapshot()
keys = list(sorted(snapshot.keys()))
self.assertEqual(
keys,
[
"exception_type",
"exception_value",
"os_environ",
"platform_info",
"python_version",
"stackframes",
"timestamp",
"traceback",
],
)
self.assertEqual(
keys,
[
"exception_type",
"exception_value",
"os_environ",
"platform_info",
"python_version",
"stackframes",
"timestamp",
"traceback",
],
)
Loading

0 comments on commit 30a558f

Please sign in to comment.