Skip to content

Commit 8a99f6b

Browse files
committed
tests/fix: fix response json property and add tests
1 parent e34b070 commit 8a99f6b

File tree

7 files changed

+125
-8
lines changed

7 files changed

+125
-8
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ To test the web framework, PyTest with the pytest-cov plugin is used. You can lo
594594

595595
| Statements | Miss | Coverage |
596596
|------------|------------|----------|
597-
| 1327 | 936 | 34% |
597+
| 1548 | 721 | 53% |
598598

599599
## Documentation 🌍
600600
Extended documentation and framework specifications are available at the following links:

examples/modern.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import os
2+
3+
from pyechonext.app import ApplicationType, EchoNext
4+
from pyechonext.config import Settings
5+
from pyechonext.middleware import middlewares
6+
from pyechonext.mvc.controllers import PageController
7+
from pyechonext.urls import URL
8+
9+
10+
class IndexController(PageController):
11+
def get(self, request, response, **kwargs):
12+
return "Hello"
13+
14+
def post(self, request, response, **kwargs):
15+
return "Hello"
16+
17+
18+
url_patterns = [URL(path="/", controller=IndexController)]
19+
settings = Settings(
20+
BASE_DIR=os.path.dirname(os.path.abspath(__file__)), TEMPLATES_DIR="templates"
21+
)
22+
echonext = EchoNext(
23+
__name__,
24+
settings,
25+
middlewares,
26+
urls=url_patterns,
27+
application_type=ApplicationType.HTML,
28+
)
29+
30+
31+
@echonext.route_page("/hello/{name}")
32+
def hello(request, response, name: str = "World"):
33+
response.body = f"Hello {name}!"

pyechonext/app.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
from typing import Any, Callable, Iterable, List, Optional, Tuple, Type
55

66
from loguru import logger
7+
from requests import Session as RequestsSession
78
from socks import method
9+
from wsgiadapter import WSGIAdapter as RequestsWSGIAdapter
810

911
from pyechonext.cache import InMemoryCache
1012
from pyechonext.config import Settings
@@ -115,6 +117,11 @@ def __init__(
115117

116118
logger.debug(f"Application {self.application_type.value}: {self.app_name}")
117119

120+
def test_session(self, host: str = "echonext"):
121+
session = RequestsSession()
122+
session.mount(prefix=f"http://{host}", adapter=RequestsWSGIAdapter(self))
123+
return session
124+
118125
def _get_request(self, environ: dict) -> Request:
119126
"""
120127
Gets the request.
@@ -136,6 +143,20 @@ def _get_response(self, request: Request) -> Response:
136143
"""
137144
return Response(request, content_type=self.application_type.value)
138145

146+
def add_route(self, page_path: str, handler: Callable):
147+
"""
148+
Adds a route.
149+
150+
:param page_path: The page path
151+
:type page_path: str
152+
:param handler: The handler
153+
:type handler: Callable
154+
"""
155+
if inspect.isclass(handler):
156+
self.router.add_url(URL(path=page_path, controller=handler))
157+
else:
158+
self.router.add_page_route(page_path, handler)
159+
139160
def route_page(self, page_path: str) -> Callable:
140161
"""
141162
Creating a New Page Route
@@ -314,6 +335,8 @@ def _handle_request(self, request: Request) -> Response:
314335

315336
if isinstance(result, Response):
316337
result = result.body
338+
elif result is None:
339+
return response
317340

318341
if route.route_type == RoutesTypes.URL_BASED:
319342
view = route.handler.get_rendered_view(request, result, self)

pyechonext/mvc/routes.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ def add_url(self, url: URL):
122122
:param url: The url
123123
:type url: URL
124124
"""
125+
if url.path in self.routes:
126+
raise RoutePathExistsError(f'Route "{url.path}" already exists.')
127+
125128
self.routes[url.path] = _create_url_route(url)
126129

127130
def resolve(

pyechonext/response.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@ def __getattr__(self, item: Any) -> Union[Any, None]:
9393

9494
def _structuring_headers(self, environ):
9595
headers = {
96-
"Host": environ["HTTP_HOST"],
97-
"Accept": environ["HTTP_ACCEPT"],
98-
"User-Agent": environ["HTTP_USER_AGENT"],
96+
"Host": environ.get("HTTP_HOST"),
97+
"Accept": environ.get("HTTP_ACCEPT"),
98+
"User-Agent": environ.get("HTTP_USER_AGENT"),
9999
}
100100

101101
for name, value in headers.items():
@@ -156,7 +156,7 @@ def __call__(self, environ: dict, start_response: method) -> Iterable:
156156
self._structuring_headers(environ)
157157

158158
logger.debug(
159-
f"[{environ['REQUEST_METHOD']} {self.status_code}] Run response: {self.content_type}"
159+
f"[{environ.get('REQUEST_METHOD')} {self.status_code}] Run response: {self.content_type}"
160160
)
161161

162162
start_response(status=self.status_code, headers=self._headerslist)
@@ -173,10 +173,9 @@ def json(self) -> dict:
173173
"""
174174
if self.body:
175175
if self.content_type == "application/json":
176-
return json.loads(json.dumps(self.body))
177-
# return self.body
178-
else:
179176
return json.loads(self.body)
177+
else:
178+
return json.loads(json.dumps(self.body))
180179

181180
return {}
182181

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ toml = "^0.10.2"
2020
pyyaml = "^6.0.2"
2121
requests = "^2.32.3"
2222
orjson = "^3.10.12"
23+
requests-wsgi-adapter = "^0.4.1"
2324

2425
[tool.poetry.group.dev.dependencies]
2526
pytest = "^8.3.0"

tests/test_app.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import os
2+
3+
import pytest
4+
5+
from pyechonext.app import ApplicationType, EchoNext
6+
from pyechonext.config import Settings
7+
from pyechonext.middleware import middlewares
8+
from pyechonext.mvc.controllers import PageController
9+
10+
11+
@pytest.fixture
12+
def echonext():
13+
settings = Settings(
14+
BASE_DIR=os.path.dirname(os.path.abspath(__file__)), TEMPLATES_DIR="templates"
15+
)
16+
echonext = EchoNext(
17+
__name__,
18+
settings,
19+
middlewares,
20+
application_type=ApplicationType.HTML,
21+
)
22+
return echonext
23+
24+
25+
@pytest.fixture
26+
def client(echonext):
27+
return echonext.test_session()
28+
29+
30+
def test_basic_route(echonext, client):
31+
RESPONSE_TEXT = "Hello World"
32+
33+
@echonext.route_page("/")
34+
def index(request, response):
35+
response.body = RESPONSE_TEXT
36+
37+
@echonext.route_page("/hello/{name}")
38+
def hello(request, response, name):
39+
response.body = f"hey {name}"
40+
41+
@echonext.route_page("/title")
42+
def title(request, response):
43+
return echonext.i18n_loader.get_string("title %{name}", name="Test")
44+
45+
@echonext.route_page("/books")
46+
class BooksController(PageController):
47+
def get(self, request, response, **kwargs):
48+
return "Book Get"
49+
50+
def post(self, request, response, **kwargs):
51+
return "Book Post"
52+
53+
assert client.get("http://echonext/").text == RESPONSE_TEXT
54+
assert client.get("http://echonext/hello/matthew").text == "hey matthew"
55+
assert client.get("http://echonext/hello/ashley").text == "hey ashley"
56+
assert client.get("http://echonext/books").text == "Book Get"
57+
assert client.post("http://echonext/books").text == "Book Post"
58+
assert client.get("http://echonext/title").text == "pyEchoNext Example Website Test"

0 commit comments

Comments
 (0)