Skip to content
This repository was archived by the owner on May 13, 2025. It is now read-only.

Commit 785fe56

Browse files
committed
Upgrade deps, config GH actions, add mergify, improve tests
1 parent 040aff4 commit 785fe56

32 files changed

+531
-366
lines changed

.env.example

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
# Environment variables for appointment-reminders-flask
22

33
# App settings
4-
export DATABASE_URL=postgres://someuser:withsomepassword@localhost:5432/appointments
4+
export DATABASE_URI=
55
export SECRET_KEY=asupersecr3tkeyshouldgo
6-
export CELERY_URL=redis://localhost:6379
6+
export CELERY_BROKER_URL=redis://localhost:6379
7+
export CELERY_RESULT_BACKEND=redis://localhost:6379
78

89
# Twilio settings
910
export TWILIO_ACCOUNT_SID=ACXXXXXXXXXXXXXXXXX

.github/workflows/flask.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Flask
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
build:
11+
12+
runs-on: ${{ matrix.platform }}
13+
strategy:
14+
max-parallel: 4
15+
matrix:
16+
python-version: [3.6, 3.7, 3.8]
17+
platform: [windows-latest, macos-latest, ubuntu-latest]
18+
19+
steps:
20+
- uses: actions/checkout@v2
21+
- name: Set up Python ${{ matrix.python-version }}
22+
uses: actions/setup-python@v1
23+
with:
24+
python-version: ${{ matrix.python-version }}
25+
- name: Install Dependencies
26+
run: |
27+
python -m pip install --upgrade pip
28+
pip install -r requirements.txt
29+
- name: Run Linter
30+
run: |
31+
flake8
32+
- name: Run Tests
33+
run: |
34+
cp .env.example .env
35+
python runtests.py

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,4 @@ target/
5959

6060
.env
6161
/venv
62+
*.sqlite

.mergify.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
pull_request_rules:
2+
- name: automatic merge for Dependabot pull requests
3+
conditions:
4+
- author~=^dependabot(|-preview)\[bot\]$
5+
- status-success=build
6+
actions:
7+
merge:
8+
method: squash

.travis.yml

Lines changed: 0 additions & 25 deletions
This file was deleted.

LICENSE

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2015 Twilio Inc.
3+
Copyright (c) 2021 Twilio Inc
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal
@@ -18,5 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1818
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2020
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21-
SOFTWARE.
22-
21+
SOFTWARE.

