Compare commits

...

15 Commits

Author SHA1 Message Date
David Zülke c361c2ffc4 HOTFIX for cedar-14 python builds (#805) 2019-03-04 14:46:33 -08:00
Casey 13d2a58add update changelog (#803) 2019-02-21 15:24:08 -08:00
Casey 49e9147439 track usage of older feature steps (#802)
* track usage of older feature steps

* remove typo whitespace

* make buildvars consistently cased
2019-02-21 14:06:20 -08:00
Casey 3c0146c0b9 Merge pull request #797 from heroku/v-147
V 147
2019-02-12 13:01:43 -06:00
Casey Faist 53c7d61291 correct date mixup + update changelog 2019-02-07 12:35:25 -05:00
Casey Faist 797652a75d new runtimes and travis test updates 2019-01-31 14:46:42 -05:00
Casey Faist d7351513c7 changelog and test update 2018-12-12 17:26:28 -05:00
Casey fe029af603 Merge pull request #785 from heroku/update-readme
Update readme
2018-12-12 10:20:01 -05:00
Casey dd8fe58de1 Merge pull request #784 from heroku/update-changelog
update changelog
2018-12-12 10:19:24 -05:00
Casey Faist a979d57a20 update readme 2018-11-15 17:41:01 -06:00
Casey Faist 3cb8db7e2e update release date 2018-11-15 17:31:29 -06:00
Casey Faist 16cce92342 update changelog 2018-11-15 16:59:51 -06:00
Casey b85fe3614c Merge pull request #783 from heroku/document-tests
Document tests
2018-11-15 12:41:15 -06:00
Hunter Loftis b024e644d1 Merge branch 'master' of github.com:heroku/heroku-buildpack-python into document-tests 2018-11-15 12:45:28 -05:00
Hunter Loftis 3a0d4c18bf add heroku-18 to test targets and document running tests 2018-11-15 11:57:44 -05:00
25 changed files with 180 additions and 69 deletions
-3
View File
@@ -10,9 +10,6 @@ jobs:
include: include:
- stage: Bash linting (shellcheck) - stage: Bash linting (shellcheck)
sudo: false sudo: false
before_install:
- wget -c https://goo.gl/ZzKHFv -O - | tar -xvJ -C /tmp/
- PATH="/tmp/shellcheck-latest:$PATH"
script: make check script: make check
- stage: Stack Unit Tests - stage: Stack Unit Tests
services: docker services: docker
+13 -1
View File
@@ -1,8 +1,20 @@
# Python Buildpack Changelog # Python Buildpack Changelog
# 148 (2019-02-21)
No user facing changes, improving internal metrics
# 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) # 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) # 144 (2018-10-10)
+1 -1
View File
@@ -1,7 +1,7 @@
# These targets are not files # These targets are not files
.PHONY: tests .PHONY: tests
test: test-heroku-16 test: test-heroku-18 test-heroku-16
check: check:
@shellcheck -x bin/compile bin/detect bin/release bin/test-compile bin/utils bin/warnings @shellcheck -x bin/compile bin/detect bin/release bin/test-compile bin/utils bin/warnings
+62 -37
View File
@@ -4,36 +4,54 @@
[![Build Status](https://travis-ci.org/heroku/heroku-buildpack-python.svg?branch=master)](https://travis-ci.org/heroku/heroku-buildpack-python) [![Build Status](https://travis-ci.org/heroku/heroku-buildpack-python.svg?branch=master)](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 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 A `requirements.txt` must be present at the root of your application's repository to deploy.
Pipfile Pipfile.lock Procfile web.py
$ 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 Current default Python Runtime: Python 3.6.7
-----> 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)
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 $ 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 Specify a Python Runtime
------------------------ ------------------------
Specific versions of the Python runtime can be specified in your `Pipfile`: Supported runtime options include:
[requires] - `python-3.7.1`
python_version = "2.7" - `python-3.6.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-2.7.15` - `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
View File
@@ -49,9 +49,9 @@ export VENDOR_URL
# These variables are used to specify which versions of Python to install by default, # 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 unsupported version. # as well as prompt the user to upgrade if they are using an unsupported version.
# Note: When 3.7 lands, I recommend switching to LATEST_36 and LATEST_37. # Note: When 3.7 lands, I recommend switching to LATEST_36 and LATEST_37.
DEFAULT_PYTHON_VERSION="python-3.6.7" DEFAULT_PYTHON_VERSION="python-3.6.8"
LATEST_36="python-3.6.7" LATEST_36="python-3.6.8"
LATEST_37="python-3.7.1" LATEST_37="python-3.7.2"
LATEST_35="python-3.5.6" LATEST_35="python-3.5.6"
LATEST_34="python-3.4.9" LATEST_34="python-3.4.9"
LATEST_27="python-2.7.15" LATEST_27="python-2.7.15"
+1 -1
View File
@@ -26,9 +26,9 @@ if (pip-grep -s requirements.txt GDAL gdal pygdal &> /dev/null) then
mkdir -p .heroku/vendor mkdir -p .heroku/vendor
# Download and extract cryptography into target vendor directory. # Download and extract cryptography into target vendor directory.
curl "$VENDORED_GDAL" -s | tar zxv -C .heroku/vendor &> /dev/null curl "$VENDORED_GDAL" -s | tar zxv -C .heroku/vendor &> /dev/null
mcount "steps.vendor.gdal"
fi fi
GDAL=$(pwd)/vendor GDAL=$(pwd)/vendor
export GDAL export GDAL
fi fi
+3
View File
@@ -22,6 +22,7 @@ source "$BIN_DIR/utils"
# If GDAL exists within requirements, use vendored gdal. # If GDAL exists within requirements, use vendored gdal.
if [[ "$BUILD_WITH_GEO_LIBRARIES" ]]; then if [[ "$BUILD_WITH_GEO_LIBRARIES" ]]; then
mcount "buildvar.BUILD_WITH_GEO_LIBRARIES"
if [ ! -f ".heroku/vendor/bin/proj" ]; then if [ ! -f ".heroku/vendor/bin/proj" ]; then
echo "-----> Bootstrapping gdal, geos, proj." echo "-----> Bootstrapping gdal, geos, proj."
@@ -31,9 +32,11 @@ if [[ "$BUILD_WITH_GEO_LIBRARIES" ]]; then
curl "$VENDORED_GEOS" -s | tar zxv -C .heroku/vendor &> /dev/null curl "$VENDORED_GEOS" -s | tar zxv -C .heroku/vendor &> /dev/null
curl "$VENDORED_PROJ" -s | tar zxv -C .heroku/vendor &> /dev/null curl "$VENDORED_PROJ" -s | tar zxv -C .heroku/vendor &> /dev/null
mcount "steps.vendor.geo_libs"
# Copy libjasper from build image to slug. # Copy libjasper from build image to slug.
if [[ "$STACK" == "heroku-16" ]]; then if [[ "$STACK" == "heroku-16" ]]; then
cp /usr/lib/x86_64-linux-gnu/libjasper.so* ".heroku/vendor/lib/." cp /usr/lib/x86_64-linux-gnu/libjasper.so* ".heroku/vendor/lib/."
mcount "steps.vendor.libjasper"
fi fi
fi fi
+1 -1
View File
@@ -4,6 +4,6 @@
if [[ -f "requirements.txt" ]]; then if [[ -f "requirements.txt" ]]; then
if (grep -Fiq "hg+" requirements.txt) then if (grep -Fiq "hg+" requirements.txt) then
/app/.heroku/python/bin/pip install mercurial | cleanup | indent /app/.heroku/python/bin/pip install mercurial | cleanup | indent
mcount "steps.mercurial"
fi fi
fi fi
+2
View File
@@ -27,6 +27,8 @@ if sp-grep -s nltk; then
python -m nltk.downloader -d "$BUILD_DIR/.heroku/python/nltk_data" "${nltk_packages[@]}" | indent python -m nltk.downloader -d "$BUILD_DIR/.heroku/python/nltk_data" "${nltk_packages[@]}" | indent
set_env NLTK_DATA "/app/.heroku/python/nltk_data" set_env NLTK_DATA "/app/.heroku/python/nltk_data"
mcount "buildvar.NLTK_PACKAGES_DEFINITION"
mcount "steps.nltk"
else else
puts-warn "'nltk.txt' not found, not downloading any corpora" puts-warn "'nltk.txt' not found, not downloading any corpora"
puts-warn "Learn more: https://devcenter.heroku.com/articles/python-nltk" puts-warn "Learn more: https://devcenter.heroku.com/articles/python-nltk"
+3 -1
View File
@@ -38,7 +38,9 @@ if [ ! "$SKIP_PIP_INSTALL" ]; then
mcount "failure.none-version" mcount "failure.none-version"
fi 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 /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]}" PIP_STATUS="${PIPESTATUS[0]}"
set -e set -e
+1
View File
@@ -29,6 +29,7 @@ if (pip-grep -s requirements.txt pylibmc &> /dev/null) then
mkdir -p .heroku/vendor mkdir -p .heroku/vendor
# Download and extract libmemcached into target vendor directory. # Download and extract libmemcached into target vendor directory.
curl "$VENDORED_MEMCACHED" -s | tar zxv -C .heroku/vendor &> /dev/null curl "$VENDORED_MEMCACHED" -s | tar zxv -C .heroku/vendor &> /dev/null
mcount "steps.vendor.pylibmc"
fi fi
LIBMEMCACHED=$(pwd)/vendor LIBMEMCACHED=$(pwd)/vendor
-1
View File
@@ -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/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 /app/.heroku/python/bin/pip install "$ROOT_DIR/vendor/setuptools-39.0.1-py2.py3-none-any.whl" &> /dev/null
fi fi
set -e set -e
+5 -1
View File
@@ -4,7 +4,11 @@
source "$BIN_DIR/utils" source "$BIN_DIR/utils"
sqlite3_version() { sqlite3_version() {
SQLITE3_VERSION=${SQLITE3_VERSION:-$(dpkg -s libsqlite3-0 | grep Version | sed 's/Version: //')} if [ "$STACK" = "cedar-14" ]; then
SQLITE3_VERSION="3.8.2-1ubuntu2.2"
else
SQLITE3_VERSION=${SQLITE3_VERSION:-$(dpkg -s libsqlite3-0 | grep Version | sed 's/Version: //')}
fi
export SQLITE3_VERSION export SQLITE3_VERSION
} }
+32
View File
@@ -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
+32
View File
@@ -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
+1 -1
View File
@@ -4,7 +4,7 @@ describe "Python!!!!!!!!!!!" do
it "🐍" do it "🐍" do
Hatchet::Runner.new('python-getting-started', stack: DEFAULT_STACK).deploy do |app| Hatchet::Runner.new('python-getting-started', stack: DEFAULT_STACK).deploy do |app|
expect(app.output).to match(/Installing pip/) 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 end
end end
+1 -1
View File
@@ -1 +1 @@
apache-airflow==1.10 apache-airflow==1.10.2
+1 -1
View File
@@ -1 +1 @@
python-3.6.7 python-3.6.8
+1 -1
View File
@@ -1 +1 @@
python-3.6.8 python-3.6.9
+1 -1
View File
@@ -1 +1 @@
python-3.6.5 python-3.6.7
+1 -1
View File
@@ -1 +1 @@
python-3.7.1 python-3.7.2
+1 -1
View File
@@ -1 +1 @@
python-3.7.2 python-3.7.3
+1 -1
View File
@@ -1 +1 @@
python-3.7.0 python-3.7.1
+10 -9
View File
@@ -3,7 +3,7 @@
testAirflow() { testAirflow() {
export SLUGIFY_USES_TEXT_UNIDECODE="yes" export SLUGIFY_USES_TEXT_UNIDECODE="yes"
compile "airflow" compile "airflow"
assertCaptured "apache-airflow==1.10" assertCaptured "apache-airflow==1.10.2"
assertCapturedSuccess assertCapturedSuccess
} }
@@ -19,7 +19,7 @@ testPipenvLock() {
testPipenvVersion() { testPipenvVersion() {
compile "pipenv-version" compile "pipenv-version"
assertCaptured "3.6.7" assertCaptured "3.6.8"
assertCapturedSuccess assertCapturedSuccess
} }
@@ -45,7 +45,8 @@ testCollectstatic() {
} }
testGEOS() { testGEOS() {
BUILD_WITH_GEO_LIBRARIES=1 compile "geos" export BUILD_WITH_GEO_LIBRARIES=1
compile "geos"
assertCaptured "geos" assertCaptured "geos"
assertCapturedSuccess assertCapturedSuccess
} }
@@ -57,7 +58,7 @@ testNLTK() {
# be bad to silence in Production. # be bad to silence in Production.
export PYTHONWARNINGS="ignore::RuntimeWarning" export PYTHONWARNINGS="ignore::RuntimeWarning"
compile "nltk" compile "nltk"
assertCaptured "Downloading NLTK packages: city_database stopwords" assertCaptured "[nltk_data] Downloading package city_database" "STD_ERR"
assertCapturedSuccess assertCapturedSuccess
} }
@@ -94,7 +95,7 @@ testPylibmc() {
testPythonDefault() { testPythonDefault() {
compile "pythonDefault" compile "pythonDefault"
assertCaptured "python-3.6.7" assertCaptured "python-3.6.8"
assertCapturedSuccess assertCapturedSuccess
} }
@@ -169,13 +170,13 @@ testPython3_5_fail() {
testPython3_6() { testPython3_6() {
compile "python3_6" compile "python3_6"
assertCaptured "python-3.6.7" assertCaptured "python-3.6.8"
assertCapturedSuccess assertCapturedSuccess
} }
testPython3_6_warn() { testPython3_6_warn() {
compile "python3_6_warn" compile "python3_6_warn"
assertCaptured "python-3.6.5" assertCaptured "python-3.6.7"
assertCaptured "security update!" assertCaptured "security update!"
assertCapturedSuccess assertCapturedSuccess
} }
@@ -191,7 +192,7 @@ testPython3_7() {
if [[ $STACK = "cedar-14" ]]; then if [[ $STACK = "cedar-14" ]]; then
assertCapturedError assertCapturedError
else else
assertCaptured "python-3.7.1" assertCaptured "python-3.7.2"
assertCapturedSuccess assertCapturedSuccess
fi fi
} }
@@ -201,7 +202,7 @@ testPython3_7_warn() {
if [[ $STACK = "cedar-14" ]]; then if [[ $STACK = "cedar-14" ]]; then
assertCapturedError assertCapturedError
else else
assertCaptured "python-3.7.0" assertCaptured "python-3.7.1"
assertCaptured "security update!" assertCaptured "security update!"
assertCapturedSuccess assertCapturedSuccess
fi fi
+3 -2
View File
@@ -83,7 +83,8 @@ assertCapturedNotEquals()
assertCaptured() assertCaptured()
{ {
assertFileContains "$@" "${STD_OUT}" stdroute=${2:-STD_OUT}
assertFileContains "$1" "${!stdroute}"
} }
assertNotCaptured() assertNotCaptured()
@@ -94,7 +95,7 @@ assertNotCaptured()
assertCapturedSuccess() assertCapturedSuccess()
{ {
assertEquals "Captured exit code -" "0" "${RETURN}" 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 if [ $RETURN -ne 0 -a -z "$(cat ${STD_ERR})" ]; then
# Failing exit code but stderr was empty. Display stdout to help debugging. # Failing exit code but stderr was empty. Display stdout to help debugging.