john pfeiffer
  • Home
  • Categories
  • Tags
  • Archives

heroku intro virtualenv bitbucket and tdd flask gunicorn

# assuming you've already install heroku cli toolbelt installed
# wget -qO- https://toolbelt.heroku.com/install-ubuntu.sh | sh
# assuming you've got your SSH key for bitbucket already setup

Create a new empty repo on bitbucket, REPONAME

THEN, on your development machine:
mkdir REPONAME
cd REPONAME
heroku login


# A LOT OF PROBLEMS CAN OCCUR AROUND MULTIPLE HEROKU ACCOUNTS (WORK AND PERSONAL) AND SSH KEYS
 !  Your account email@example.com does not have access to kittyandbear.
 !
 !  SSH Key Fingerprint: e5:1c:12:4d:c7:6a:d1:d8:96:20:35:f0:bf:b4:47

1. install heroku toolbelt  wget -qO- https://toolbelt.heroku.com/install-ubuntu.sh | sh
2. create a new ssh key on a clean ubuntu vm: ssh-keygen -t rsa
3. ADD THE SSH KEY TO YOUR LOCAL KEYCHAIN: ssh-add ~/.ssh/id_rsa
4. remove all ssh keys from your personal account
5. add the NEW id_rsa.pub to the heroku Account -> SSH Keys (https://dashboard.heroku.com/account)
6. heroku git:clone -a APPNAME


- - - - - -
sudo pip install virtualenv # version 1.7.1.2 from Ubuntu is old
pip install virtualenv --upgrade  # ensure the newest version, e.g. 1.11.4  http://www.virtualenv.org/en/latest/virtualenv.html#usage

virtulenv venv  # creates a copy of Python in the ./venv directory,
source venv/bin/activate
pip install pip --upgrade  # upgrade pip from 1.1 to 1.53, otherwise really bad pip
pip install Flask gunicorn --upgrade  # if installing to the host OS it would be sudo pip install BUT then all of the packages would be in pip freeze  # list the packages installed
# deactivate  # stop using the virtaul environment

echo -e "web: gunicorn hello:app" > Procfile
# yes there's a space after the colon indicating run gunicorn passing in hello.py file, global variable app

pip freeze > requirements.txt
    Flask==0.10.1
    Jinja2==2.7.2
    MarkupSafe==0.18
    Werkzeug==0.9.4
    argparse==1.2.1
    gunicorn==18.0
    itsdangerous==0.23
    wsgiref==0.1.2

- - - - - -
vi hello_test.py

import unittest
import hello


class HelloTestCase(unittest.TestCase):

    def setUp(self):
        hello.app.config['TESTING'] = True
        self.app = hello.app.test_client()

    # def tearDown(self):

    def test_index_route(self):
        response = self.app.get('/', content_type='text/plaintext')
        self.assertEqual(200, response.status_code)
        self.assertEqual('Hello!', response.data)

    def test_not_found_404(self):
        response = self.app.get('/doesnotexist')
        self.assertEqual(404, response.status_code)


if __name__ == '__main__':
    unittest.main()

- - - - - -
vi hello.py

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello!'

if __name__ == '__main__':
    app.run()

# "python hello_test.py" runs the unit tests (should all pass with . . ) and make a hello.pyc
# "python hello.py" runs Flask(Werkzeug) dev server on 127.0.0.1:5000 , for external access: app.run(host='0.0.0.0')
# "foreman start" uses the Heroku Toolbelt and the Procfile to run the app, localhost:5000 , control + C to quit

- - - - - -
# prevent binaries from being saved in the repository
echo -e "venv\n*.pyc" >> .gitignore

git init
git add .
git commit -m "part1: tdd hello flask app on heroku (with gitignore, requirements, Procfile)"
[master (root-commit) 192ec69] part1: tdd hello flask app on heroku (with gitignore, requirements, Procfile)
 5 files changed, 47 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 Procfile
 create mode 100644 hello.py
 create mode 100644 hello_test.py
 create mode 100644 requirements.txt

- - - - - -
heroku apps:create REPONAME

git remote add all ssh://git@bitbucket.org/USERNAME/REPONAME.git
git remote set-url --add all git@heroku.com:REPONAME.git

git config --list
    user.name=Your Name
    user.email=yourname@example.com
    core.repositoryformatversion=0
    core.filemode=true
    core.bare=false
    core.logallrefupdates=true

    remote.heroku.url=git@heroku.com:REPONAME.git
    remote.heroku.fetch=+refs/heads/*:refs/remotes/heroku/*

    remote.all.url=git@heroku.com:REPONAME.git
    remote.all.url=ssh://git@bitbucket.org/USERNAME/REPONAME.git
    remote.all.fetch=+refs/heads/*:refs/remotes/all/*

git push all master     #  Heroku first push takes a few minutes

    Counting objects: 7, done.
    Delta compression using up to 4 threads.
    Compressing objects: 100% (5/5), done.
    Writing objects: 100% (7/7), 968 bytes, done.
    Total 7 (delta 0), reused 0 (delta 0)
    To ssh://git@bitbucket.org/USERNAME/REPONAME.git
     * [new branch]      master -> master
    Initializing repository, done.

    -----> Python app detected
    -----> No runtime.txt provided; assuming python-2.7.6.
    -----> Preparing Python runtime (python-2.7.6)
    -----> Installing Setuptools (2.1)
    -----> Installing Pip (1.5.4)
    -----> Installing dependencies using Pip (1.5.4)
    ...

       Successfully installed Flask Jinja2 MarkupSafe Werkzeug argparse gunicorn itsdangerous
       Cleaning up...
    -----> Discovering process types
       Procfile declares types -> web

    -----> Compressing... done, 30.4MB
    -----> Launching... done, v3
       http://tddflask.herokuapp.com deployed to Heroku

    To git@heroku.com:tddflask.git
     * [new branch]      master -> master

curl http://REPONAME.herokuapp.com  # Hello!
wget -q -O- http://REPONAME.herokuapp.com  # Hello!

deactivate  # turns off virtualenv and returns to normal OS python environment
# git pull all master

- - - - - -
- - - - - -
- - - - - -

# git remote add origin git@bitbucket.org:USERNAME/REPONAME.git

echo -e "venv\n__pycache__\n*.pyc\n*~\n*.swp\n*.egg\n*.egg-info" >> .gitignore

git config --list

- - -
#echo -e "# This is my README" >> README.md
#git add README.md .gitignore
#git commit -m "Adding a README"
#git push -u origin master

- - -
OR download an existing- repo...
git clone git@bitbucket.org:USERNAME/REPONAME.git

git clone git@heroku.com:tddflask.git -o heroku

- - -
CRAZY ERRORS? from old pip? argparse dependency can't be met?!?!
# answer: Heroku upgrade to pip 1.5.2 which introduced a bug, they upgraded again to 1.5.4 (and fixed a typo)
# https://github.com/heroku/heroku-buildpack-python/commits/master


-----> Installing Pip (1.5.2)
-----> Installing dependencies using Pip (1.5.2)
       Downloading/unpacking Flask==0.10.1 (from -r requirements.txt (line 1))
    ...
    Error with argparse and setup.py

- - -
TypeError: 'int' object is not callable

Flask types that are returned need some help, like:

from flask import jsonify

def build_response(status_code, message_dict):
    response = jsonify(message_dict)
    response.status_code = status_code
    return response

  • « decorators on classes introspection dir properties
  • rpsls unittest test »

Published

Nov 18, 2014

Category

python

~719 words

Tags

  • and 29
  • bitbucket 1
  • flask 2
  • gunicorn 1
  • heroku 4
  • intro 9
  • python 180
  • tdd 2
  • virtualenv 1