README.md

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,47 +21,54 @@ This project is built using the [Flask](http://flask.pocoo.org/) web framework.
2121

2222
To run the app locally, first clone this repository and `cd` into its directory. Then:
2323

24-
1. Create a new virtual environment:
25-
- If using vanilla [virtualenv](https://virtualenv.pypa.io/en/latest/):
24+
1. Create and activate a new python3 virtual environment.
2625

27-
```bash
28-
$ virtualenv venv
29-
$ source venv/bin/activate
30-
```
31-
32-
- If using [virtualenvwrapper](https://virtualenvwrapper.readthedocs.org/en/latest/):
26+
```bash
27+
python3 -m venv venv
28+
source venv/bin/activate
29+
```
3330

34-
```bash
35-
$ mkvirtualenv appointment-reminders
36-
```
3731

38-
1. Install the requirements:
32+
1. Install the requirements using [pip](https://pip.pypa.io/en/stable/installing/).
3933

4034
```bash
41-
$ pip install -r requirements.txt
35+
pip install -r requirements.txt
4236
```
4337

44-
1. Start a local PostgreSQL database and create a database called `appointments`:
45-
- If on a Mac, we recommend [Postgres.app](http://postgresapp.com/). After install, open psql and run `CREATE DATABASE appointments;`
46-
- If Postgres is already installed locally, you can just run `createdb appointments` from a terminal
38+
1. Copy the `.env.example` file to `.env` and add the following values. Be sure to replace the placeholders and connection string with real information.
4739

48-
1. Copy the `.env_example` file to `.env`, and edit it to include your credentials for the Twilio API (found at https://www.twilio.com/user/account/voice) and your local Postgres database
49-
1. Run `source .env` to apply the environment variables (or even better, use [autoenv](https://github.com/kennethreitz/autoenv))
40+
```
41+
SECRET_KEY = 'your_authy_secret_key'
42+
43+
TWILIO_ACCOUNT_SID = '[your_twilio_account_sid]'
44+
TWILIO_AUTH_TOKEN = '[your_twilio_auth_token]'
45+
TWILIO_NUMBER = '[your_twilio_phone_number]'
46+
```
5047
51-
1. Run the migrations with:
48+
1. Create Flask application variables
49+
50+
```bash
51+
export FLASK_APP=reminders
52+
export FLASK_ENV=development
53+
```
5254

53-
```bash
54-
$ alembic upgrade +1
55-
```
56-
Note: If you have a local postgres installation where you access without password add this line to your `pg_hba.conf` file, *JUST FOR DEVELOPMENT, DO NOT USE THIS IN PRODUCTION*:
57-
`host all YOUR_USER 127.0.0.1/32 trust`
55+
1. Run the migrations.
56+
57+
```bash
58+
flask db upgrade
59+
```
5860

59-
1. Start a [redis](http://redis.io/) server to be our Celery broker. If on a Mac, we recommend installing redis through [homebrew](http://brew.sh/)
61+
1. Start a [redis](http://redis.io/) server to be our Celery broker.
62+
If on a Mac, we recommend installing redis through [homebrew](http://brew.sh/)
63+
If you already have docker installed in your system an easy way of get redis running is:
64+
```bash
65+
docker run -d -p 6379:6379 redis:latest
66+
```
6067

6168
1. Start the development server:
6269

6370
```bash
64-
$ python runapp.py
71+
flask run
6572
```
6673

6774
You can now access the application at
@@ -72,23 +79,28 @@ you must also start a separate Celery worker process.
7279
1. Start a new terminal session, `cd` into the repository, and active your
7380
`appointment-reminders` virtualenv
7481

82+
1. Activate Flask development environment
83+
84+
```bash
85+
export FLASK_ENV=development
86+
```
87+
7588
1. Start the Celery worker:
7689

7790
```bash
78-
$ celery -A reminders.celery worker -l info
91+
celery -A tasks.celery worker -l info
7992
```
8093

8194
Celery will now send SMS reminders for any new appointments you create through
8295
the web app.
8396

8497
## Run the tests
8598

86-
You can run the tests locally through [pytest](http://pytest.org/).
87-
88-
Follow the instructions in the [Local Development](#local-development) section above, and then run:
99+
You can run the tests locally. Follow the instructions in the
100+
[Local Development](#local-development) section above, and then run:
89101

90102
```bash
91-
$ py.test --cov tests
103+
python runtests.py
92104
```
93105

94106
You can then view the results with `coverage report` or build an HTML report with `coverage html`.

application.py

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import flask
2-
import flask.ext.sqlalchemy
2+
from flask_migrate import Migrate
3+
4+
from flask_sqlalchemy import SQLAlchemy
35

46
from celery import Celery
7+
8+
from config import config_classes
59
from views.appointment import (
610
AppointmentFormResource,
711
AppointmentResourceCreate,
@@ -11,7 +15,6 @@
1115

1216

1317
class Route(object):
14-
1518
def __init__(self, url, route_name, resource):
1619
self.url = url
1720
self.route_name = route_name
@@ -21,35 +24,35 @@ def __init__(self, url, route_name, resource):
2124
handlers = [
2225
Route('/', 'appointment.index', AppointmentResourceIndex),
2326
Route('/appointment', 'appointment.create', AppointmentResourceCreate),
24-
Route('/appointment/<int:id>/delete',
25-
'appointment.delete', AppointmentResourceDelete),
27+
Route(
28+
'/appointment/<int:id>/delete', 'appointment.delete', AppointmentResourceDelete
29+
),
2630
Route('/appointment/new', 'appointment.new', AppointmentFormResource),
2731
]
2832

2933

3034
class Application(object):
31-
32-
def __init__(self, routes, config, debug=True):
35+
def __init__(self, routes, environment):
3336
self.flask_app = flask.Flask(__name__)
3437
self.routes = routes
35-
self.debug = debug
36-
self._configure_app(config)
38+
self._configure_app(environment)
3739
self._set_routes()
3840

3941
def celery(self):
40-
app = self.flask_app
41-
celery = Celery(app.import_name, broker=app.config[
42-
'CELERY_BROKER_URL'])
43-
celery.conf.update(app.config)
42+
celery = Celery(
43+
self.flask_app.import_name, broker=self.flask_app.config['CELERY_BROKER_URL']
44+
)
45+
celery.conf.update(self.flask_app.config)
4446

4547
TaskBase = celery.Task
4648

4749
class ContextTask(TaskBase):
4850
abstract = True
4951

5052
def __call__(self, *args, **kwargs):
51-
with app.app_context():
53+
with self.flask_app.app_context():
5254
return TaskBase.__call__(self, *args, **kwargs)
55+
5356
celery.Task = ContextTask
5457

5558
return celery
@@ -60,25 +63,7 @@ def _set_routes(self):
6063
self.flask_app.add_url_rule(route.url, view_func=app_view)
6164

6265
def _configure_app(self, env):
63-
celery_url = env.get('CELERY_URL')
64-
65-
self.flask_app.config[
66-
'SQLALCHEMY_DATABASE_URI'] = env.get('DATABASE_URL')
67-
68-
self.flask_app.config['CELERY_BROKER_URL'] = env.get(
69-
'REDIS_URL', celery_url)
70-
self.flask_app.config['CELERY_RESULT_BACKEND'] = env.get(
71-
'REDIS_URL', celery_url)
72-
73-
self.flask_app.config['TWILIO_ACCOUNT_SID'] = env.get(
74-
'TWILIO_ACCOUNT_SID')
75-
self.flask_app.config['TWILIO_AUTH_TOKEN'] = env.get(
76-
'TWILIO_AUTH_TOKEN')
77-
self.flask_app.config['TWILIO_NUMBER'] = env.get('TWILIO_NUMBER')
78-
79-
self.flask_app.secret_key = env.get('SECRET_KEY')
80-
81-
self.db = flask.ext.sqlalchemy.SQLAlchemy(self.flask_app)
82-
83-
def start_app(self):
84-
self.flask_app.run(debug=self.debug)
66+
self.flask_app.config.from_object(config_classes[env])
67+
self.db = SQLAlchemy(self.flask_app)
68+
self.migrate = Migrate()
69+
self.migrate.init_app(self.flask_app, self.db)

black.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[tool.black]
2+
line-length = 90
3+
target-version = ['py36']
4+
include = '\.pyi?$'
5+
exclude = '''
6+
7+
(
8+
/(
9+
\.eggs # exclude a few common directories in the
10+
| \.git # root of the project
11+
| \.tox
12+
| \.venv
13+
| _build
14+
| build
15+
| dist
16+
)/
17+
)
18+
'''

config/__init__.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import os
2+
3+
from dotenv import load_dotenv
4+
5+
load_dotenv()
6+
7+
basedir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
8+
9+
10+
class DefaultConfig(object):
11+
SECRET_KEY = os.environ.get('SECRET_KEY')
12+
DEBUG = False
13+
SQLALCHEMY_TRACK_MODIFICATIONS = False
14+
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI')
15+
TWILIO_ACCOUNT_SID = os.environ.get('TWILIO_ACCOUNT_SID')
16+
TWILIO_AUTH_TOKEN = os.environ.get('TWILIO_AUTH_TOKEN')
17+
TWILIO_NUMBER = os.environ.get('TWILIO_NUMBER')
18+
19+
20+
class DevelopmentConfig(DefaultConfig):
21+
DEBUG = True
22+
SECRET_KEY = os.environ.get('SECRET_KEY', 'secret-key')
23+
SQLALCHEMY_DATABASE_URI = (
24+
os.environ.get('DATABASE_URI')
25+
or f"sqlite:///{os.path.join(basedir, 'dev.sqlite')}"
26+
)
27+
28+
29+
class TestConfig(DefaultConfig):
30+
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
31+
PRESERVE_CONTEXT_ON_EXCEPTION = False
32+
DEBUG = True
33+
TESTING = True
34+
WTF_CSRF_ENABLED = False
35+
SERVER_NAME = 'server.test'
36+
37+
38+
config_classes = {
39+
'testing': TestConfig,
40+
'development': DevelopmentConfig,
41+
'production': DefaultConfig,
42+
}

database.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from flask_sqlalchemy import SQLAlchemy
2+
from flask_migrate import Migrate
3+
4+
db = SQLAlchemy()
5+
migrate = Migrate()

0 commit comments

Comments
 (0)