Romain Clement
CTO @ Sylha, Freelance Software Engineer
Python Meetup Grenoble
2019-03-28
virtualenv
pip
requirements.txt
requirements-dev.txt
> venv myapp
> cd myapp
> source venv/bin/activate
> pip install -r requirements.txt
> pip install another-package
> pip freeze > requirements.txt
> pip uninstall previous-package
> pip freeze > requirements.txt
> pip list --outdated
> pip install another-package --upgrade
> pip freeze > requirements.txt
pipenv
Pipfile
Pipfile.lock
> pipenv install
> pipenv shell
> pipenv install another-package
> pipenv uninstall previous-package
> pipenv update --outdated
> pipenv update
> pipenv sync
> pipenv rm
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[packages]
celery = {extras = ["redis"]}
flask = "*"
redis = "==2.10.6"
[dev-packages]
pytest = "*"
[requires]
python_version = "3.6"
Porcelain for venv + pip under the hood
Specify dependencies contraints with Pipfile
Deterministic environment for dev and production
Updating packages a breeze
App configuration
.env, .env.example
pipenv shell
python-dotenv
FLASK_APP=myapp.wsgi:app
FLASK_ENV=development
SECRET_KEY=supersecretkey
API_KEY=apisupersecretkey
import os
SECRET_KEY = os.environ.get('SECRET_KEY')
API_KEY = os.environ.get('API_KEY')
DO NOT USE MAKEFILES!
pyinvoke
tasks.py
inv <task> <args>
from invoke import task
@task
def tests(ctx):
ctx.run('py.test tests')
@task
def lint(ctx):
ctx.run('flake8 myapp')
@task
def safety(ctx):
ctx.run('safety check')
@task(tests, lint, safety)
def qa(ctx):
pass
External services (databases, analytics, sentry)
Development and testing
docker-compose
version: '3'
services:
postgres:
image: 'postgres:10.2'
environment:
POSTGRES_USER: "${POSTGRES_USER}"
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
POSTGRES_DB: "${POSTGRES_DB}"
volumes:
- './data/postgres:/var/lib/postgresql/data'
ports:
- "${POSTGRES_PORT_HOST}:${POSTGRES_PORT}"
redis:
image: 'redis:4.0.8'
ports:
- "${REDIS_PORT_HOST}:${REDIS_PORT}"
python-dotenv
pyinvoke
tox
pytest
flake8
black
safety
liccheck
honcho
dist: xenial
language: python
python:
- "3.7"
install:
- pipenv install --dev
script:
- pipenv run inv qa
Dockerfile
docker-compose
FROM python:3.7-alpine
RUN set -ex \
&& pip install --upgrade pip \
&& pip install pipenv
WORKDIR /app
COPY Pipfile Pipfile
COPY Pipfile.lock Pipfile.lock
RUN set -ex \
&& pipenv install --deploy --system \
COPY . /app
EXPOSE 5000
ENTRYPOINT ["honcho", "start"]
CMD ["web"]
Heroku / Dokku
Build a Docker image automatically
Define multiple types of tasks
Procfile
honcho
web: gunicorn --name=myapp --worker-class=gevent --error-logfile=- myapp.wsgi:app
worker: celery worker --app celery_worker:celery --config celery_config --loglevel=info
beat: celery beat --app celery_worker:celery --config celery_config --loglevel=info
Zeit Now, AWS Lambda, Azure functions
Stateless app automatic scaling
Short-lived app instances
Run a single entry-point handler function
Can be a WSGI / ASGI app
Not appropriate for everything
Dead-simple mailer micro-service for static websites
The 12-factor app: https://12factor.net Pipenv: https://pipenv.readthedocs.io Travis-CI: https://travis-ci.org Docker: https://docs.docker.com Kubernetes: https://kubernetes.io Zeit Now: https://zeit.co/docs Heroku: https://www.heroku.com Dokku: http://dokku.viewdocs.io/dokku
By Romain Clement
Python software development for the modern age (or embracing the unexpected vertue of ignorance)