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 | |
|---|---|---|---|
| a7c20eea42 | |||
| 0a4cc2c476 | |||
| cbb718bb8b | |||
| db95cdd3f3 | |||
| 04f3ddbc86 | |||
| f06f5676e8 | |||
| c8c8995d70 | |||
| 4ee3baaded | |||
| ff94908505 | |||
| 5496c02f9f | |||
| 8d6d14b671 | |||
| 98dc586a99 |
+32
-1
@@ -1,9 +1,40 @@
|
|||||||
# 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
|
||||||
|
|
||||||
unreleased
|
General improvements.
|
||||||
|
|
||||||
|
- Fix for Heroku CI.
|
||||||
- Use `pkg_resources` to check if a distribution is installed instead of
|
- Use `pkg_resources` to check if a distribution is installed instead of
|
||||||
parsing `requirements.txt`. ([#395][395])
|
parsing `requirements.txt`. ([#395][395])
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
MIT License:
|
MIT License:
|
||||||
|
|
||||||
Copyright (C) 2016 Heroku, Inc.
|
Copyright (C) 2017 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:
|
||||||
|
|
||||||
|
|||||||
+6
-12
@@ -32,11 +32,10 @@ CACHE_DIR=$2
|
|||||||
ENV_DIR=$3
|
ENV_DIR=$3
|
||||||
|
|
||||||
# Python defaults
|
# Python defaults
|
||||||
DEFAULT_PYTHON_VERSION="python-2.7.13"
|
DEFAULT_PYTHON_VERSION="python-3.6.1"
|
||||||
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)
|
||||||
@@ -145,11 +144,6 @@ 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
|
||||||
|
|
||||||
@@ -176,16 +170,16 @@ sub-env $BIN_DIR/steps/geo-libs
|
|||||||
# GDAL support.
|
# GDAL support.
|
||||||
source $BIN_DIR/steps/gdal
|
source $BIN_DIR/steps/gdal
|
||||||
|
|
||||||
# Install dependencies with Pip (where the magic happens).
|
|
||||||
let start=$(nowms)
|
|
||||||
source $BIN_DIR/steps/pip-install
|
|
||||||
mtime "pip.install.time" "${start}"
|
|
||||||
|
|
||||||
# Uninstall removed dependencies with Pip.
|
# Uninstall removed dependencies with Pip.
|
||||||
let start=$(nowms)
|
let start=$(nowms)
|
||||||
source $BIN_DIR/steps/pip-uninstall
|
source $BIN_DIR/steps/pip-uninstall
|
||||||
mtime "pip.uninstall.time" "${start}"
|
mtime "pip.uninstall.time" "${start}"
|
||||||
|
|
||||||
|
# Install dependencies with Pip (where the magic happens).
|
||||||
|
let start=$(nowms)
|
||||||
|
source $BIN_DIR/steps/pip-install
|
||||||
|
mtime "pip.install.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
|
||||||
|
|||||||
@@ -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
|
||||||
pip-grep -s Django && DJANGO_INSTALLED=1
|
sp-grep -s django && DJANGO_INSTALLED=1
|
||||||
|
|
||||||
|
|
||||||
if [ ! "$DISABLE_COLLECTSTATIC" ] && [ -f "$MANAGE_FILE" ] && [ "$DJANGO_INSTALLED" ]; then
|
if [ ! "$DISABLE_COLLECTSTATIC" ] && [ -f "$MANAGE_FILE" ] && [ "$DJANGO_INSTALLED" ]; then
|
||||||
|
|||||||
@@ -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 argon2-cffi bcrypt cffi cryptography PyNaCl pyOpenSSL PyOpenSSL misaka &> /dev/null) then
|
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 [ ! -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
@@ -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 GDAL pygdal &> /dev/null) then
|
if (pip-grep -s requirements.txt GDAL 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
@@ -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 pylibmc &> /dev/null) then
|
if (pip-grep -s requirements.txt 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."
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
#!/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
|
|
||||||
Executable
+12
@@ -0,0 +1,12 @@
|
|||||||
|
#!/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
|
||||||
Executable
+18
@@ -0,0 +1,18 @@
|
|||||||
|
#!/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
|
||||||
|
|
||||||
+1
-2
@@ -1,2 +1 @@
|
|||||||
# TODO: Replace this once the bob-builder changes on master are released:
|
bob-builder==0.0.13
|
||||||
https://github.com/kennethreitz/bob-builder/archive/54211376a8fb49c67ecbd6798bd45b55f4d125f4.zip
|
|
||||||
|
|||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
python-2.7.13
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
pylibmc
|
||||||
@@ -44,6 +44,12 @@ 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"
|
||||||
@@ -56,6 +62,16 @@ 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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Vendored
+46
-11
@@ -2,26 +2,58 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""Usage:
|
"""Usage:
|
||||||
pip-grep [-s] <package>...
|
pip-grep [-s] <reqfile> <package>...
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-h --help Show this screen.
|
-h --help Show this screen.
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
from docopt import docopt
|
from docopt import docopt
|
||||||
from pkg_resources import DistributionNotFound, get_distribution
|
from pip.req import parse_requirements
|
||||||
|
from pip.index import PackageFinder
|
||||||
|
from pip._vendor.requests import session
|
||||||
|
|
||||||
|
requests = session()
|
||||||
|
|
||||||
|
|
||||||
def has_any_distribution(names, silent=False):
|
class Requirements(object):
|
||||||
for name in names:
|
def __init__(self, reqfile=None):
|
||||||
try:
|
super(Requirements, self).__init__()
|
||||||
get_distribution(name)
|
self.path = reqfile
|
||||||
except DistributionNotFound:
|
self.requirements = []
|
||||||
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('Package {name} found!'.format(name=name))
|
print('There was a problem loading the given requirement file.')
|
||||||
|
exit(os.EX_NOINPUT)
|
||||||
|
|
||||||
exit(0)
|
for req in r.requirements:
|
||||||
|
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.')
|
||||||
@@ -31,7 +63,10 @@ def has_any_distribution(names, 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
@@ -0,0 +1,38 @@
|
|||||||
|
#!/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()
|
||||||
Reference in New Issue
Block a user