Compare commits

..

1 Commits

Author SHA1 Message Date
kennethreitz 52758c36c6 updated changelog 2017-05-30 11:12:40 -04:00
18 changed files with 45 additions and 196 deletions
-30
View File
@@ -1,35 +1,5 @@
# Python Buildpack Changelog # Python Buildpack Changelog
# 110
Update Default Python to 3.6.1, bugfixes.
- Fixed automatic pip uninstall of dependencies removed from requirements.txt.
# 109
Fix output for collectstatic step.
# 108
Updated setuptools.
# 107
Bugfix for C dependency installation.
# 106
Don't install packages that could mess up packaging.
- The Python buildpack will automatically remove `six`, `pyparsing`, `appdirs`,
`setuptools`, and `distribute` from a `requirements.txt` file now, as these
packages are provided by the Python buildpack.
# 105
Improvements to output messaging.
# 104 # 104
General improvements. General improvements.
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License: MIT License:
Copyright (C) 2017 Heroku, Inc. Copyright (C) 2016 Heroku, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+4 -4
View File
@@ -8,7 +8,7 @@ This is the official [Heroku buildpack](https://devcenter.heroku.com/articles/bu
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**. 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.
Some Python packages with obscure C dependencies are [not compatible](https://devcenter.heroku.com/articles/python-c-deps). Some Python packages with obscure C dependencies (e.g. scipy) are [not compatible](https://devcenter.heroku.com/articles/python-c-deps).
See it in Action See it in Action
---------------- ----------------
@@ -23,7 +23,7 @@ Deploying a Python application couldn't be easier:
$ git push heroku master $ git push heroku master
... ...
-----> Python app detected -----> Python app detected
-----> Installing python-3.6.2 -----> Installing python-2.7.13
$ pip install -r requirements.txt $ pip install -r requirements.txt
Collecting requests (from -r requirements.txt (line 1)) Collecting requests (from -r requirements.txt (line 1))
Downloading requests-2.12.4-py2.py3-none-any.whl (576KB) Downloading requests-2.12.4-py2.py3-none-any.whl (576KB)
@@ -46,11 +46,11 @@ Specify a Python Runtime
Specific versions of the Python runtime can be specified with a `runtime.txt` file: Specific versions of the Python runtime can be specified with a `runtime.txt` file:
$ cat runtime.txt $ cat runtime.txt
python-2.7.13 python-3.6.1
Runtime options include: Runtime options include:
- `python-3.6.2`
- `python-2.7.13` - `python-2.7.13`
- `python-3.6.1`
- `pypy-5.7.1` (unsupported, experimental) - `pypy-5.7.1` (unsupported, experimental)
- `pypy3-5.5.1` (unsupported, experimental) - `pypy3-5.5.1` (unsupported, experimental)
+12 -6
View File
@@ -32,10 +32,11 @@ CACHE_DIR=$2
ENV_DIR=$3 ENV_DIR=$3
# Python defaults # Python defaults
DEFAULT_PYTHON_VERSION="python-3.6.2" DEFAULT_PYTHON_VERSION="python-2.7.13"
DEFAULT_PYTHON_STACK="cedar-14" DEFAULT_PYTHON_STACK="cedar-14"
PYTHON_EXE="/app/.heroku/python/bin/python" PYTHON_EXE="/app/.heroku/python/bin/python"
PIP_VERSION="9.0.1" PIP_VERSION="9.0.1"
SETUPTOOLS_VERSION="32.1.0"
# Common Problem Warnings # Common Problem Warnings
export WARNINGS_LOG=$(mktemp) export WARNINGS_LOG=$(mktemp)
@@ -144,6 +145,11 @@ let start=$(nowms)
source $BIN_DIR/steps/python source $BIN_DIR/steps/python
mtime "python.install.time" "${start}" mtime "python.install.time" "${start}"
# Sanity check for setuptools/distribute.
let start=$(nowms)
source $BIN_DIR/steps/setuptools
mtime "setuptools.install.time" "${start}"
# Pipenv support. # Pipenv support.
source $BIN_DIR/steps/pipenv source $BIN_DIR/steps/pipenv
@@ -170,16 +176,16 @@ sub-env $BIN_DIR/steps/geo-libs
# GDAL support. # GDAL support.
source $BIN_DIR/steps/gdal source $BIN_DIR/steps/gdal
# Uninstall removed dependencies with Pip.
let start=$(nowms)
source $BIN_DIR/steps/pip-uninstall
mtime "pip.uninstall.time" "${start}"
# Install dependencies with Pip (where the magic happens). # Install dependencies with Pip (where the magic happens).
let start=$(nowms) let start=$(nowms)
source $BIN_DIR/steps/pip-install source $BIN_DIR/steps/pip-install
mtime "pip.install.time" "${start}" mtime "pip.install.time" "${start}"
# Uninstall removed dependencies with Pip.
let start=$(nowms)
source $BIN_DIR/steps/pip-uninstall
mtime "pip.uninstall.time" "${start}"
# Support for NLTK corpora. # Support for NLTK corpora.
let start=$(nowms) let start=$(nowms)
sub-env $BIN_DIR/steps/nltk sub-env $BIN_DIR/steps/nltk
+1 -1
View File
@@ -20,7 +20,7 @@ MANAGE_FILE=${MANAGE_FILE:-fakepath}
[ -f .heroku/collectstatic_disabled ] && DISABLE_COLLECTSTATIC=1 [ -f .heroku/collectstatic_disabled ] && DISABLE_COLLECTSTATIC=1
# Ensure that Django is explicitly specified in requirements.txt # Ensure that Django is explicitly specified in requirements.txt
sp-grep -s django && DJANGO_INSTALLED=1 pip-grep -s Django && DJANGO_INSTALLED=1
if [ ! "$DISABLE_COLLECTSTATIC" ] && [ -f "$MANAGE_FILE" ] && [ "$DJANGO_INSTALLED" ]; then if [ ! "$DISABLE_COLLECTSTATIC" ] && [ -f "$MANAGE_FILE" ] && [ "$DJANGO_INSTALLED" ]; then
+1 -1
View File
@@ -18,7 +18,7 @@ PKG_CONFIG_PATH="/app/.heroku/vendor/lib/pkgconfig:$PKG_CONFIG_PATH"
source $BIN_DIR/utils source $BIN_DIR/utils
# If a package using cffi exists within requirements, use vendored libffi. # If a package using cffi exists within requirements, use vendored libffi.
if (pip-grep -s requirements.txt argon2-cffi bcrypt cffi cryptography django[argon2] Django[argon2] django[bcrypt] Django[bcrypt] PyNaCl pyOpenSSL PyOpenSSL requests[security] misaka &> /dev/null) then if (pip-grep -s argon2-cffi bcrypt cffi cryptography PyNaCl pyOpenSSL PyOpenSSL misaka &> /dev/null) then
if [ ! -d ".heroku/vendor/lib/libffi-3.1" ]; then if [ ! -d ".heroku/vendor/lib/libffi-3.1" ]; then
echo "-----> Noticed cffi. Bootstrapping libffi." echo "-----> Noticed cffi. Bootstrapping libffi."
+1 -1
View File
@@ -18,7 +18,7 @@ PKG_CONFIG_PATH="/app/.heroku/vendor/lib/pkgconfig:$PKG_CONFIG_PATH"
source $BIN_DIR/utils source $BIN_DIR/utils
# If GDAL exists within requirements, use vendored gdal. # If GDAL exists within requirements, use vendored gdal.
if (pip-grep -s requirements.txt GDAL gdal pygdal &> /dev/null) then if (pip-grep -s GDAL pygdal &> /dev/null) then
if [ ! -f ".heroku/vendor/bin/gdalserver" ]; then if [ ! -f ".heroku/vendor/bin/gdalserver" ]; then
echo "-----> Noticed GDAL. Bootstrapping gdal." echo "-----> Noticed GDAL. Bootstrapping gdal."
+1 -1
View File
@@ -17,7 +17,7 @@ source $BIN_DIR/utils
# If pylibmc exists within requirements, use vendored libmemcached. # If pylibmc exists within requirements, use vendored libmemcached.
if (pip-grep -s requirements.txt pylibmc &> /dev/null) then if (pip-grep -s pylibmc &> /dev/null) then
if [ ! -d ".heroku/vendor/lib/sasl2" ]; then if [ ! -d ".heroku/vendor/lib/sasl2" ]; then
echo "-----> Noticed pylibmc. Bootstrapping libmemcached." echo "-----> Noticed pylibmc. Bootstrapping libmemcached."
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
# Syntax sugar.
source $BIN_DIR/utils
if (pip-grep -s setuptools distribute &> /dev/null) then
puts-warn 'The package setuptools/distribute is listed in requirements.txt.'
puts-warn 'Please remove to ensure expected behavior. '
fi
-12
View File
@@ -1,12 +0,0 @@
#!/usr/bin/env bash
# Build Path: /app/.heroku/python/
# Build Deps: libraries/sqlite
OUT_PREFIX=$1
echo "Building PyPy..."
SOURCE_TARBALL='https://bitbucket.org/pypy/pypy/downloads/pypy3-v5.8.0-linux64.tar.bz2'
curl -L $SOURCE_TARBALL | tar jx
cp -R pypy3-v5.8.0-linux64/* $OUT_PREFIX
ln $OUT_PREFIX/bin/pypy3 $OUT_PREFIX/bin/python
-18
View File
@@ -1,18 +0,0 @@
#!/usr/bin/env bash
# Build Path: /app/.heroku/python/
# Build Deps: libraries/sqlite
OUT_PREFIX=$1
echo "Building Python..."
SOURCE_TARBALL='https://python.org/ftp/python/3.5.3/Python-3.5.3.tgz'
curl -L $SOURCE_TARBALL | tar xz
mv Python-3.5.3 src
cd src
./configure --prefix=$OUT_PREFIX --with-ensurepip=no
make
make install
# ln $OUT_PREFIX/bin/python3 $OUT_PREFIX/bin/python
-18
View File
@@ -1,18 +0,0 @@
#!/usr/bin/env bash
# Build Path: /app/.heroku/python/
# Build Deps: libraries/sqlite
OUT_PREFIX=$1
echo "Building Python..."
SOURCE_TARBALL='https://python.org/ftp/python/3.6.2/Python-3.6.2.tgz'
curl -L $SOURCE_TARBALL | tar xz
mv Python-3.6.2 src
cd src
./configure --prefix=$OUT_PREFIX --with-ensurepip=no
make
make install
ln $OUT_PREFIX/bin/python3 $OUT_PREFIX/bin/python
+2 -1
View File
@@ -1 +1,2 @@
bob-builder==0.0.13 # TODO: Replace this once the bob-builder changes on master are released:
https://github.com/kennethreitz/bob-builder/archive/54211376a8fb49c67ecbd6798bd45b55f4d125f4.zip
-1
View File
@@ -1 +0,0 @@
python-2.7.13
-1
View File
@@ -1 +0,0 @@
pylibmc
-16
View File
@@ -44,12 +44,6 @@ testPsycopg2() {
assertCapturedSuccess assertCapturedSuccess
} }
testPylibmc() {
compile "pylibmc"
assertCaptured "pylibmc"
assertCapturedSuccess
}
testPython2() { testPython2() {
compile "python2" compile "python2"
assertCaptured "python-2.7.13" assertCaptured "python-2.7.13"
@@ -62,16 +56,6 @@ testPython3() {
assertCapturedSuccess assertCapturedSuccess
} }
testSmartRequirements() {
local cache_dir="$(mktmpdir)"
compile "requirements-standard" "$cache_dir"
assertFile "requests" ".heroku/python/requirements-declared.txt"
assertCapturedSuccess
compile "psycopg2" "$cache_dir"
assertCaptured "Uninstalling requests"
assertFile "psycopg2" ".heroku/python/requirements-declared.txt"
assertCapturedSuccess
}
+11 -46
View File
@@ -2,58 +2,26 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Usage: """Usage:
pip-grep [-s] <reqfile> <package>... pip-grep [-s] <package>...
Options: Options:
-h --help Show this screen. -h --help Show this screen.
""" """
import os
from docopt import docopt from docopt import docopt
from pip.req import parse_requirements from pkg_resources import DistributionNotFound, get_distribution
from pip.index import PackageFinder
from pip._vendor.requests import session
requests = session()
class Requirements(object): def has_any_distribution(names, silent=False):
def __init__(self, reqfile=None): for name in names:
super(Requirements, self).__init__() try:
self.path = reqfile get_distribution(name)
self.requirements = [] except DistributionNotFound:
continue
if reqfile:
self.load(reqfile)
def __repr__(self):
return '<Requirements \'{}\'>'.format(self.path)
def load(self, reqfile):
if not os.path.exists(reqfile):
raise ValueError('The given requirements file does not exist.')
finder = PackageFinder([], [], session=requests)
for requirement in parse_requirements(reqfile, finder=finder, session=requests):
if requirement.req:
if not getattr(requirement.req, 'name', None):
# Prior to pip 8.1.2 the attribute `name` did not exist.
requirement.req.name = requirement.req.project_name
self.requirements.append(requirement.req)
def grep(reqfile, packages, silent=False):
try:
r = Requirements(reqfile)
except ValueError:
if not silent: if not silent:
print('There was a problem loading the given requirement file.') print('Package {name} found!'.format(name=name))
exit(os.EX_NOINPUT)
for req in r.requirements: exit(0)
if req.name in packages:
if not silent:
print('Package {} found!'.format(req.name))
exit(0)
if not silent: if not silent:
print('Not found.') print('Not found.')
@@ -63,10 +31,7 @@ def grep(reqfile, packages, silent=False):
def main(): def main():
args = docopt(__doc__, version='pip-grep') args = docopt(__doc__, version='pip-grep')
has_any_distribution(names=args['<package>'], silent=args['-s'])
kwargs = {'reqfile': args['<reqfile>'], 'packages': args['<package>'], 'silent': args['-s']}
grep(**kwargs)
if __name__ == '__main__': if __name__ == '__main__':
-38
View File
@@ -1,38 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Usage:
sp-grep [-s] <package>...
Options:
-h --help Show this screen.
"""
from docopt import docopt
from pkg_resources import DistributionNotFound, get_distribution
def has_any_distribution(names, silent=False):
for name in names:
try:
get_distribution(name)
except DistributionNotFound:
continue
if not silent:
print('Package {name} found!'.format(name=name))
exit(0)
if not silent:
print('Not found.')
exit(1)
def main():
args = docopt(__doc__, version='sp-grep')
has_any_distribution(names=args['<package>'], silent=args['-s'])
if __name__ == '__main__':
main()