Skip to content

Commit

Permalink
remove type hints
Browse files Browse the repository at this point in the history
  • Loading branch information
0x67757300 committed Dec 14, 2023
1 parent dbe3f9e commit c0e287b
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 57 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
# µHTTP - Pythonic web development

µHTTP emerged from the need of a **simple** web framework. It's great for micro-services, single page applications, AND monolithic monsters.
µHTTP emerged from the need of a **simple** web framework. It's great for micro-services, small applications, AND monolithic monsters.

_In µHTTP there is no hidden logic. Everything is what it seems._

### Why

- Stupid simple, seriously there are maybe 15 lines of "real" code in it. _No external dependencies._
- Stupid simple, seriously, there are maybe 15 lines of "real" code in it. _No external dependencies._
- Extremely modular, entire extensions can just follow the simple App pattern.
- Very flexible, because of decisions like being able to raise Responses.
- Quite fast, because it doesn't do much.
- Great learning device.

[The rant.](https://lobste.rs/s/ukh5id/uhttp_pythonic_web_development#c_9jln1d)

### Installation

µHTTP is on [PyPI](https://pypi.org/project/uhttp/).
Expand Down
97 changes: 42 additions & 55 deletions uhttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from urllib.parse import parse_qs, unquote
from asyncio import to_thread
from inspect import iscoroutinefunction
from typing import Any, Callable, Iterable, Optional, Union


class App:
Expand All @@ -19,17 +18,20 @@ class App:
def __init__(
self,
*,
routes: Optional[
dict[str, dict[str, Callable[['Request'], Any]]]
] = None,
startup: Optional[list[Callable[[dict], Any]]] = None,
shutdown: Optional[list[Callable[[dict], Any]]] = None,
before: Optional[list[Callable[['Request'], Any]]] = None,
after: Optional[list[Callable[['Request', 'Response'], Any]]] = None,
max_content: int = 1048576
routes=None,
startup=None,
shutdown=None,
before=None,
after=None,
max_content=1048576
):
"""Initializes an App.
- routes must follow: `{'PATH': {'METHOD': FUNC}}`.
- startup, shutdown, before and after must be a list of funcs.
- max_content is the maximum size allowed, in bytes, of a
request body. Defaults to 1 MB.
E.g.:
```python
Expand Down Expand Up @@ -58,7 +60,7 @@ def __init__(
self._after = after or []
self._max_content = max_content

def mount(self, app: 'App', prefix: str = ''):
def mount(self, app, prefix=''):
"""Mounts another app."""
self._startup += app._startup
self._shutdown += app._shutdown
Expand All @@ -67,7 +69,7 @@ def mount(self, app: 'App', prefix: str = ''):
self._routes.update({prefix + k: v for k, v in app._routes.items()})
self._max_content = max(self._max_content, app._max_content)

def startup(self, func: Callable[[dict], Any]):
def startup(self, func):
"""A startup decorator.
Appends the decorated function to the list of startup functions.
Expand All @@ -86,7 +88,7 @@ def open_db(state):
self._startup.append(func)
return func

def shutdown(self, func: Callable[[dict], Any]):
def shutdown(self, func):
"""A shutdown decorator.
Appends the decorated function to the list of shutdown
Expand All @@ -104,7 +106,7 @@ def close_db(state):
self._shutdown.append(func)
return func

def before(self, func: Callable[['Request'], Any]):
def before(self, func):
"""A before decorator.
Appends the decorated function to the list of before functions.
Expand All @@ -124,7 +126,7 @@ def auth(request):
self._before.append(func)
return func

def after(self, func: Callable[['Request', 'Response'], Any]):
def after(self, func):
"""An after decorator.
Appends the decorated function to the list of after functions.
Expand All @@ -142,7 +144,7 @@ def logger(request, response):
self._after.append(func)
return func

def route(self, path: str, methods: Iterable[str] = ('GET',)):
def route(self, path, methods=('GET',)):
"""A route decorator.
Adds the decorated function to the routing table.
Expand Down Expand Up @@ -172,43 +174,43 @@ def decorator(func):
return func
return decorator

def get(self, path: str):
def get(self, path):
"""A `GET` route."""
return self.route(path, methods=('GET',))

def head(self, path: str):
def head(self, path):
"""A `HEAD` route."""
return self.route(path, methods=('HEAD',))

def post(self, path: str):
def post(self, path):
"""A `POST` route."""
return self.route(path, methods=('POST',))

def put(self, path: str):
def put(self, path):
"""A `PUT` route."""
return self.route(path, methods=('PUT',))

def delete(self, path: str):
def delete(self, path):
"""A `DELETE` route."""
return self.route(path, methods=('DELETE',))

def connect(self, path: str):
def connect(self, path):
"""A `CONNECT` route."""
return self.route(path, methods=('CONNECT',))

def options(self, path: str):
def options(self, path):
"""An `OPTIONS` route."""
return self.route(path, methods=('OPTIONS',))

def trace(self, path: str):
def trace(self, path):
"""A `TRACE` route."""
return self.route(path, methods=('TRACE',))

def patch(self, path: str):
def patch(self, path):
"""A `PATCH` route."""
return self.route(path, methods=('PATCH',))

async def __call__(self, scope: dict, receive: Callable, send: Callable):
async def __call__(self, scope, receive, send):
state = scope.get('state', {})

if scope['type'] == 'lifespan':
Expand Down Expand Up @@ -340,30 +342,20 @@ async def __call__(self, scope: dict, receive: Callable, send: Callable):

class Request:
"""An HTTP request."""
method: str
path: str
params: dict[str, str]
args: 'MultiDict'
headers: 'MultiDict'
cookies: SimpleCookie
body: bytes
json: Any
form: 'MultiDict'
state: dict

def __init__(
self,
method: str,
path: str,
method,
path,
*,
params: Optional[dict] = None,
args: Optional[Union['MultiDict', dict, list]] = None,
headers: Optional[Union['MultiDict', dict, list]] = None,
cookies: Optional[dict] = None,
body: bytes = b'',
json: Optional[Any] = None,
form: Optional[Union['MultiDict', dict, list]] = None,
state: Optional[dict] = None
params=None,
args=None,
headers=None,
cookies=None,
body=b'',
json=None,
form=None,
state=None
):
self.method = method
self.path = path
Expand Down Expand Up @@ -399,19 +391,14 @@ def account(request):
user = user(request.state['db'], 'john')
```
"""
status: int
description: str
headers: 'MultiDict'
cookies: SimpleCookie
body: bytes

def __init__(
self,
status: int,
status,
*,
headers: Optional[Union['MultiDict', dict, list]] = None,
cookies: Optional[dict] = None,
body: bytes = b''
headers=None,
cookies=None,
body=b''
):
self.status = status
try:
Expand All @@ -430,7 +417,7 @@ def __repr__(self):
return f'{self.status} {self.description}'

@classmethod
def from_any(cls, any: Any) -> 'Response':
def from_any(cls, any):
if isinstance(any, int):
return cls(status=any, body=HTTPStatus(any).phrase.encode())
elif isinstance(any, str):
Expand Down

0 comments on commit c0e287b

Please sign in to comment.