Skip to content
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

initial python version (with_tests) #58

Open
wants to merge 7 commits into
base: with_tests
Choose a base branch
from
Open
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
43 changes: 43 additions & 0 deletions .github/workflows/python-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: python-build

env:
PROJECT_DIR: python

on:
push:
paths:
- 'python/**'
- '.github/workflows/python-build.yml'
pull_request:
paths:
- 'python/**'
- '.github/workflows/python-build.yml'

jobs:
build:
defaults:
run:
working-directory: ./${{ env.PROJECT_DIR }}

runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v2

- name: Install Python
uses: actions/setup-python@v2
with:
python-version: "3.9"

- name: Install dependency manager (poetry)
uses: abatilo/[email protected]

- name: Set up dependencies
run: poetry install

- name: Set up the database
run: poetry run python database.py createdb

- name: Test
run: poetry run pytest
3 changes: 3 additions & 0 deletions python/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
__pycache__
ski.db
.venv
46 changes: 46 additions & 0 deletions python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Setup


## Make sure you have Python installed

Run the following:

```bash
python --version
```

You should see the version number and hopefully it'll be >= 3.9 (Oct. 5, 2020).

If you don't start by installing it, using, for instance [pyenv][https://github.com/pyenv/pyenv].

## Install dependencies

Start by installing poetry, to manage dependencies.
See [here][https://python-poetry.org/docs/#osx--linux--bashonwindows-install-instructions]

Then you can install all dependencies with:

```bash
./python $ poetry install
```

## Setup the database

```bash
./python $ rm ski.db # To clean the DB, literally
./python $ poetry run python database.py createdb
```

# Run

## The tests

```bash
./python $ poetry run pytest
```

## The server

```bash
./python $ poetry run uvicorn main:app --reload
```
60 changes: 60 additions & 0 deletions python/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import sqlalchemy
import sys

from datetime import date
from databases import Database
from sqlalchemy import select
from sqlalchemy.dialects.sqlite import insert

# Wraps the database with databases.Database to get an async API
# on top of SQL alchemy.
database = Database("sqlite:///ski.db")

_metadata = sqlalchemy.MetaData()

base_price = sqlalchemy.Table(
"base_price",
_metadata,
sqlalchemy.Column("id", sqlalchemy.Integer, primary_key=True),
sqlalchemy.Column("type", sqlalchemy.String(
length=255), nullable=False, unique=True),
sqlalchemy.Column("cost", sqlalchemy.Integer, nullable=False),
)

holidays = sqlalchemy.Table(
"holidays",
_metadata,
sqlalchemy.Column("holiday", sqlalchemy.Date, primary_key=True),
sqlalchemy.Column("description", sqlalchemy.String(
length=255), nullable=False),
)


def create_schema():
engine = sqlalchemy.create_engine(str(database.url))
_metadata.create_all(engine)


def seed_data():
engine = sqlalchemy.create_engine(str(database.url))
engine.execute(
insert(base_price),
[
{"type": "1jour", "cost": 35},
{"type": "night", "cost": 19},
],
)
engine.execute(
insert(holidays),
[
{"holiday": date(2019, 2, 18), "description": "winter"},
{"holiday": date(2019, 2, 25), "description": "winter"},
{"holiday": date(2019, 3, 4), "description": "winter"},
],
)


if __name__ == "__main__":
if sys.argv[1] == "createdb":
create_schema()
seed_data()
87 changes: 87 additions & 0 deletions python/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import datetime
import math

from fastapi import FastAPI
from typing import Optional

from database import (
database, insert, select,
base_price as base_price_table,
holidays as holidays_table,
)

app = FastAPI()


@app.on_event("startup")
async def startup():
await database.connect()


@app.on_event("shutdown")
async def shutdown():
await database.disconnect()


@app.put("/prices")
async def upsert_price(type: str, cost: int):
await database.execute(
insert(base_price_table)
.values({"type": type, "cost": cost})
.on_conflict_do_update(
index_elements=['type'],
set_={"cost": cost},
)
)


@app.get("/prices")
async def compute_price(
type: str,
age: Optional[int] = None,
date: Optional[datetime.date] = None,
):
result = await database.fetch_one(
select(base_price_table.c.cost)
.where(base_price_table.c.type == type),
)

if age and age < 6:
return {"cost": 0}
else:
if type != 'night':
holidays = await database.fetch_all(select(holidays_table))

is_holiday = False
reduction = 0

for row in holidays:
if date:
if date == row.holiday:
is_holiday = True

if not is_holiday and date and date.weekday() == 0:
reduction = 35

# TODO apply reduction for others
if age and age < 15:
return {"cost": math.ceil(result.cost * .7)}
else:
if not age:
cost = result.cost * (1 - reduction / 100)
return {"cost": math.ceil(cost)}
else:
if age > 64:
cost = result.cost * .75 * (1 - reduction / 100)
return {"cost": math.ceil(cost)}
else:
cost = result.cost * (1 - reduction / 100)
return {"cost": math.ceil(cost)}
else:
if age and age >= 6:
if age and age > 64:
return {"cost": math.ceil(result.cost * .4)}
else:
return result
else:
return {"cost": 0}
Loading