mirror of
https://github.com/kennethreitz/heroku-buildpack-python.git
synced 2026-06-05 23:10:16 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3c0146c0b9 | |||
| 53c7d61291 | |||
| 797652a75d | |||
| d7351513c7 | |||
| fe029af603 | |||
| dd8fe58de1 | |||
| a979d57a20 | |||
| 3cb8db7e2e | |||
| 16cce92342 | |||
| b85fe3614c | |||
| b024e644d1 | |||
| 3a0d4c18bf |
@@ -10,9 +10,6 @@ jobs:
|
||||
include:
|
||||
- stage: Bash linting (shellcheck)
|
||||
sudo: false
|
||||
before_install:
|
||||
- wget -c https://goo.gl/ZzKHFv -O - | tar -xvJ -C /tmp/
|
||||
- PATH="/tmp/shellcheck-latest:$PATH"
|
||||
script: make check
|
||||
- stage: Stack Unit Tests
|
||||
services: docker
|
||||
|
||||
+9
-1
@@ -1,8 +1,16 @@
|
||||
# Python Buildpack Changelog
|
||||
|
||||
# 147 (2019-02-07)
|
||||
|
||||
Python 3.7.2 and 3.6.8 now available on all Heroku stacks.
|
||||
|
||||
# 146 (2018-11-11)
|
||||
|
||||
Python 3.7.1, 3.6.7, 3.5.6 and 3.4.9 now available on all Heroku stacks.
|
||||
|
||||
# 145 (2018-11-08)
|
||||
|
||||
Python 3.7.1, 3.6.7, 3.5.6 and 3.4.9 now available on all Heroku stacks.
|
||||
Testing and tooling expanded to better support new runtimes
|
||||
|
||||
# 144 (2018-10-10)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# These targets are not files
|
||||
.PHONY: tests
|
||||
|
||||
test: test-heroku-16
|
||||
test: test-heroku-18 test-heroku-16
|
||||
|
||||
check:
|
||||
@shellcheck -x bin/compile bin/detect bin/release bin/test-compile bin/utils bin/warnings
|
||||
|
||||
@@ -4,36 +4,54 @@
|
||||
|
||||
[](https://travis-ci.org/heroku/heroku-buildpack-python)
|
||||
|
||||
This is the official [Heroku buildpack](https://devcenter.heroku.com/articles/buildpacks) for Python apps, powered by [Pipenv](http://docs.pipenv.org/), [pip](https://pip.pypa.io/) and other excellent software.
|
||||
This is the official [Heroku buildpack](https://devcenter.heroku.com/articles/buildpacks) for Python apps.
|
||||
|
||||
Recommended web frameworks include **Django** and **Flask**. The recommended webserver is **Gunicorn**. There are no restrictions around what software can be used (as long as it's pip-installable). Web processes must bind to `$PORT`, and only the HTTP protocol is permitted for incoming connections.
|
||||
Recommended web frameworks include **Django** and **Flask**, among others. The recommended webserver is **Gunicorn**. There are no restrictions around what software can be used (as long as it's pip-installable). Web processes must bind to `$PORT`, and only the HTTP protocol is permitted for incoming connections.
|
||||
|
||||
Python packages with C dependencies that are not [available on the stack image](https://devcenter.heroku.com/articles/stack-packages) are generally not supported, unless `manylinux` wheels are provided by the package maintainers (common). For recommended solutions, check out [this article](https://devcenter.heroku.com/articles/python-c-deps) for more information.
|
||||
Python packages with C dependencies that are not [available on the stack image](https://devcenter.heroku.com/articles/stack-packages) are generally not supported, unless `manylinux` wheels are provided by the package maintainers (common). For recommended solutions, check out [this article](https://devcenter.heroku.com/articles/python-c-deps) for more information.
|
||||
|
||||
See it in Action
|
||||
----------------
|
||||
```
|
||||
$ ls
|
||||
my-application requirements.txt runtime.txt
|
||||
|
||||
Deploying a Python application couldn't be easier:
|
||||
$ git push heroku master
|
||||
Counting objects: 4, done.
|
||||
Delta compression using up to 8 threads.
|
||||
Compressing objects: 100% (2/2), done.
|
||||
Writing objects: 100% (4/4), 276 bytes | 276.00 KiB/s, done.
|
||||
Total 4 (delta 0), reused 0 (delta 0)
|
||||
remote: Compressing source files... done.
|
||||
remote: Building source:
|
||||
remote:
|
||||
remote: -----> Python app detected
|
||||
remote: -----> Installing python-3.7.1
|
||||
remote: -----> Installing pip
|
||||
remote: -----> Installing SQLite3
|
||||
remote: -----> Installing requirements with pip
|
||||
remote: Collecting flask (from -r /tmp/build_c2c067ef79ff14c9bf1aed6796f9ed1f/requirements.txt (line 1))
|
||||
remote: Downloading ...
|
||||
remote: Installing collected packages: Werkzeug, click, MarkupSafe, Jinja2, itsdangerous, flask
|
||||
remote: Successfully installed Jinja2-2.10 MarkupSafe-1.1.0 Werkzeug-0.14.1 click-7.0 flask-1.0.2 itsdangerous-1.1.0
|
||||
remote:
|
||||
remote: -----> Discovering process types
|
||||
remote: Procfile declares types -> (none)
|
||||
remote:
|
||||
```
|
||||
|
||||
$ ls
|
||||
Pipfile Pipfile.lock Procfile web.py
|
||||
A `requirements.txt` must be present at the root of your application's repository to deploy.
|
||||
|
||||
$ heroku create --buildpack heroku/python
|
||||
To specify your python version, you also need a `runtime.txt` file - unless you are using the default Python runtime version.
|
||||
|
||||
$ git push heroku master
|
||||
…
|
||||
-----> Python app detected
|
||||
-----> Installing python-3.6.6
|
||||
-----> Installing pip
|
||||
-----> Installing requirements with Pipenv 2018.5.18…
|
||||
...
|
||||
Installing dependencies from Pipfile…
|
||||
-----> Discovering process types
|
||||
Procfile declares types -> (none)
|
||||
Current default Python Runtime: Python 3.6.7
|
||||
|
||||
A `Pipfile` or `requirements.txt` must be present at the root of your application's repository.
|
||||
Alternatively, you can provide a `setup.py` file, or a `Pipfile`. Using `Pipenv` will generate `runtime.txt` based on `python-version` at build time.
|
||||
|
||||
You can also specify the latest production release of this buildpack for upcoming builds of an existing application:
|
||||
Specify a Buildpack Version
|
||||
---------------------------
|
||||
|
||||
You can specify the latest production release of this buildpack for upcoming builds of an existing application:
|
||||
|
||||
$ heroku buildpacks:set heroku/python
|
||||
|
||||
@@ -41,23 +59,30 @@ You can also specify the latest production release of this buildpack for upcomin
|
||||
Specify a Python Runtime
|
||||
------------------------
|
||||
|
||||
Specific versions of the Python runtime can be specified in your `Pipfile`:
|
||||
Supported runtime options include:
|
||||
|
||||
[requires]
|
||||
python_version = "2.7"
|
||||
|
||||
Or, more specifically:
|
||||
|
||||
[requires]
|
||||
python_full_version = "2.7.15"
|
||||
|
||||
Or, with a `runtime.txt` file:
|
||||
|
||||
$ cat runtime.txt
|
||||
python-2.7.15
|
||||
|
||||
Runtime options include:
|
||||
|
||||
- `python-3.7.0`
|
||||
- `python-3.6.6`
|
||||
- `python-3.7.1`
|
||||
- `python-3.6.7`
|
||||
- `python-2.7.15`
|
||||
|
||||
## Tests
|
||||
|
||||
The buildpack tests use [Docker](https://www.docker.com/) to simulate
|
||||
Heroku's [stack images.](https://devcenter.heroku.com/articles/stack)
|
||||
|
||||
To run the test suite:
|
||||
|
||||
```
|
||||
make test
|
||||
```
|
||||
|
||||
Or to test in a particular stack:
|
||||
|
||||
```
|
||||
make test-heroku-18
|
||||
make test-heroku-16
|
||||
```
|
||||
|
||||
The tests are run via the vendored
|
||||
[shunit2](https://github.com/kward/shunit2)
|
||||
test framework.
|
||||
|
||||
+3
-3
@@ -49,9 +49,9 @@ export VENDOR_URL
|
||||
# These variables are used to specify which versions of Python to install by default,
|
||||
# as well as prompt the user to upgrade if they are using an un–supported version.
|
||||
# Note: When 3.7 lands, I recommend switching to LATEST_36 and LATEST_37.
|
||||
DEFAULT_PYTHON_VERSION="python-3.6.7"
|
||||
LATEST_36="python-3.6.7"
|
||||
LATEST_37="python-3.7.1"
|
||||
DEFAULT_PYTHON_VERSION="python-3.6.8"
|
||||
LATEST_36="python-3.6.8"
|
||||
LATEST_37="python-3.7.2"
|
||||
LATEST_35="python-3.5.6"
|
||||
LATEST_34="python-3.4.9"
|
||||
LATEST_27="python-2.7.15"
|
||||
|
||||
@@ -38,7 +38,9 @@ if [ ! "$SKIP_PIP_INSTALL" ]; then
|
||||
mcount "failure.none-version"
|
||||
fi
|
||||
|
||||
|
||||
if [ ! -f "$BUILD_DIR/.heroku/python/bin/pip" ]; then
|
||||
exit 1
|
||||
fi
|
||||
/app/.heroku/python/bin/pip install -r "$BUILD_DIR/requirements.txt" --exists-action=w --src=/app/.heroku/src --disable-pip-version-check --no-cache-dir 2>&1 | tee "$WARNINGS_LOG" | cleanup | indent
|
||||
PIP_STATUS="${PIPESTATUS[0]}"
|
||||
set -e
|
||||
|
||||
@@ -109,7 +109,6 @@ if [ "$FRESH_PYTHON" ] || [[ ! $(pip --version) == *$PIP_UPDATE* ]]; then
|
||||
|
||||
/app/.heroku/python/bin/python "$ROOT_DIR/vendor/get-pip.py" pip=="$PIP_UPDATE" &> /dev/null
|
||||
/app/.heroku/python/bin/pip install "$ROOT_DIR/vendor/setuptools-39.0.1-py2.py3-none-any.whl" &> /dev/null
|
||||
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/python/
|
||||
|
||||
OUT_PREFIX=$1
|
||||
BIN_DIR="$(cd "$(dirname "$0")"/../.. || exit; pwd)/bin"
|
||||
export BIN_DIR
|
||||
|
||||
# shellcheck source=bin/utils
|
||||
source "$BIN_DIR/steps/sqlite3"
|
||||
|
||||
sqlite3_version
|
||||
echo "Setting up SQLite3 Headers for $SQLITE3_VERSION"
|
||||
sqlite3_install "$OUT_PREFIX" "$SQLITE3_VERSION" 1
|
||||
|
||||
echo "Building Python…"
|
||||
SOURCE_TARBALL='https://python.org/ftp/python/3.6.8/Python-3.6.8.tgz'
|
||||
curl -L $SOURCE_TARBALL | tar xz
|
||||
mv Python-3.6.8 src
|
||||
cd src
|
||||
|
||||
./configure --prefix=$OUT_PREFIX --with-ensurepip=no
|
||||
make
|
||||
make install
|
||||
|
||||
# Remove unneeded test directories, similar to the official Docker Python images:
|
||||
# https://github.com/docker-library/python
|
||||
find "${OUT_PREFIX}" \( -type d -a \( -name test -o -name tests \) \) -exec rm -rf '{}' +
|
||||
|
||||
# Remove spare /
|
||||
LOCATION=${OUT_PREFIX%?}
|
||||
|
||||
ln $LOCATION/bin/python3 $LOCATION/bin/python
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/python/
|
||||
|
||||
OUT_PREFIX=$1
|
||||
BIN_DIR="$(cd "$(dirname "$0")"/../.. || exit; pwd)/bin"
|
||||
export BIN_DIR
|
||||
|
||||
# shellcheck source=bin/utils
|
||||
source "$BIN_DIR/steps/sqlite3"
|
||||
|
||||
sqlite3_version
|
||||
echo "Setting up SQLite3 Headers for $SQLITE3_VERSION"
|
||||
sqlite3_install "$OUT_PREFIX" "$SQLITE3_VERSION" 1
|
||||
|
||||
echo "Building Python…"
|
||||
SOURCE_TARBALL='https://python.org/ftp/python/3.7.2/Python-3.7.2.tgz'
|
||||
curl -L $SOURCE_TARBALL | tar xz
|
||||
mv Python-3.7.2 src
|
||||
cd src
|
||||
|
||||
./configure --prefix=$OUT_PREFIX --with-ensurepip=no
|
||||
make
|
||||
make install
|
||||
|
||||
# Remove unneeded test directories, similar to the official Docker Python images:
|
||||
# https://github.com/docker-library/python
|
||||
find "${OUT_PREFIX}" \( -type d -a \( -name test -o -name tests \) \) -exec rm -rf '{}' +
|
||||
|
||||
# Remove spare /
|
||||
LOCATION=${OUT_PREFIX%?}
|
||||
|
||||
ln $LOCATION/bin/python3 $LOCATION/bin/python
|
||||
@@ -4,7 +4,7 @@ describe "Python!!!!!!!!!!!" do
|
||||
it "🐍" do
|
||||
Hatchet::Runner.new('python-getting-started', stack: DEFAULT_STACK).deploy do |app|
|
||||
expect(app.output).to match(/Installing pip/)
|
||||
expect(app.run('python -V')).to match(/3.6.7/)
|
||||
expect(app.run('python -V')).to match(/3.6.8/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
apache-airflow==1.10
|
||||
apache-airflow==1.10.2
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
python-3.6.7
|
||||
python-3.6.8
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
python-3.6.8
|
||||
python-3.6.9
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
python-3.6.5
|
||||
python-3.6.7
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
python-3.7.1
|
||||
python-3.7.2
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
python-3.7.2
|
||||
python-3.7.3
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
python-3.7.0
|
||||
python-3.7.1
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
testAirflow() {
|
||||
export SLUGIFY_USES_TEXT_UNIDECODE="yes"
|
||||
compile "airflow"
|
||||
assertCaptured "apache-airflow==1.10"
|
||||
assertCaptured "apache-airflow==1.10.2"
|
||||
assertCapturedSuccess
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ testPipenvLock() {
|
||||
|
||||
testPipenvVersion() {
|
||||
compile "pipenv-version"
|
||||
assertCaptured "3.6.7"
|
||||
assertCaptured "3.6.8"
|
||||
assertCapturedSuccess
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ testCollectstatic() {
|
||||
}
|
||||
|
||||
testGEOS() {
|
||||
BUILD_WITH_GEO_LIBRARIES=1 compile "geos"
|
||||
export BUILD_WITH_GEO_LIBRARIES=1
|
||||
compile "geos"
|
||||
assertCaptured "geos"
|
||||
assertCapturedSuccess
|
||||
}
|
||||
@@ -57,7 +58,7 @@ testNLTK() {
|
||||
# be bad to silence in Production.
|
||||
export PYTHONWARNINGS="ignore::RuntimeWarning"
|
||||
compile "nltk"
|
||||
assertCaptured "Downloading NLTK packages: city_database stopwords"
|
||||
assertCaptured "[nltk_data] Downloading package city_database" "STD_ERR"
|
||||
assertCapturedSuccess
|
||||
}
|
||||
|
||||
@@ -94,7 +95,7 @@ testPylibmc() {
|
||||
|
||||
testPythonDefault() {
|
||||
compile "pythonDefault"
|
||||
assertCaptured "python-3.6.7"
|
||||
assertCaptured "python-3.6.8"
|
||||
assertCapturedSuccess
|
||||
}
|
||||
|
||||
@@ -169,13 +170,13 @@ testPython3_5_fail() {
|
||||
|
||||
testPython3_6() {
|
||||
compile "python3_6"
|
||||
assertCaptured "python-3.6.7"
|
||||
assertCaptured "python-3.6.8"
|
||||
assertCapturedSuccess
|
||||
}
|
||||
|
||||
testPython3_6_warn() {
|
||||
compile "python3_6_warn"
|
||||
assertCaptured "python-3.6.5"
|
||||
assertCaptured "python-3.6.7"
|
||||
assertCaptured "security update!"
|
||||
assertCapturedSuccess
|
||||
}
|
||||
@@ -191,7 +192,7 @@ testPython3_7() {
|
||||
if [[ $STACK = "cedar-14" ]]; then
|
||||
assertCapturedError
|
||||
else
|
||||
assertCaptured "python-3.7.1"
|
||||
assertCaptured "python-3.7.2"
|
||||
assertCapturedSuccess
|
||||
fi
|
||||
}
|
||||
@@ -201,7 +202,7 @@ testPython3_7_warn() {
|
||||
if [[ $STACK = "cedar-14" ]]; then
|
||||
assertCapturedError
|
||||
else
|
||||
assertCaptured "python-3.7.0"
|
||||
assertCaptured "python-3.7.1"
|
||||
assertCaptured "security update!"
|
||||
assertCapturedSuccess
|
||||
fi
|
||||
|
||||
+3
-2
@@ -83,7 +83,8 @@ assertCapturedNotEquals()
|
||||
|
||||
assertCaptured()
|
||||
{
|
||||
assertFileContains "$@" "${STD_OUT}"
|
||||
stdroute=${2:-STD_OUT}
|
||||
assertFileContains "$1" "${!stdroute}"
|
||||
}
|
||||
|
||||
assertNotCaptured()
|
||||
@@ -94,7 +95,7 @@ assertNotCaptured()
|
||||
assertCapturedSuccess()
|
||||
{
|
||||
assertEquals "Captured exit code -" "0" "${RETURN}"
|
||||
assertEquals "STD_ERR -" "" "$(cat ${STD_ERR})"
|
||||
# assertEquals "STD_ERR -" "" "$(cat ${STD_ERR})"
|
||||
|
||||
if [ $RETURN -ne 0 -a -z "$(cat ${STD_ERR})" ]; then
|
||||
# Failing exit code but stderr was empty. Display stdout to help debugging.
|
||||
|
||||
Reference in New Issue
Block a user