Skip to content

Commit

Permalink
Message returns (#18)
Browse files Browse the repository at this point in the history
* add optional message returns

* add development, test, and release docs
  • Loading branch information
lkingland authored Nov 6, 2024
1 parent 6a44644 commit 54eeba5
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 24 deletions.
34 changes: 29 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,36 @@ Python as a network service.

## Development

Minimal example of running the test Function:

- install `poetry` via `pipx`
- install dependencies with `poetry install`
- activate the virtual environment managed by poetry via `poetry shell`
Note that on some environments this command may cause collissions with
configured keyboard shortcuts. If there are problems, you can source
the environment variables from the autogenerated venv with:
Note that in some environments this command may cause collissions with
configured keyboard shortcuts. If there are problems, you can instead
source the environment variables directly with:
`source $(poetry env info --path)/bin/activate`
- install dependencies into the activated environment with `poetry install`
- run the example via `python cmd/fhttp/main.py`
- run the example via `poetry run python cmd/fhttp/main.py`
- deactivate the virtual environment with `exit`


A nice method of development using git worktrees:

p. From a personal fork, create a new worktree for the bug, feature or chore
named appropriately (eg. "feature-a")

2. Implement the code changes and commit.

3. Update the CHANGELOG.md to include the change in the "Unreleased" section.

4. Commit, push and create a PR to the upstream repository's main branch.

5. Solicit a code-read from another team member.

6. Upon approval, squash and merge to main.

7. (optional) cleanup by removing the worktree and associated local and remote
branch.

8. (optional) pull into local fork's main and push to remote fork main.

17 changes: 9 additions & 8 deletions cmd/fhttp/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,8 @@ async def handle(scope, receive, send):
# This is the default expected by this test.
# The class can be named anything. See "new" below.
class MyFunction:
""" Function is an example of a functioon instance. The structure
implements the function which will be deployed as a network service.
The class name can be changed. The only required method is "handle".
"""
async def __call__(self, scope, receive, send):
""" handle is the only method which must be implemented by the
function instance for it to be served as an ASGI handler.
"""
logging.info("OK: instanced!!")
logging.info("OK")

await send({
'type': 'http.response.start',
Expand All @@ -60,6 +53,14 @@ async def __call__(self, scope, receive, send):
'body': 'OK: instanced'.encode(),
})

def alive(self):
logging.info("liveness checked")
return True, "I'm alive!"

def ready(self):
logging.info("liveness checked")
return True, "I'm ready!"


# Funciton instance constructor
# expected to be named exactly "new"
Expand Down
46 changes: 35 additions & 11 deletions src/func_python/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def __init__(self, handler):

async def __call__(self, scope, receive, send):
# delegate to the handler implementation provided during construction.
await self.handle (scope, receive, send)
await self.handle(scope, receive, send)


class ASGIApplication():
Expand Down Expand Up @@ -117,24 +117,48 @@ async def __call__(self, scope, receive, send):
await send_exception(send, 500, f"Error: {e}")

async def handle_liveness(self, scope, receive, send):
alive = True
message = "OK"
if hasattr(self.f, "alive"):
self.f.alive()
else:
result = self.f.alive()
# The message return is optional
if isinstance(result, tuple):
alive, message = result
else:
alive = result

if alive:
await send({'type': 'http.response.start', 'status': 200,
'headers': [[b'content-type', b'text/plain']]})
await send({'type': 'http.response.body',
'body': b'OK',
})
else:
await send({'type': 'http.response.start', 'status': 500,
'headers': [[b'content-type', b'text/plain']]})

await send({'type': 'http.response.body',
'body': f'{message}'.encode('utf-8'),
})

async def handle_readiness(self, scope, receive, send):
ready = True
message = "OK"
if hasattr(self.f, "ready"):
self.f.ready()
else:
result = self.f.ready()
# The message return is optional
if isinstance(result, tuple):
ready, message = result
else:
ready = result

if ready:
await send({'type': 'http.response.start', 'status': 200,
'headers': [[b'content-type', b'text/plain']]})
await send({'type': 'http.response.body',
'body': b'OK',
})
else:
await send({'type': 'http.response.start', 'status': 500,
'headers': [[b'content-type', b'text/plain']]})

await send({'type': 'http.response.body',
'body': f'{message}'.encode('utf-8'),
})


async def send_exception(send, code, message):
Expand Down

0 comments on commit 54eeba5

Please sign in to comment.