mirror of
https://github.com/kennethreitz/heroku-buildpack-python.git
synced 2026-06-05 23:10:16 +00:00
Compare commits
96 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 65648fb7a8 | |||
| 45b0d18532 | |||
| 8f258ae0b8 | |||
| b80f7a953f | |||
| f27a84e015 | |||
| 5794bacbbf | |||
| e29b60dcfd | |||
| 7c95b156ce | |||
| e05346e8c1 | |||
| 9deea01360 | |||
| c19f0f83ee | |||
| 8b88d655c4 | |||
| 0e8c0077ff | |||
| cfda557b31 | |||
| 44c2b75b8d | |||
| c3849fb6d3 | |||
| 5608ed9f3c | |||
| e9108858fc | |||
| c85f5d015c | |||
| 321543d4ae | |||
| 8bd209de13 | |||
| 58e9c84347 | |||
| dcfff15151 | |||
| 9426dc8668 | |||
| cdbeb6419e | |||
| 858113cf76 | |||
| a547da0b52 | |||
| df52fd46e5 | |||
| 2e37a96984 | |||
| 12c3b8cb1d | |||
| 0fadebf7d8 | |||
| 33ccaa9e45 | |||
| 6b5ec50ab9 | |||
| 63810f29d3 | |||
| 0de749a6a2 | |||
| 2df1131d3c | |||
| af0795264b | |||
| 327daa5f32 | |||
| 09b7e44841 | |||
| e26a0f04d9 | |||
| c92f379f78 | |||
| 893bdec066 | |||
| 607dcfda07 | |||
| 26a0b9678f | |||
| e58e5d2b74 | |||
| 6faa5a4efc | |||
| 2881d65e4e | |||
| 1696e7cee6 | |||
| 35b89386ed | |||
| 3634eb1dbf | |||
| 66f5a66740 | |||
| 6e2a504fc1 | |||
| 124aff5ea6 | |||
| c44ab4cd03 | |||
| 677dfeec11 | |||
| c77a1877d3 | |||
| 1c51f5d84e | |||
| 6922a82536 | |||
| 9cc5bf1a85 | |||
| 012cb8a4df | |||
| fab60ae6ab | |||
| cd52da6155 | |||
| acd9347930 | |||
| d7e2f0fb08 | |||
| a3ed9c7155 | |||
| 8db1f07fba | |||
| 17081d0328 | |||
| d1ab87748b | |||
| 6844d1252d | |||
| 1346c29089 | |||
| 3bc1b5e697 | |||
| 9a6fa0478a | |||
| 573ded6d41 | |||
| b4ec35433a | |||
| cf1148f0a8 | |||
| a0649b1e50 | |||
| 2f2fd24421 | |||
| f754ae16bb | |||
| cef1be80a5 | |||
| c0571d86bf | |||
| d82eddca03 | |||
| 119e8145c3 | |||
| 99dae0f671 | |||
| f54dfff8a9 | |||
| c9760ae0ee | |||
| 98ff1670b3 | |||
| bdd466f838 | |||
| 324ebc9223 | |||
| 42ec6d8701 | |||
| 19513067bb | |||
| 753c912ecc | |||
| 4e8c469ec7 | |||
| 852723f867 | |||
| 94514a8179 | |||
| 7d57744c0a | |||
| a41ddf6bd1 |
@@ -1,2 +1,3 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
site
|
site
|
||||||
|
.DS_Store
|
||||||
|
|||||||
+9
-2
@@ -1,2 +1,9 @@
|
|||||||
sudo: false
|
language: bash
|
||||||
script: exit 0
|
sudo: required
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
|
# install: docker pull heroku/cedar:14
|
||||||
|
script: ./tests.sh
|
||||||
|
env:
|
||||||
|
- STACK=heroku-16
|
||||||
|
- STACK=cedar-14
|
||||||
@@ -1,5 +1,52 @@
|
|||||||
# Python Buildpack Changelog
|
# Python Buildpack Changelog
|
||||||
|
|
||||||
|
## 100
|
||||||
|
|
||||||
|
Preliminary pipenv support.
|
||||||
|
|
||||||
|
## 99
|
||||||
|
|
||||||
|
Cleanup.
|
||||||
|
|
||||||
|
## 98
|
||||||
|
|
||||||
|
Official NLTK support and other improvements.
|
||||||
|
|
||||||
|
- Support for `nltk.txt` file for declaring corpora to be downloaded.
|
||||||
|
- Leading zeros for auto-set WEB_CONCURRENCY.
|
||||||
|
|
||||||
|
## 97
|
||||||
|
|
||||||
|
Improved egg-link functionality.
|
||||||
|
|
||||||
|
## 96
|
||||||
|
|
||||||
|
Bugfix.
|
||||||
|
|
||||||
|
## 95
|
||||||
|
|
||||||
|
Improved output support.
|
||||||
|
|
||||||
|
## v94
|
||||||
|
|
||||||
|
Improved support for PyPy.
|
||||||
|
|
||||||
|
## v93
|
||||||
|
|
||||||
|
Improved support for PyPy.
|
||||||
|
|
||||||
|
## v92
|
||||||
|
|
||||||
|
Improved cache functionality and fix egg-links regression.
|
||||||
|
|
||||||
|
## v91
|
||||||
|
|
||||||
|
Bugfix, rolled back to v88.
|
||||||
|
|
||||||
|
## v90
|
||||||
|
|
||||||
|
Bugfix.
|
||||||
|
|
||||||
## v89
|
## v89
|
||||||
|
|
||||||
Improved cache functionality and fix egg-links regression.
|
Improved cache functionality and fix egg-links regression.
|
||||||
|
|||||||
@@ -1,8 +1,17 @@
|
|||||||
# These targets are not files
|
# These targets are not files
|
||||||
.PHONY: tests
|
.PHONY: tests
|
||||||
|
|
||||||
tests:
|
test: test-cedar-14
|
||||||
./bin/test
|
|
||||||
|
test-cedar-14:
|
||||||
|
@echo "Running tests in docker (cedar-14)..."
|
||||||
|
@docker run -v $(shell pwd):/buildpack:ro --rm -it -e "STACK=cedar-14" heroku/cedar:14 bash -c 'cp -r /buildpack /buildpack_test; cd /buildpack_test/; test/run;'
|
||||||
|
@echo ""
|
||||||
|
|
||||||
|
test-heroku-16:
|
||||||
|
@echo "Running tests in docker (heroku-16)..."
|
||||||
|
@docker run -v $(shell pwd):/buildpack:ro --rm -it -e "STACK=heroku-16" heroku/heroku:16-build bash -c 'cp -r /buildpack /buildpack_test; cd /buildpack_test/; test/run;'
|
||||||
|
@echo ""
|
||||||
|
|
||||||
tools:
|
tools:
|
||||||
git clone https://github.com/kennethreitz/pip-pop.git
|
git clone https://github.com/kennethreitz/pip-pop.git
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
# Heroku Buildpack: Python
|
# Heroku Buildpack: Python
|
||||||
|
|
||||||
|
[](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 [pip](https://pip.pypa.io/) and other excellent software.
|
This is the official [Heroku buildpack](https://devcenter.heroku.com/articles/buildpacks) for Python apps, powered by [pip](https://pip.pypa.io/) and other excellent software.
|
||||||
|
|
||||||
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.
|
||||||
@@ -21,12 +23,12 @@ Deploying a Python application couldn't be easier:
|
|||||||
$ git push heroku master
|
$ git push heroku master
|
||||||
...
|
...
|
||||||
-----> Python app detected
|
-----> Python app detected
|
||||||
-----> Installing python-2.7.12
|
-----> 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.10.0-py2.py3-none-any.whl (501kB)
|
Downloading requests-2.12.4-py2.py3-none-any.whl (576KB)
|
||||||
Installing collected packages: requests
|
Installing collected packages: requests
|
||||||
Successfully installed requests-2.10.0
|
Successfully installed requests-2.12.4
|
||||||
|
|
||||||
-----> Discovering process types
|
-----> Discovering process types
|
||||||
Procfile declares types -> (none)
|
Procfile declares types -> (none)
|
||||||
@@ -44,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-3.5.2
|
python-3.6.0
|
||||||
|
|
||||||
Runtime options include:
|
Runtime options include:
|
||||||
|
|
||||||
- `python-2.7.12`
|
- `python-2.7.13`
|
||||||
- `python-3.5.2`
|
- `python-3.6.0`
|
||||||
- `pypy-5.3.1` (unsupported, experimental)
|
- `pypy-5.6.0` (unsupported, experimental)
|
||||||
- `pypy3-2.4.0` (unsupported, experimental)
|
- `pypy3-5.5.0` (unsupported, experimental)
|
||||||
|
|||||||
+45
-42
@@ -27,9 +27,7 @@ BUILD_DIR=$1
|
|||||||
CACHE_DIR=$2
|
CACHE_DIR=$2
|
||||||
ENV_DIR=$3
|
ENV_DIR=$3
|
||||||
|
|
||||||
# Export path environment variables for sub-scripts.
|
# Python defaults
|
||||||
export BIN_DIR ROOT_DIR BUILD_DIR CACHE_DIR ENV_DIR
|
|
||||||
|
|
||||||
DEFAULT_PYTHON_VERSION="python-2.7.13"
|
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"
|
||||||
@@ -41,7 +39,7 @@ export WARNINGS_LOG=$(mktemp)
|
|||||||
export RECOMMENDED_PYTHON_VERSION=$DEFAULT_PYTHON_VERSION
|
export RECOMMENDED_PYTHON_VERSION=$DEFAULT_PYTHON_VERSION
|
||||||
|
|
||||||
# Setup bpwatch
|
# Setup bpwatch
|
||||||
export PATH=$PATH:$ROOT_DIR/vendor/bpwatch
|
export PATH=$PATH:$ROOT_DIR/vendor/:$ROOT_DIR/vendor/bpwatch
|
||||||
LOGPLEX_KEY="t.b90d9d29-5388-4908-9737-b4576af1d4ce"
|
LOGPLEX_KEY="t.b90d9d29-5388-4908-9737-b4576af1d4ce"
|
||||||
export BPWATCH_STORE_PATH=$CACHE_DIR/bpwatch.json
|
export BPWATCH_STORE_PATH=$CACHE_DIR/bpwatch.json
|
||||||
BUILDPACK_VERSION=v28
|
BUILDPACK_VERSION=v28
|
||||||
@@ -106,12 +104,6 @@ bpwatch start pre_compile
|
|||||||
source $BIN_DIR/steps/hooks/pre_compile
|
source $BIN_DIR/steps/hooks/pre_compile
|
||||||
bpwatch stop pre_compile
|
bpwatch stop pre_compile
|
||||||
|
|
||||||
# If no requirements.txt file given, assume `setup.py develop` is intended.
|
|
||||||
if [ ! -f requirements.txt ]; then
|
|
||||||
echo "-e ." > requirements.txt
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# Sticky runtimes.
|
# Sticky runtimes.
|
||||||
if [ -f $CACHE_DIR/.heroku/python-version ]; then
|
if [ -f $CACHE_DIR/.heroku/python-version ]; then
|
||||||
DEFAULT_PYTHON_VERSION=$(cat $CACHE_DIR/.heroku/python-version)
|
DEFAULT_PYTHON_VERSION=$(cat $CACHE_DIR/.heroku/python-version)
|
||||||
@@ -124,6 +116,9 @@ else
|
|||||||
CACHED_PYTHON_STACK=$STACK
|
CACHED_PYTHON_STACK=$STACK
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Pipenv Python version support.
|
||||||
|
source $BIN_DIR/steps/pipenv-python-version
|
||||||
|
|
||||||
# If no runtime given, assume default version.
|
# If no runtime given, assume default version.
|
||||||
if [ ! -f runtime.txt ]; then
|
if [ ! -f runtime.txt ]; then
|
||||||
echo $DEFAULT_PYTHON_VERSION > runtime.txt
|
echo $DEFAULT_PYTHON_VERSION > runtime.txt
|
||||||
@@ -134,33 +129,27 @@ mkdir -p $CACHE_DIR
|
|||||||
|
|
||||||
# Restore old artifacts from the cache.
|
# Restore old artifacts from the cache.
|
||||||
bpwatch start restore_cache
|
bpwatch start restore_cache
|
||||||
mkdir -p .heroku
|
mkdir -p .heroku
|
||||||
|
|
||||||
cp -R $CACHE_DIR/.heroku/python .heroku/ &> /dev/null || true
|
|
||||||
cp -R $CACHE_DIR/.heroku/python-stack .heroku/ &> /dev/null || true
|
|
||||||
cp -R $CACHE_DIR/.heroku/python-version .heroku/ &> /dev/null || true
|
|
||||||
cp -R $CACHE_DIR/.heroku/vendor .heroku/ &> /dev/null || true
|
|
||||||
cp -R $CACHE_DIR/.heroku/venv .heroku/ &> /dev/null || true
|
|
||||||
|
|
||||||
if [[ -d $CACHE_DIR/.heroku/src ]]; then
|
|
||||||
cp -R $CACHE_DIR/.heroku/src .heroku/ &> /dev/null || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
cp -R $CACHE_DIR/.heroku/python .heroku/ &> /dev/null || true
|
||||||
|
cp -R $CACHE_DIR/.heroku/python-stack .heroku/ &> /dev/null || true
|
||||||
|
cp -R $CACHE_DIR/.heroku/python-version .heroku/ &> /dev/null || true
|
||||||
|
cp -R $CACHE_DIR/.heroku/vendor .heroku/ &> /dev/null || true
|
||||||
|
if [[ -d $CACHE_DIR/.heroku/src ]]; then
|
||||||
|
cp -R $CACHE_DIR/.heroku/src .heroku/ &> /dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
bpwatch stop restore_cache
|
bpwatch stop restore_cache
|
||||||
|
|
||||||
mkdir -p $(dirname $PROFILE_PATH)
|
mkdir -p $(dirname $PROFILE_PATH)
|
||||||
|
|
||||||
# Make the directory for -e pip installations.
|
|
||||||
mkdir -p /app/.heroku/src
|
mkdir -p /app/.heroku/src
|
||||||
|
|
||||||
if [[ $BUILD_DIR != '/app' ]]; then
|
if [[ $BUILD_DIR != '/app' ]]; then
|
||||||
# python expects to reside in /app, so set up symlinks
|
# python expects to reside in /app, so set up symlinks
|
||||||
# we will not remove these later so subsequent buildpacks can still invoke it
|
# we will not remove these later so subsequent buildpacks can still invoke it
|
||||||
ln -s $BUILD_DIR/.heroku/python /app/.heroku/python
|
ln -nsf $BUILD_DIR/.heroku/python /app/.heroku/python
|
||||||
ln -s $BUILD_DIR/.heroku/vendor /app/.heroku/vendor
|
ln -nsf $BUILD_DIR/.heroku/vendor /app/.heroku/vendor
|
||||||
ln -s $BUILD_DIR/.heroku/venv /app/.heroku/venv
|
# Note: .heroku/src is copied in later.
|
||||||
# NOTE: /app/.heroku/src also exists, but is copied manually later.
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Install Python.
|
# Install Python.
|
||||||
@@ -169,8 +158,16 @@ source $BIN_DIR/steps/python
|
|||||||
# Sanity check for setuptools/distribute.
|
# Sanity check for setuptools/distribute.
|
||||||
source $BIN_DIR/steps/setuptools
|
source $BIN_DIR/steps/setuptools
|
||||||
|
|
||||||
# Uninstall removed dependencies with Pip.
|
# Pipenv support.
|
||||||
source $BIN_DIR/steps/pip-uninstall
|
source $BIN_DIR/steps/pipenv
|
||||||
|
|
||||||
|
# If no requirements.txt file given, assume `setup.py develop` is intended.
|
||||||
|
if [ ! -f requirements.txt ] && [ ! -f Pipfile ]; then
|
||||||
|
echo "-e ." > requirements.txt
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fix egg-links.
|
||||||
|
source $BIN_DIR/steps/eggpath-fix
|
||||||
|
|
||||||
# Mercurial support.
|
# Mercurial support.
|
||||||
source $BIN_DIR/steps/mercurial
|
source $BIN_DIR/steps/mercurial
|
||||||
@@ -187,13 +184,22 @@ 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.
|
# Install dependencies with Pip (where the magic happens).
|
||||||
source $BIN_DIR/steps/pip-install
|
source $BIN_DIR/steps/pip-install
|
||||||
|
|
||||||
|
# Uninstall removed dependencies with Pip.
|
||||||
|
source $BIN_DIR/steps/pip-uninstall
|
||||||
|
|
||||||
|
# Support for NLTK corpora.
|
||||||
|
sub-env $BIN_DIR/steps/nltk
|
||||||
|
|
||||||
|
# Support for pip install -e.
|
||||||
|
rm -fr $BUILD_DIR/.heroku/src
|
||||||
|
deep-cp /app/.heroku/src $BUILD_DIR/.heroku/src
|
||||||
|
|
||||||
# Django collectstatic support.
|
# Django collectstatic support.
|
||||||
sub-env $BIN_DIR/steps/collectstatic
|
sub-env $BIN_DIR/steps/collectstatic
|
||||||
|
|
||||||
|
|
||||||
# Create .profile script for application runtime environment variables.
|
# Create .profile script for application runtime environment variables.
|
||||||
set-env PATH '$HOME/.heroku/python/bin:$PATH'
|
set-env PATH '$HOME/.heroku/python/bin:$PATH'
|
||||||
set-env PYTHONUNBUFFERED true
|
set-env PYTHONUNBUFFERED true
|
||||||
@@ -207,17 +213,14 @@ set-default-env PYTHONPATH /app/
|
|||||||
# Install sane-default script for $WEB_CONCURRENCY and $FORWARDED_ALLOW_IPS.
|
# Install sane-default script for $WEB_CONCURRENCY and $FORWARDED_ALLOW_IPS.
|
||||||
cp $ROOT_DIR/vendor/python.gunicorn.sh $GUNICORN_PROFILE_PATH
|
cp $ROOT_DIR/vendor/python.gunicorn.sh $GUNICORN_PROFILE_PATH
|
||||||
|
|
||||||
# Symlink the directory for -e pip installations
|
|
||||||
if [[ $BUILD_DIR != '/app' ]]; then
|
|
||||||
mv /app/.heroku/src $BUILD_DIR/.heroku
|
|
||||||
ln -s /app/.heroku/src $BUILD_DIR/.heroku/src
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Experimental post_compile hook.
|
# Experimental post_compile hook.
|
||||||
bpwatch start post_compile
|
bpwatch start post_compile
|
||||||
source $BIN_DIR/steps/hooks/post_compile
|
source $BIN_DIR/steps/hooks/post_compile
|
||||||
bpwatch stop post_compile
|
bpwatch stop post_compile
|
||||||
|
|
||||||
|
# Fix egg-links, again.
|
||||||
|
source $BIN_DIR/steps/eggpath-fix2
|
||||||
|
|
||||||
# Store new artifacts in cache.
|
# Store new artifacts in cache.
|
||||||
bpwatch start dump_cache
|
bpwatch start dump_cache
|
||||||
|
|
||||||
@@ -225,7 +228,6 @@ bpwatch start dump_cache
|
|||||||
rm -rf $CACHE_DIR/.heroku/python-version
|
rm -rf $CACHE_DIR/.heroku/python-version
|
||||||
rm -rf $CACHE_DIR/.heroku/python-stack
|
rm -rf $CACHE_DIR/.heroku/python-stack
|
||||||
rm -rf $CACHE_DIR/.heroku/vendor
|
rm -rf $CACHE_DIR/.heroku/vendor
|
||||||
rm -rf $CACHE_DIR/.heroku/venv
|
|
||||||
rm -rf $CACHE_DIR/.heroku/src
|
rm -rf $CACHE_DIR/.heroku/src
|
||||||
|
|
||||||
mkdir -p $CACHE_DIR/.heroku
|
mkdir -p $CACHE_DIR/.heroku
|
||||||
@@ -233,8 +235,9 @@ bpwatch start dump_cache
|
|||||||
cp -R .heroku/python-version $CACHE_DIR/.heroku/
|
cp -R .heroku/python-version $CACHE_DIR/.heroku/
|
||||||
cp -R .heroku/python-stack $CACHE_DIR/.heroku/ &> /dev/null || true
|
cp -R .heroku/python-stack $CACHE_DIR/.heroku/ &> /dev/null || true
|
||||||
cp -R .heroku/vendor $CACHE_DIR/.heroku/ &> /dev/null || true
|
cp -R .heroku/vendor $CACHE_DIR/.heroku/ &> /dev/null || true
|
||||||
cp -R .heroku/venv $CACHE_DIR/.heroku/ &> /dev/null || true
|
if [[ -d .heroku/src ]]; then
|
||||||
cp -R .heroku/src $CACHE_DIR/.heroku/ &> /dev/null || true
|
cp -R .heroku/src $CACHE_DIR/.heroku/ &> /dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
bpwatch stop dump_cache
|
bpwatch stop dump_cache
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
BUILD_DIR=$1
|
BUILD_DIR=$1
|
||||||
|
|
||||||
# Exit early if app is clearly not Python.
|
# Exit early if app is clearly not Python.
|
||||||
if [ ! -f $BUILD_DIR/requirements.txt ] && [ ! -f $BUILD_DIR/setup.py ]; then
|
if [ ! -f $BUILD_DIR/requirements.txt ] && [ ! -f $BUILD_DIR/setup.py ] && [ ! -f $BUILD_DIR/Pipfile ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
set +e
|
||||||
|
# delete any existing egg links, to uninstall exisisting installations.
|
||||||
|
find .heroku/python/lib/python*/site-packages/ -name "*.egg-link" -delete 2> /dev/null
|
||||||
|
find .heroku/python/lib/python*/site-packages/ -name "*.pth" -print0 2> /dev/null | xargs -r -0 -n 1 sed -i -e "s#/app/#/$(pwd)/#" &> /dev/null
|
||||||
|
set -e
|
||||||
|
|
||||||
|
set +e
|
||||||
|
# Support for the above, for PyPy.
|
||||||
|
find .heroku/python/lib-python/*/site-packages/ -name "*.egg-link" -print0 2> /dev/null | xargs -r -0 -n 1 sed -i -e "s#/app/#$(pwd)/#" &> /dev/null
|
||||||
|
find .heroku/python/lib-python/*/site-packages/ -name "*.pth" -print0 2> /dev/null | xargs -r -0 -n 1 sed -i -e "s#/app/#/$(pwd)/#" &> /dev/null
|
||||||
|
set -e
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
set +e
|
||||||
|
# rewrite build dir in egg links to /app so things are found at runtime
|
||||||
|
find .heroku/python/lib/python*/site-packages/ -name "*.pth" -print0 2> /dev/null | xargs -r -0 -n 1 sed -i -e "s#$(pwd)#/app#" &> /dev/null
|
||||||
|
set -e
|
||||||
|
|
||||||
|
set +e
|
||||||
|
# Support for PyPy
|
||||||
|
find .heroku/python/lib-python/*/site-packages/ -name "*.pth" -print0 2> /dev/null | xargs -r -0 -n 1 sed -i -e "s#$(pwd)#/app#" &> /dev/null
|
||||||
|
set -e
|
||||||
Executable
+33
@@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# This script serves as the NLTK build step of the
|
||||||
|
# [**Python Buildpack**](https://github.com/heroku/heroku-buildpack-python)
|
||||||
|
# compiler.
|
||||||
|
#
|
||||||
|
# A [buildpack](https://devcenter.heroku.com/articles/buildpacks) is an
|
||||||
|
# adapter between a Python application and Heroku's runtime.
|
||||||
|
#
|
||||||
|
# This script is invoked by [`bin/compile`](/).
|
||||||
|
|
||||||
|
# Syntax sugar.
|
||||||
|
source $BIN_DIR/utils
|
||||||
|
|
||||||
|
bpwatch start nltk_download
|
||||||
|
|
||||||
|
# Check that nltk was installed by pip, otherwise obviously not needed
|
||||||
|
python -m nltk.downloader -h >/dev/null 2>&1
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
puts-step "Downloading NLTK corpora..."
|
||||||
|
nltk_packages_definition="$BUILD_DIR/nltk.txt"
|
||||||
|
if [ -f "$nltk_packages_definition" ]; then
|
||||||
|
nltk_packages=$(tr "\n" " " < "$nltk_packages_definition")
|
||||||
|
puts-step "Downloading NLTK packages: $nltk_packages"
|
||||||
|
python -m nltk.downloader -d $BUILD_DIR/.heroku/python/nltk_data $nltk_packages | indent
|
||||||
|
set-env NLTK_DATA "/app/.heroku/python/nltk_data"
|
||||||
|
else
|
||||||
|
puts-warn "nltk.txt not found, not downloading any corpora"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
bpwatch stop nltk_download
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Install dependencies with Pip.
|
# Install dependencies with Pip.
|
||||||
puts-cmd "pip install -r requirements.txt"
|
puts-step "Installing requirements with pip"
|
||||||
|
|
||||||
[ ! "$FRESH_PYTHON" ] && bpwatch start pip_install
|
[ ! "$FRESH_PYTHON" ] && bpwatch start pip_install
|
||||||
[ "$FRESH_PYTHON" ] && bpwatch start pip_install_first
|
[ "$FRESH_PYTHON" ] && bpwatch start pip_install_first
|
||||||
@@ -20,11 +20,6 @@ fi
|
|||||||
cp requirements.txt .heroku/python/requirements-declared.txt
|
cp requirements.txt .heroku/python/requirements-declared.txt
|
||||||
/app/.heroku/python/bin/pip freeze --disable-pip-version-check > .heroku/python/requirements-installed.txt
|
/app/.heroku/python/bin/pip freeze --disable-pip-version-check > .heroku/python/requirements-installed.txt
|
||||||
|
|
||||||
# Replace egg-links with new paths for /app.
|
|
||||||
# find .heroku/python/lib/python*/site-packages/ -name "*.egg-link" -print0 | xargs -0 cat
|
|
||||||
find .heroku/python/lib/python*/site-packages/ -name "*.egg-link" -print0 | xargs -0 -n 1 sed -i -e "s#$(pwd)/#./app/#"
|
|
||||||
find .heroku/python/lib/python*/site-packages/ -name "easy-install.pth" -print0 | xargs -0 -n 1 sed -i -e "s#$(pwd)/#/app/#"
|
|
||||||
|
|
||||||
[ ! "$FRESH_PYTHON" ] && bpwatch stop pip_install
|
[ ! "$FRESH_PYTHON" ] && bpwatch stop pip_install
|
||||||
[ "$FRESH_PYTHON" ] && bpwatch stop pip_install_first
|
[ "$FRESH_PYTHON" ] && bpwatch stop pip_install_first
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# Pipenv support (Generate requriements.txt with pipenv).
|
||||||
|
if [[ -f Pipfile ]]; then
|
||||||
|
if [[ ! -f requirements.txt ]]; then
|
||||||
|
puts-step "Generating 'requirements.txt' with pipenv"
|
||||||
|
|
||||||
|
/app/.heroku/python/bin/pip install pipenv --upgrade &> /dev/null
|
||||||
|
|
||||||
|
/app/.heroku/python/bin/pipenv lock --requirements --no-hashes > $BUILD_DIR/requirements.txt 2> /dev/null
|
||||||
|
fi
|
||||||
|
fi
|
||||||
Executable
+23
@@ -0,0 +1,23 @@
|
|||||||
|
# Detect Python-version with Pipenv.
|
||||||
|
|
||||||
|
if [[ -f $BUILD_DIR/Pipfile.lock ]]; then
|
||||||
|
|
||||||
|
if [[ ! -f $BUILD_DIR/runtime.txt ]]; then
|
||||||
|
if [[ ! -f $BUILD_DIR/Pipfile.lock ]]; then
|
||||||
|
puts-warn "No 'pipfile.lock' found! We recommend you commit this into your repository."
|
||||||
|
fi
|
||||||
|
if [[ -f $BUILD_DIR/Pipfile.lock ]]; then
|
||||||
|
set +e
|
||||||
|
PYTHON=$(cat $BUILD_DIR/Pipfile.lock | jq '._meta.requires.python_version' -r)
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$PYTHON" = 2.7 ]; then
|
||||||
|
echo "python-2.7.13" > $BUILD_DIR/runtime.txt
|
||||||
|
fi
|
||||||
|
if [ "$PYTHON" = 3.6 ]; then
|
||||||
|
echo "python-3.6.0" > $BUILD_DIR/runtime.txt
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
+7
-15
@@ -1,4 +1,5 @@
|
|||||||
set +e
|
set +e
|
||||||
|
runtime-fixer runtime.txt
|
||||||
PYTHON_VERSION=$(cat runtime.txt)
|
PYTHON_VERSION=$(cat runtime.txt)
|
||||||
|
|
||||||
# Install Python.
|
# Install Python.
|
||||||
@@ -54,23 +55,14 @@ if [ "$FRESH_PYTHON" ] || [[ ! $(pip --version) == *$PIP_VERSION* ]]; then
|
|||||||
TMPTARDIR=$(mktemp -d)
|
TMPTARDIR=$(mktemp -d)
|
||||||
trap "rm -rf $TMPTARDIR" RETURN
|
trap "rm -rf $TMPTARDIR" RETURN
|
||||||
|
|
||||||
bpwatch start install_setuptools
|
puts-step "Installing pip"
|
||||||
# Prepare it for the real world
|
|
||||||
# puts-step "Installing Setuptools ($SETUPTOOLS_VERSION)"
|
|
||||||
tar zxf $ROOT_DIR/vendor/setuptools-$SETUPTOOLS_VERSION.tar.gz -C $TMPTARDIR
|
|
||||||
cd $TMPTARDIR/setuptools-$SETUPTOOLS_VERSION/
|
|
||||||
python setup.py install &> /dev/null
|
|
||||||
cd $WORKING_DIR
|
|
||||||
bpwatch stop install_setuptoools
|
|
||||||
|
|
||||||
bpwatch start install_pip
|
# Remove old installations.
|
||||||
# puts-step "Installing Pip ($PIP_VERSION)"
|
rm -fr /app/.heroku/python/lib/python2.7/site-packages/pip-*
|
||||||
tar zxf $ROOT_DIR/vendor/pip-$PIP_VERSION.tar.gz -C $TMPTARDIR
|
rm -fr /app/.heroku/python/lib/python2.7/site-packages/setuptools-*
|
||||||
cd $TMPTARDIR/pip-$PIP_VERSION/
|
|
||||||
python setup.py install &> /dev/null
|
/app/.heroku/python/bin/python $ROOT_DIR/vendor/get-pip.py &> /dev/null
|
||||||
cd $WORKING_DIR
|
|
||||||
|
|
||||||
bpwatch stop install_pip
|
|
||||||
bpwatch stop prepare_environment
|
bpwatch stop prepare_environment
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ indent() {
|
|||||||
|
|
||||||
# Clean up pip output
|
# Clean up pip output
|
||||||
cleanup() {
|
cleanup() {
|
||||||
sed -e 's/\.\.\.\+/.../g' | sed -e '/already satisfied/Id' | sed -e '/Overwriting/Id' | sed -e '/python executable/Id' | sed -e '/no previously-included files/Id'
|
sed -e 's/\.\.\.\+/.../g' | sed -e '/already satisfied/Id' | sed -e '/No files were found to uninstall/Id' | sed -e '/Overwriting/Id' | sed -e '/python executable/Id' | sed -e '/no previously-included files/Id'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Buildpack Indented line.
|
# Buildpack Indented line.
|
||||||
|
|||||||
Vendored
+1
-1
@@ -15,7 +15,7 @@ SOURCE_TARBALL='http://download.osgeo.org/gdal/1.11.1/gdal-1.11.1.tar.gz'
|
|||||||
curl -L $SOURCE_TARBALL | tar zx
|
curl -L $SOURCE_TARBALL | tar zx
|
||||||
|
|
||||||
cd gdal-1.11.1
|
cd gdal-1.11.1
|
||||||
./configure --prefix=$OUT_PREFIX &&
|
./configure --prefix=$OUT_PREFIX --enable-static=no &&
|
||||||
make
|
make
|
||||||
make install
|
make install
|
||||||
|
|
||||||
|
|||||||
Vendored
+3
-3
@@ -10,12 +10,12 @@ hash -r
|
|||||||
|
|
||||||
echo "Building geos..."
|
echo "Building geos..."
|
||||||
|
|
||||||
SOURCE_TARBALL='http://download.osgeo.org/geos/geos-3.4.2.tar.bz2'
|
SOURCE_TARBALL='http://download.osgeo.org/geos/geos-3.4.3.tar.bz2'
|
||||||
|
|
||||||
curl -L $SOURCE_TARBALL | tar xj
|
curl -L $SOURCE_TARBALL | tar xj
|
||||||
|
|
||||||
cd geos-3.4.2
|
cd geos-3.4.3
|
||||||
./configure --prefix=$OUT_PREFIX &&
|
./configure --prefix=$OUT_PREFIX --enable-static=no &&
|
||||||
make
|
make
|
||||||
make install
|
make install
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -15,7 +15,7 @@ SOURCE_TARBALL='http://download.osgeo.org/proj/proj-4.8.0.tar.gz'
|
|||||||
curl -L $SOURCE_TARBALL | tar zx
|
curl -L $SOURCE_TARBALL | tar zx
|
||||||
|
|
||||||
cd proj-4.8.0
|
cd proj-4.8.0
|
||||||
./configure --prefix=$OUT_PREFIX &&
|
./configure --prefix=$OUT_PREFIX --enable-static=no &&
|
||||||
make
|
make
|
||||||
make install
|
make install
|
||||||
|
|
||||||
|
|||||||
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.6.0/Python-3.6.0.tgz'
|
||||||
|
curl -L $SOURCE_TARBALL | tar xz
|
||||||
|
mv Python-3.6.0 src
|
||||||
|
cd src
|
||||||
|
|
||||||
|
./configure --prefix=$OUT_PREFIX --with-ensurepip=no
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
|
||||||
|
ln $OUT_PREFIX/bin/python3 $OUT_PREFIX/bin/python
|
||||||
|
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
wordnet
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
nltk
|
||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
[[source]]
|
||||||
|
url = "https://pypi.python.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
requests = "*"
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.6"
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"default": {
|
||||||
|
"requests": {
|
||||||
|
"version": "==2.13.0",
|
||||||
|
"hash": "sha256:1a720e8862a41aa22e339373b526f508ef0c8988baf48b84d3fc891a8e237efb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {},
|
||||||
|
"_meta": {
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"url": "https://pypi.python.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requires": {
|
||||||
|
"python_version": "3.6"
|
||||||
|
},
|
||||||
|
"hash": {
|
||||||
|
"sha256": "5866990104fc8f27d13cdf01abc2a32c553129e03f666316cacc5b42d3e0884e"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+2
@@ -0,0 +1,2 @@
|
|||||||
|
[packages]
|
||||||
|
"delegator.py" = "*"
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
psycopg2
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
requests
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
python-2.7.13
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
requests
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
python-3.6.0
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
requests
|
||||||
Vendored
+114
@@ -0,0 +1,114 @@
|
|||||||
|
Maya: Datetime for Humans™
|
||||||
|
==========================
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/pypi/v/maya.svg
|
||||||
|
:target: https://pypi.python.org/pypi/maya
|
||||||
|
|
||||||
|
.. image:: https://travis-ci.org/kennethreitz/maya.svg?branch=master
|
||||||
|
:target: https://travis-ci.org/kennethreitz/maya
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/badge/SayThanks.io-☼-1EAEDB.svg
|
||||||
|
:target: https://saythanks.io/to/kennethreitz
|
||||||
|
|
||||||
|
|
||||||
|
Datetimes are very frustrating to work with in Python, especially when dealing
|
||||||
|
with different locales on different systems. This library exists to make the
|
||||||
|
simple things **much** easier, while admitting that time is an illusion
|
||||||
|
(timezones doubly so).
|
||||||
|
|
||||||
|
Datetimes should be interacted with via an API written for humans.
|
||||||
|
|
||||||
|
Maya is mostly built around the headaches and use-cases around parsing datetime data from websites.
|
||||||
|
|
||||||
|
|
||||||
|
☤ Basic Usage of Maya
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Behold, datetimes for humans!
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> now = maya.now()
|
||||||
|
<MayaDT epoch=1481850660.9>
|
||||||
|
|
||||||
|
>>> tomorrow = maya.when('tomorrow')
|
||||||
|
<MayaDT epoch=1481919067.23>
|
||||||
|
|
||||||
|
>>> tomorrow.slang_date()
|
||||||
|
'tomorrow'
|
||||||
|
|
||||||
|
>>> tomorrow.slang_time()
|
||||||
|
'23 hours from now'
|
||||||
|
|
||||||
|
>>> tomorrow.iso8601()
|
||||||
|
'2016-12-16T15:11:30.263350Z'
|
||||||
|
|
||||||
|
>>> tomorrow.rfc2822()
|
||||||
|
'Fri, 16 Dec 2016 20:11:30 -0000'
|
||||||
|
|
||||||
|
>>> tomorrow.datetime()
|
||||||
|
datetime.datetime(2016, 12, 16, 15, 11, 30, 263350, tzinfo=<UTC>)
|
||||||
|
|
||||||
|
# Automatically parse datetime strings and generate naive datetimes.
|
||||||
|
>>> scraped = '2016-12-16 18:23:45.423992+00:00'
|
||||||
|
>>> maya.parse(scraped).datetime(to_timezone='US/Eastern', naive=True)
|
||||||
|
datetime.datetime(2016, 12, 16, 13, 23, 45, 423992)
|
||||||
|
|
||||||
|
>>> rand_day = maya.when('2011-02-07', timezone='US/Eastern')
|
||||||
|
<MayaDT epoch=1297036800.0>
|
||||||
|
|
||||||
|
# Note how this is the 6th, not the 7th.
|
||||||
|
>>> rand_day.day
|
||||||
|
6
|
||||||
|
|
||||||
|
# Always.
|
||||||
|
>>> rand_day.timezone
|
||||||
|
UTC
|
||||||
|
|
||||||
|
☤ Why is this useful?
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
- All timezone algebra will behave identically on all machines, regardless of system locale.
|
||||||
|
- Complete symmetric import and export of both ISO 8601 and RFC 2822 datetime stamps.
|
||||||
|
- Fantastic parsing of both dates written for/by humans and machines (``maya.when()`` vs ``maya.parse()``).
|
||||||
|
- Support for human slang, both import and export (e.g. `an hour ago`).
|
||||||
|
- Datetimes can very easily be generated, with or without tzinfo attached.
|
||||||
|
- This library is based around epoch time, but dates before Jan 1 1970 are indeed supported, via negative integers.
|
||||||
|
- Maya never panics, and always carries a towel.
|
||||||
|
|
||||||
|
|
||||||
|
☤ What about Delorean, Arrow, & Pendulum?
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
Arrow, for example, is a fantastic library, but isn't what I wanted in a datetime library. In many ways, it's better than Maya for certain things. In some ways, in my opinion, it's not.
|
||||||
|
|
||||||
|
I simply desire a sane API for datetimes that made sense to me for all the things I'd ever want to do—especially when dealing with timezone algebra. Arrow doesn't do all of the things I need (but it does a lot more!). Maya does do exactly what I need.
|
||||||
|
|
||||||
|
I think these projects complement each-other, personally. Maya is great for parsing websites. For example- Arrow supports floors and ceilings and spans of dates, which Maya does not at all.
|
||||||
|
|
||||||
|
|
||||||
|
☤ Installing Maya
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Installation is easy, with pip::
|
||||||
|
|
||||||
|
$ pip install maya
|
||||||
|
|
||||||
|
✨🍰✨
|
||||||
|
|
||||||
|
☤ Like it?
|
||||||
|
----------
|
||||||
|
|
||||||
|
`Say Thanks <https://saythanks.io/to/kennethreitz>`_!
|
||||||
|
|
||||||
|
|
||||||
|
How to Contribute
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
#. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug.
|
||||||
|
#. Fork `the repository`_ on GitHub to start making your changes to the **master** branch (or branch off of it).
|
||||||
|
#. Write a test which shows that the bug was fixed or that the feature works as expected.
|
||||||
|
#. Send a pull request and bug the maintainer until it gets merged and published. :) Make sure to add yourself to AUTHORS_.
|
||||||
|
|
||||||
|
.. _`the repository`: http://github.com/kennethreitz/maya
|
||||||
|
.. _AUTHORS: https://github.com/kennethreitz/maya/blob/master/AUTHORS.rst
|
||||||
Vendored
+273
@@ -0,0 +1,273 @@
|
|||||||
|
|
||||||
|
# ___ __ ___ _ _ ___
|
||||||
|
# || \/ | ||=|| \\// ||=||
|
||||||
|
# || | || || // || ||
|
||||||
|
|
||||||
|
# Ignore warnings for yaml usage.
|
||||||
|
import warnings
|
||||||
|
import ruamel.yaml
|
||||||
|
warnings.simplefilter('ignore', ruamel.yaml.error.UnsafeLoaderWarning)
|
||||||
|
|
||||||
|
|
||||||
|
import email.utils
|
||||||
|
import time
|
||||||
|
from datetime import datetime as Datetime
|
||||||
|
|
||||||
|
import pytz
|
||||||
|
import humanize
|
||||||
|
import dateparser
|
||||||
|
import iso8601
|
||||||
|
import dateutil.parser
|
||||||
|
from tzlocal import get_localzone
|
||||||
|
|
||||||
|
_EPOCH_START = (1970, 1, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_class_type_arguments(operator):
|
||||||
|
"""
|
||||||
|
Decorator to validate all the arguments to function
|
||||||
|
are of the type of calling class
|
||||||
|
"""
|
||||||
|
|
||||||
|
def inner(function):
|
||||||
|
def wrapper(self, *args, **kwargs):
|
||||||
|
for arg in args + tuple(kwargs.values()):
|
||||||
|
if not isinstance(arg, self.__class__):
|
||||||
|
raise TypeError('unorderable types: {}() {} {}()'.format(
|
||||||
|
type(self).__name__, operator, type(arg).__name__))
|
||||||
|
return function(self, *args, **kwargs)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
return inner
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class MayaDT(object):
|
||||||
|
"""The Maya Datetime object."""
|
||||||
|
|
||||||
|
def __init__(self, epoch):
|
||||||
|
super(MayaDT, self).__init__()
|
||||||
|
self._epoch = epoch
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<MayaDT epoch={}>'.format(self._epoch)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.rfc2822()
|
||||||
|
|
||||||
|
def __format__(self, *args, **kwargs):
|
||||||
|
"""Return's the datetime's format"""
|
||||||
|
return format(self.datetime(), *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@validate_class_type_arguments('==')
|
||||||
|
def __eq__(self, maya_dt):
|
||||||
|
return self._epoch == maya_dt._epoch
|
||||||
|
|
||||||
|
@validate_class_type_arguments('!=')
|
||||||
|
def __ne__(self, maya_dt):
|
||||||
|
return self._epoch != maya_dt._epoch
|
||||||
|
|
||||||
|
@validate_class_type_arguments('<')
|
||||||
|
def __lt__(self, maya_dt):
|
||||||
|
return self._epoch < maya_dt._epoch
|
||||||
|
|
||||||
|
@validate_class_type_arguments('<=')
|
||||||
|
def __le__(self, maya_dt):
|
||||||
|
return self._epoch <= maya_dt._epoch
|
||||||
|
|
||||||
|
@validate_class_type_arguments('>')
|
||||||
|
def __gt__(self, maya_dt):
|
||||||
|
return self._epoch > maya_dt._epoch
|
||||||
|
|
||||||
|
@validate_class_type_arguments('>=')
|
||||||
|
def __ge__(self, maya_dt):
|
||||||
|
return self._epoch >= maya_dt._epoch
|
||||||
|
|
||||||
|
|
||||||
|
# Timezone Crap
|
||||||
|
# -------------
|
||||||
|
|
||||||
|
@property
|
||||||
|
def timezone(self):
|
||||||
|
"""Returns the UTC tzinfo name. It's always UTC. Always."""
|
||||||
|
return 'UTC'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _tz(self):
|
||||||
|
"""Returns the UTC tzinfo object."""
|
||||||
|
return pytz.timezone(self.timezone)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def local_timezone(self):
|
||||||
|
"""Returns the name of the local timezone, for informational purposes."""
|
||||||
|
return self._local_tz.zone
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _local_tz(self):
|
||||||
|
"""Returns the local timezone."""
|
||||||
|
return get_localzone()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __dt_to_epoch(dt):
|
||||||
|
"""Converts a datetime into an epoch."""
|
||||||
|
|
||||||
|
# Assume UTC if no datetime is provided.
|
||||||
|
if dt.tzinfo is None:
|
||||||
|
dt = dt.replace(tzinfo=pytz.utc)
|
||||||
|
|
||||||
|
epoch_start = Datetime(*_EPOCH_START, tzinfo=pytz.timezone('UTC'))
|
||||||
|
return (dt - epoch_start).total_seconds()
|
||||||
|
|
||||||
|
# Importers
|
||||||
|
# ---------
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_datetime(klass, dt):
|
||||||
|
"""Returns MayaDT instance from datetime."""
|
||||||
|
return klass(klass.__dt_to_epoch(dt))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_iso8601(klass, string):
|
||||||
|
"""Returns MayaDT instance from iso8601 string."""
|
||||||
|
dt = iso8601.parse_date(string)
|
||||||
|
return klass.from_datetime(dt)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_rfc2822(string):
|
||||||
|
"""Returns MayaDT instance from rfc2822 string."""
|
||||||
|
return parse(string)
|
||||||
|
|
||||||
|
# Exporters
|
||||||
|
# ---------
|
||||||
|
|
||||||
|
def datetime(self, to_timezone=None, naive=False):
|
||||||
|
"""Returns a timezone-aware datetime...
|
||||||
|
Defaulting to UTC (as it should).
|
||||||
|
|
||||||
|
Keyword Arguments:
|
||||||
|
to_timezone {string} -- timezone to convert to (default: None/UTC)
|
||||||
|
naive {boolean} -- if True, the tzinfo is simply dropped (default: False)
|
||||||
|
"""
|
||||||
|
if to_timezone:
|
||||||
|
dt = self.datetime().astimezone(pytz.timezone(to_timezone))
|
||||||
|
else:
|
||||||
|
dt = Datetime.utcfromtimestamp(self._epoch)
|
||||||
|
dt.replace(tzinfo=self._tz)
|
||||||
|
|
||||||
|
# Strip the timezone info if requested to do so.
|
||||||
|
if naive:
|
||||||
|
return dt.replace(tzinfo=None)
|
||||||
|
else:
|
||||||
|
if dt.tzinfo is None:
|
||||||
|
dt = dt.replace(tzinfo=self._tz)
|
||||||
|
|
||||||
|
return dt
|
||||||
|
|
||||||
|
def iso8601(self):
|
||||||
|
"""Returns an ISO 8601 representation of the MayaDT."""
|
||||||
|
# Get a timezone-naive datetime.
|
||||||
|
dt = self.datetime(naive=True)
|
||||||
|
return '{}Z'.format(dt.isoformat())
|
||||||
|
|
||||||
|
def rfc2822(self):
|
||||||
|
"""Returns an RFC 2822 representation of the MayaDT."""
|
||||||
|
return email.utils.formatdate(self.epoch, usegmt=True)
|
||||||
|
|
||||||
|
# Properties
|
||||||
|
# ----------
|
||||||
|
|
||||||
|
@property
|
||||||
|
def year(self):
|
||||||
|
return self.datetime().year
|
||||||
|
|
||||||
|
@property
|
||||||
|
def month(self):
|
||||||
|
return self.datetime().month
|
||||||
|
|
||||||
|
@property
|
||||||
|
def day(self):
|
||||||
|
return self.datetime().day
|
||||||
|
|
||||||
|
@property
|
||||||
|
def week(self):
|
||||||
|
return self.datetime().isocalendar()[1]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def weekday(self):
|
||||||
|
"""Return the day of the week as an integer. Monday is 1 and Sunday is 7"""
|
||||||
|
return self.datetime().isoweekday()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hour(self):
|
||||||
|
return self.datetime().hour
|
||||||
|
|
||||||
|
@property
|
||||||
|
def minute(self):
|
||||||
|
return self.datetime().minute
|
||||||
|
|
||||||
|
@property
|
||||||
|
def second(self):
|
||||||
|
return self.datetime().second
|
||||||
|
|
||||||
|
@property
|
||||||
|
def microsecond(self):
|
||||||
|
return self.datetime().microsecond
|
||||||
|
|
||||||
|
@property
|
||||||
|
def epoch(self):
|
||||||
|
return self._epoch
|
||||||
|
|
||||||
|
# Human Slang Extras
|
||||||
|
# ------------------
|
||||||
|
|
||||||
|
def slang_date(self):
|
||||||
|
""""Returns human slang representation of date."""
|
||||||
|
dt = self.datetime(naive=True, to_timezone=self.local_timezone)
|
||||||
|
return humanize.naturaldate(dt)
|
||||||
|
|
||||||
|
def slang_time(self):
|
||||||
|
""""Returns human slang representation of time."""
|
||||||
|
dt = self.datetime(naive=True, to_timezone=self.local_timezone)
|
||||||
|
return humanize.naturaltime(dt)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def now():
|
||||||
|
"""Returns a MayaDT instance for this exact moment."""
|
||||||
|
epoch = time.time()
|
||||||
|
return MayaDT(epoch=epoch)
|
||||||
|
|
||||||
|
def when(string, timezone='UTC'):
|
||||||
|
""""Returns a MayaDT instance for the human moment specified.
|
||||||
|
|
||||||
|
Powered by dateparser. Useful for scraping websites.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
'next week', 'now', 'tomorrow', '300 years ago', 'August 14, 2015'
|
||||||
|
|
||||||
|
Keyword Arguments:
|
||||||
|
string -- string to be parsed
|
||||||
|
timezone -- timezone referenced from (default: 'UTC')
|
||||||
|
|
||||||
|
"""
|
||||||
|
dt = dateparser.parse(string, settings={'TIMEZONE': timezone, 'RETURN_AS_TIMEZONE_AWARE': True, 'TO_TIMEZONE': 'UTC'})
|
||||||
|
|
||||||
|
if dt is None:
|
||||||
|
raise ValueError('invalid datetime input specified.')
|
||||||
|
|
||||||
|
return MayaDT.from_datetime(dt)
|
||||||
|
|
||||||
|
def parse(string, day_first=False):
|
||||||
|
""""Returns a MayaDT instance for the machine-produced moment specified.
|
||||||
|
|
||||||
|
Powered by dateutil. Accepts most known formats. Useful for working with data.
|
||||||
|
|
||||||
|
Keyword Arguments:
|
||||||
|
string -- string to be parsed
|
||||||
|
day_first -- if true, the first value (e.g. 01/05/2016) is parsed as day (default: False)
|
||||||
|
"""
|
||||||
|
dt = dateutil.parser.parse(string, dayfirst=day_first)
|
||||||
|
return MayaDT.from_datetime(dt)
|
||||||
Vendored
+51
@@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import codecs
|
||||||
|
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Python 3
|
||||||
|
from os import dirname
|
||||||
|
except ImportError:
|
||||||
|
# Python 2
|
||||||
|
from os.path import dirname
|
||||||
|
|
||||||
|
here = os.path.abspath(dirname(__file__))
|
||||||
|
|
||||||
|
with codecs.open(os.path.join(here, 'README.rst'), encoding='utf-8') as f:
|
||||||
|
long_description = '\n' + f.read()
|
||||||
|
|
||||||
|
|
||||||
|
if sys.argv[-1] == "publish":
|
||||||
|
os.system("python setup.py sdist bdist_wheel upload")
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
required = [
|
||||||
|
'humanize',
|
||||||
|
'pytz',
|
||||||
|
'dateparser',
|
||||||
|
'iso8601',
|
||||||
|
'python-dateutil',
|
||||||
|
'ruamel.yaml',
|
||||||
|
'tzlocal'
|
||||||
|
]
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='maya',
|
||||||
|
version='0.1.6',
|
||||||
|
description='Datetimes for Humans.',
|
||||||
|
long_description=long_description,
|
||||||
|
author='Kenneth Reitz',
|
||||||
|
author_email='me@kennethreitz.com',
|
||||||
|
url='https://github.com/kennethreitz/maya',
|
||||||
|
py_modules=['maya'],
|
||||||
|
install_requires=required,
|
||||||
|
license='MIT',
|
||||||
|
classifiers=(
|
||||||
|
|
||||||
|
),
|
||||||
|
)
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
|
||||||
|
testPipenv() {
|
||||||
|
compile "pipenv"
|
||||||
|
assertCapturedSuccess
|
||||||
|
}
|
||||||
|
|
||||||
|
testPipenvVersion() {
|
||||||
|
compile "pipenv-version"
|
||||||
|
assertCaptured "3.6.0"
|
||||||
|
assertCapturedSuccess
|
||||||
|
}
|
||||||
|
|
||||||
|
testNoRequirements() {
|
||||||
|
compile "no-requirements"
|
||||||
|
assertCapturedError
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
testNLTK() {
|
||||||
|
compile "nltk"
|
||||||
|
assertCaptured "wordnet"
|
||||||
|
assertCapturedSuccess
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
testSetupPy() {
|
||||||
|
compile "setup-py"
|
||||||
|
assertCaptured "maya"
|
||||||
|
assertCapturedSuccess
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
testStandardRequirements() {
|
||||||
|
compile "requirements-standard"
|
||||||
|
assertCaptured "requests"
|
||||||
|
assertCapturedSuccess
|
||||||
|
}
|
||||||
|
|
||||||
|
testPsycopg2() {
|
||||||
|
compile "psycopg2"
|
||||||
|
assertCaptured "psycopg2"
|
||||||
|
assertCapturedSuccess
|
||||||
|
}
|
||||||
|
|
||||||
|
testPython2() {
|
||||||
|
compile "python2"
|
||||||
|
assertCaptured "python-2.7.13"
|
||||||
|
assertCapturedSuccess
|
||||||
|
}
|
||||||
|
|
||||||
|
testPython3() {
|
||||||
|
compile "python3"
|
||||||
|
assertCaptured "python-3.6.0"
|
||||||
|
assertCapturedSuccess
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pushd $(dirname 0) >/dev/null
|
||||||
|
popd >/dev/null
|
||||||
|
|
||||||
|
source $(pwd)/test/utils
|
||||||
|
|
||||||
|
mktmpdir() {
|
||||||
|
dir=$(mktemp -t testXXXXX)
|
||||||
|
rm -rf $dir
|
||||||
|
mkdir $dir
|
||||||
|
echo $dir
|
||||||
|
}
|
||||||
|
|
||||||
|
detect() {
|
||||||
|
capture $(pwd)/bin/detect $(pwd)/test/fixtures/$1
|
||||||
|
}
|
||||||
|
|
||||||
|
compile_dir=""
|
||||||
|
|
||||||
|
default_process_types_cleanup() {
|
||||||
|
file="/tmp/default_process_types"
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
rm "$file"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
compile() {
|
||||||
|
default_process_types_cleanup
|
||||||
|
bp_dir=$(mktmpdir)
|
||||||
|
compile_dir=$(mktmpdir)
|
||||||
|
cp -a $(pwd)/* ${bp_dir}
|
||||||
|
cp -a ${bp_dir}/test/fixtures/$1/. ${compile_dir}
|
||||||
|
capture ${bp_dir}/bin/compile ${compile_dir} ${2:-$(mktmpdir)} $3
|
||||||
|
}
|
||||||
|
|
||||||
|
compileDir() {
|
||||||
|
default_process_types_cleanup
|
||||||
|
|
||||||
|
local bp_dir=$(mktmpdir)
|
||||||
|
local compile_dir=${1:-$(mktmpdir)}
|
||||||
|
local cache_dir=${2:-$(mktmpdir)}
|
||||||
|
local env_dir=$3
|
||||||
|
|
||||||
|
cp -a $(pwd)/* ${bp_dir}
|
||||||
|
capture ${bp_dir}/bin/compile ${compile_dir} ${cache_dir} ${env_dir}
|
||||||
|
}
|
||||||
|
|
||||||
|
release() {
|
||||||
|
bp_dir=$(mktmpdir)
|
||||||
|
cp -a $(pwd)/* ${bp_dir}
|
||||||
|
capture ${bp_dir}/bin/release ${bp_dir}/test/fixtures/$1
|
||||||
|
}
|
||||||
|
|
||||||
|
assertFile() {
|
||||||
|
assertEquals "$1" "$(cat ${compile_dir}/$2)"
|
||||||
|
}
|
||||||
|
|
||||||
|
source $(pwd)/test/shunit2
|
||||||
Executable
+1048
File diff suppressed because it is too large
Load Diff
+197
@@ -0,0 +1,197 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# taken from
|
||||||
|
# https://github.com/ryanbrainard/heroku-buildpack-testrunner/blob/master/lib/test_utils.sh
|
||||||
|
|
||||||
|
oneTimeSetUp()
|
||||||
|
{
|
||||||
|
TEST_SUITE_CACHE="$(mktemp -d ${SHUNIT_TMPDIR}/test_suite_cache.XXXX)"
|
||||||
|
}
|
||||||
|
|
||||||
|
oneTimeTearDown()
|
||||||
|
{
|
||||||
|
rm -rf ${TEST_SUITE_CACHE}
|
||||||
|
}
|
||||||
|
|
||||||
|
setUp()
|
||||||
|
{
|
||||||
|
OUTPUT_DIR="$(mktemp -d ${SHUNIT_TMPDIR}/output.XXXX)"
|
||||||
|
STD_OUT="${OUTPUT_DIR}/stdout"
|
||||||
|
STD_ERR="${OUTPUT_DIR}/stderr"
|
||||||
|
BUILD_DIR="${OUTPUT_DIR}/build"
|
||||||
|
CACHE_DIR="${OUTPUT_DIR}/cache"
|
||||||
|
mkdir -p ${OUTPUT_DIR}
|
||||||
|
mkdir -p ${BUILD_DIR}
|
||||||
|
mkdir -p ${CACHE_DIR}
|
||||||
|
}
|
||||||
|
|
||||||
|
tearDown()
|
||||||
|
{
|
||||||
|
rm -rf ${OUTPUT_DIR}
|
||||||
|
}
|
||||||
|
|
||||||
|
capture()
|
||||||
|
{
|
||||||
|
resetCapture
|
||||||
|
|
||||||
|
LAST_COMMAND="$@"
|
||||||
|
|
||||||
|
$@ >${STD_OUT} 2>${STD_ERR}
|
||||||
|
RETURN=$?
|
||||||
|
rtrn=${RETURN} # deprecated
|
||||||
|
}
|
||||||
|
|
||||||
|
resetCapture()
|
||||||
|
{
|
||||||
|
if [ -f ${STD_OUT} ]; then
|
||||||
|
rm ${STD_OUT}
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f ${STD_ERR} ]; then
|
||||||
|
rm ${STD_ERR}
|
||||||
|
fi
|
||||||
|
|
||||||
|
unset LAST_COMMAND
|
||||||
|
unset RETURN
|
||||||
|
unset rtrn # deprecated
|
||||||
|
}
|
||||||
|
|
||||||
|
detect()
|
||||||
|
{
|
||||||
|
capture ${BUILDPACK_HOME}/bin/detect ${BUILD_DIR}
|
||||||
|
}
|
||||||
|
|
||||||
|
compile()
|
||||||
|
{
|
||||||
|
capture ${BUILDPACK_HOME}/bin/compile ${BUILD_DIR} ${CACHE_DIR}
|
||||||
|
}
|
||||||
|
|
||||||
|
release()
|
||||||
|
{
|
||||||
|
capture ${BUILDPACK_HOME}/bin/release ${BUILD_DIR}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertCapturedEquals()
|
||||||
|
{
|
||||||
|
assertEquals "$@" "$(cat ${STD_OUT})"
|
||||||
|
}
|
||||||
|
|
||||||
|
assertCapturedNotEquals()
|
||||||
|
{
|
||||||
|
assertNotEquals "$@" "$(cat ${STD_OUT})"
|
||||||
|
}
|
||||||
|
|
||||||
|
assertCaptured()
|
||||||
|
{
|
||||||
|
assertFileContains "$@" "${STD_OUT}"
|
||||||
|
}
|
||||||
|
|
||||||
|
assertNotCaptured()
|
||||||
|
{
|
||||||
|
assertFileNotContains "$@" "${STD_OUT}"
|
||||||
|
}
|
||||||
|
|
||||||
|
assertCapturedSuccess()
|
||||||
|
{
|
||||||
|
assertEquals "Expected captured exit code to be 0; was <${RETURN}>" "0" "${RETURN}"
|
||||||
|
assertEquals "Expected STD_ERR to be empty; was <$(cat ${STD_ERR})>" "" "$(cat ${STD_ERR})"
|
||||||
|
}
|
||||||
|
|
||||||
|
# assertCapturedError [[expectedErrorCode] expectedErrorMsg]
|
||||||
|
assertCapturedError()
|
||||||
|
{
|
||||||
|
if [ $# -gt 1 ]; then
|
||||||
|
local expectedErrorCode=${1}
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
local expectedErrorMsg=${1:-""}
|
||||||
|
|
||||||
|
if [ -z ${expectedErrorCode} ]; then
|
||||||
|
assertTrue "Expected captured exit code to be greater than 0; was <${RETURN}>" "[ ${RETURN} -gt 0 ]"
|
||||||
|
else
|
||||||
|
assertTrue "Expected captured exit code to be <${expectedErrorCode}>; was <${RETURN}>" "[ ${RETURN} -eq ${expectedErrorCode} ]"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${expectedErrorMsg}" != "" ]; then
|
||||||
|
assertFileContains "Expected STD_ERR to contain error <${expectedErrorMsg}>" "${expectedErrorMsg}" "${STD_ERR}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_assertContains()
|
||||||
|
{
|
||||||
|
if [ 5 -eq $# ]; then
|
||||||
|
local msg=$1
|
||||||
|
shift
|
||||||
|
elif [ ! 4 -eq $# ]; then
|
||||||
|
fail "Expected 4 or 5 parameters; Receieved $# parameters"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local needle=$1
|
||||||
|
local haystack=$2
|
||||||
|
local expectation=$3
|
||||||
|
local haystack_type=$4
|
||||||
|
|
||||||
|
case "${haystack_type}" in
|
||||||
|
"file") grep -q -F -e "${needle}" ${haystack} ;;
|
||||||
|
"text") echo "${haystack}" | grep -q -F -e "${needle}" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ "${expectation}" != "$?" ]; then
|
||||||
|
case "${expectation}" in
|
||||||
|
0) default_msg="Expected <${haystack}> to contain <${needle}>" ;;
|
||||||
|
1) default_msg="Did not expect <${haystack}> to contain <${needle}>" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
fail "${msg:-${default_msg}}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
debug()
|
||||||
|
{
|
||||||
|
cat $STD_OUT
|
||||||
|
echo '^^^^^^'
|
||||||
|
cat $STD_ERR
|
||||||
|
}
|
||||||
|
|
||||||
|
assertContains()
|
||||||
|
{
|
||||||
|
_assertContains "$@" 0 "text"
|
||||||
|
}
|
||||||
|
|
||||||
|
assertNotContains()
|
||||||
|
{
|
||||||
|
_assertContains "$@" 1 "text"
|
||||||
|
}
|
||||||
|
|
||||||
|
assertFileContains()
|
||||||
|
{
|
||||||
|
_assertContains "$@" 0 "file"
|
||||||
|
}
|
||||||
|
|
||||||
|
assertFileNotContains()
|
||||||
|
{
|
||||||
|
_assertContains "$@" 1 "file"
|
||||||
|
}
|
||||||
|
|
||||||
|
command_exists () {
|
||||||
|
type "$1" > /dev/null 2>&1 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertFileMD5()
|
||||||
|
{
|
||||||
|
expectedHash=$1
|
||||||
|
filename=$2
|
||||||
|
|
||||||
|
if command_exists "md5sum"; then
|
||||||
|
md5_cmd="md5sum ${filename}"
|
||||||
|
expected_md5_cmd_output="${expectedHash} ${filename}"
|
||||||
|
elif command_exists "md5"; then
|
||||||
|
md5_cmd="md5 ${filename}"
|
||||||
|
expected_md5_cmd_output="MD5 (${filename}) = ${expectedHash}"
|
||||||
|
else
|
||||||
|
fail "no suitable MD5 hashing command found on this system"
|
||||||
|
fi
|
||||||
|
|
||||||
|
assertEquals "${expected_md5_cmd_output}" "`${md5_cmd}`"
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
if [[ ! "$STACK" ]]; then
|
||||||
|
echo '$STACK must be set! (heroku-16 | cedar-14)'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$STACK" == "cedar-14" ]]; then
|
||||||
|
make test-cedar-14
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$STACK" == "heroku-16" ]]; then
|
||||||
|
make test-heroku-16
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
Vendored
+20061
File diff suppressed because it is too large
Load Diff
Vendored
BIN
Binary file not shown.
Vendored
+10
-4
@@ -1,29 +1,35 @@
|
|||||||
|
if [[ "${WEB_CONCURRENCY:-}" == 0* ]]; then
|
||||||
|
# another buildpack set a default value, with leading zero
|
||||||
|
unset WEB_CONCURRENCY
|
||||||
|
fi
|
||||||
|
|
||||||
case $(ulimit -u) in
|
case $(ulimit -u) in
|
||||||
|
|
||||||
# Automatic configuration for Gunicorn's Workers setting.
|
# Automatic configuration for Gunicorn's Workers setting.
|
||||||
|
# Leading zero padding so a subsequent buildpack can figure out that we set a value, and not the user
|
||||||
|
|
||||||
# Standard-1X (+Free, +Hobby) Dyno
|
# Standard-1X (+Free, +Hobby) Dyno
|
||||||
256)
|
256)
|
||||||
export DYNO_RAM=512
|
export DYNO_RAM=512
|
||||||
export WEB_CONCURRENCY=${WEB_CONCURRENCY:-2}
|
export WEB_CONCURRENCY=${WEB_CONCURRENCY:-02}
|
||||||
;;
|
;;
|
||||||
|
|
||||||
# Standard-2X Dyno
|
# Standard-2X Dyno
|
||||||
512)
|
512)
|
||||||
export DYNO_RAM=1024
|
export DYNO_RAM=1024
|
||||||
export WEB_CONCURRENCY=${WEB_CONCURRENCY:-4}
|
export WEB_CONCURRENCY=${WEB_CONCURRENCY:-04}
|
||||||
;;
|
;;
|
||||||
|
|
||||||
# Performance-M Dyno
|
# Performance-M Dyno
|
||||||
16384)
|
16384)
|
||||||
export DYNO_RAM=2560
|
export DYNO_RAM=2560
|
||||||
export WEB_CONCURRENCY=${WEB_CONCURRENCY:-8}
|
export WEB_CONCURRENCY=${WEB_CONCURRENCY:-08}
|
||||||
;;
|
;;
|
||||||
|
|
||||||
# Performance-L Dyno
|
# Performance-L Dyno
|
||||||
32768)
|
32768)
|
||||||
export DYNO_RAM=6656
|
export DYNO_RAM=6656
|
||||||
export WEB_CONCURRENCY=${WEB_CONCURRENCY:-11}
|
export WEB_CONCURRENCY=${WEB_CONCURRENCY:-011}
|
||||||
;;
|
;;
|
||||||
|
|
||||||
esac
|
esac
|
||||||
|
|||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
runtime_file = sys.argv[1]
|
||||||
|
|
||||||
|
with open(runtime_file, 'r') as f:
|
||||||
|
r = f.read().strip()
|
||||||
|
|
||||||
|
with open(runtime_file, 'w') as f:
|
||||||
|
f.write(r)
|
||||||
Reference in New Issue
Block a user