Skip to content

Add Azure Function Baseline #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 28 commits into from
Jun 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Python - Test
on:
push:
branches:
- main
paths:
- "code/function/**"
- "tests/**"
- "requirements.txt"
- ".github/workflows/python.yml"
pull_request:
branches:
- main
paths:
- "code/function/**"
- "tests/**"
- "requirements.txt"
- ".github/workflows/python.yml"

jobs:
lint:
name: Python Test
runs-on: ubuntu-latest

steps:
# Setup Python 3.10
- name: Setup Python 3.10
id: python_setup
uses: actions/setup-python@v4
with:
python-version: "3.10"

# Checkout repository
- name: Check Out Repository
id: checkout_repository
uses: actions/checkout@v3

# Run Python Tests
- name: Run Python Tests
id: python_test
run: |
pip install -r ./code/function/requirements.txt -q
pip install -r requirements.txt -q
pytest
9 changes: 9 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ repos:
- id: check-yaml
- id: pretty-format-json
args: ["--indent", "2", "--autofix", "--no-sort-keys"]
- repo: https://github.com/PyCQA/isort
rev: 5.12.0
hooks:
- id: isort
args: ["--profile", "black", "--filter-files"]
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
- repo: local
hooks:
- id: terraform-fmt
Expand Down
6 changes: 6 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"recommendations": [
"ms-azuretools.vscode-azurefunctions",
"ms-python.python"
]
}
12 changes: 12 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Python Functions",
"type": "python",
"request": "attach",
"port": 9091,
"preLaunchTask": "func: host start"
}
]
}
9 changes: 9 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"azureFunctions.deploySubpath": "code\\function",
"azureFunctions.scmDoBuildDuringDeployment": true,
"azureFunctions.pythonVenv": ".venv",
"azureFunctions.projectLanguage": "Python",
"azureFunctions.projectRuntime": "~4",
"debug.internalConsoleOptions": "neverOpen",
"azureFunctions.projectLanguageModel": 2
}
33 changes: 33 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "func",
"label": "func: host start",
"command": "host start",
"problemMatcher": "$func-python-watch",
"isBackground": true,
"dependsOn": "pip install (functions)",
"options": {
"cwd": "${workspaceFolder}/code\\function"
}
},
{
"label": "pip install (functions)",
"type": "shell",
"osx": {
"command": "${config:azureFunctions.pythonVenv}/bin/python -m pip install -r requirements.txt"
},
"windows": {
"command": "${config:azureFunctions.pythonVenv}\\Scripts\\python -m pip install -r requirements.txt"
},
"linux": {
"command": "${config:azureFunctions.pythonVenv}/bin/python -m pip install -r requirements.txt"
},
"problemMatcher": [],
"options": {
"cwd": "${workspaceFolder}/code\\function"
}
}
]
}
8 changes: 8 additions & 0 deletions code/function/.funcignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.git*
.vscode
__azurite_db*__.json
__blobstorage__
__queuestorage__
local.settings.json
test
.venv
135 changes: 135 additions & 0 deletions code/function/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don’t work, or not
# install all needed dependencies.
#Pipfile.lock

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# Azure Functions artifacts
bin
obj
appsettings.json
local.settings.json

# Azurite artifacts
__blobstorage__
__queuestorage__
__azurite_db*__.json
.python_packages
File renamed without changes.
File renamed without changes.
6 changes: 6 additions & 0 deletions code/function/api/v1/api_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from fastapi import APIRouter
from function.api.v1.endpoints import heartbeat, sample

api_v1_router = APIRouter()
api_v1_router.include_router(sample.router, prefix="/landingZone", tags=["sample"])
api_v1_router.include_router(heartbeat.router, prefix="/health", tags=["health"])
15 changes: 15 additions & 0 deletions code/function/api/v1/endpoints/heartbeat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from typing import Any

from fastapi import APIRouter
from function.models.heartbeat import HearbeatResult
from function.utils import setup_logging

logger = setup_logging(__name__)

router = APIRouter()


@router.get("/heartbeat", response_model=HearbeatResult, name="heartbeat")
async def get_hearbeat() -> Any:
logger.info("Received Heartbeat Request")
return HearbeatResult(isAlive=True)
17 changes: 17 additions & 0 deletions code/function/api/v1/endpoints/sample.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from typing import Any

from fastapi import APIRouter
from function.models.sample import SampleRequest, SampleResponse
from function.utils import setup_logging

logger = setup_logging(__name__)

router = APIRouter()


@router.post("/create", response_model=SampleResponse, name="create")
async def post_predict(
data: SampleRequest,
) -> SampleResponse:
logger.info(f"Received request: {data}")
return SampleResponse(output=f"Hello ${data.input}")
Empty file added code/function/core/__init__.py
Empty file.
15 changes: 15 additions & 0 deletions code/function/core/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import logging

from pydantic import BaseSettings


class Settings(BaseSettings):
PROJECT_NAME: str = "FunctionSample"
SERVER_NAME: str = "FunctionSample"
APP_VERSION: str = "v0.0.1"
API_V1_STR: str = "/v1"
LOGGING_LEVEL: int = logging.INFO
DEBUG: bool = False


settings = Settings()
14 changes: 14 additions & 0 deletions code/function/core/messages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from pydantic import BaseSettings


class Messages(BaseSettings):
# Base messages
NO_API_KEY = "No API key provided."
AUTH_REQ = "Authentication required."
HTTP_500_DETAIL = "Internal server error."

# Templates
NO_VALID_PAYLOAD = "{} is not a valid payload."


messages = Messages()
34 changes: 34 additions & 0 deletions code/function/function_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import azure.functions as func
from fastapi import FastAPI
from function.api.v1.api_v1 import api_v1_router
from function.core.config import settings


def get_app() -> FastAPI:
app = FastAPI(
title=settings.PROJECT_NAME,
version=settings.APP_VERSION,
openapi_url="/openapi.json",
debug=settings.DEBUG,
)
app.include_router(api_v1_router, prefix=settings.API_V1_STR)
return app


fastapi_app = get_app()


@fastapi_app.on_event("startup")
async def startup_event():
pass


@fastapi_app.on_event("shutdown")
async def shutdown_event():
pass


app = func.AsgiFunctionApp(
app=fastapi_app,
http_auth_level=func.AuthLevel.ANONYMOUS,
)
Loading