docker setup; celery/beat config

This commit is contained in:
crflynn
2018-04-22 17:43:40 -04:00
parent 9cb0cfb9d1
commit 0cbdd8398d
18 changed files with 284 additions and 403 deletions

35
.dockerignore Normal file
View File

@@ -0,0 +1,35 @@
# project
.git
.gitignore
.dockerignore
Dockerfile
Pipfile
Pipfile.lock
migrations/
zappa*
run.sh
docs/
tests/
# mac osx
.DS_Store
# python bytecode
*.py[cod]
__pycache__
# ignore
ignore/
# celery
celerybeat-schedule
celerybeat.pid
# redis
dump.rdb
# packaged deployments
*.zip
# zappa settings
zappa_settings.json

8
.gitignore vendored
View File

@@ -1,4 +1,3 @@
# credentials # credentials
secret.* secret.*
env_vars* env_vars*
@@ -16,5 +15,12 @@ ignore/
# packaged deployments # packaged deployments
*.zip *.zip
# celery
celerybeat-schedule
celerybeat.pid
# redis
dump.rdb
# zappa settings # zappa settings
zappa_settings.json zappa_settings.json

7
Dockerfile Normal file
View File

@@ -0,0 +1,7 @@
FROM python:3.6-slim
ADD requirements.txt requirements.txt
RUN pip install -r requirements.txt
ADD . .
EXPOSE 5000

15
Pipfile
View File

@@ -10,13 +10,14 @@ name = "pypi"
google-cloud-bigquery = "*" google-cloud-bigquery = "*"
pandas = "*" pandas = "*"
"psycopg2" = "*" "psycopg2" = "*"
Flask = "*" flask = "*"
GitHub-Flask = "*" github-flask = "*"
Flask-SQLAlchemy = "*" flask-sqlalchemy = "*"
Flask-Migrate = "*" flask-migrate = "*"
Flask-Login = "*" flask-login = "*"
Flask-WTF = "*" flask-wtf = "*"
zappa = "*" celery = "*"
redis = "*"
[dev-packages] [dev-packages]

219
Pipfile.lock generated
View File

@@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "f00e05278f16f93aec905d0408ca9e786385d8f3a2a29dc5a1b7b6b65aca8383" "sha256": "8fbdf096ac477c3d82ab03aa50f0238201297c7572dc9d7b5f709675e7f0e6bd"
}, },
"host-environment-markers": { "host-environment-markers": {
"implementation_name": "cpython", "implementation_name": "cpython",
@@ -33,33 +33,19 @@
], ],
"version": "==0.9.9" "version": "==0.9.9"
}, },
"argcomplete": { "amqp": {
"hashes": [ "hashes": [
"sha256:74e34bbd5bcb902e67a39e2edf1b1ef3dcb504a6a1d4cd23ce3949f25c4aad55", "sha256:4e28d3ea61a64ae61830000c909662cb053642efddbe96503db0e7783a6ee85b",
"sha256:d6ea272a93bb0387f758def836e73c36fff0c54170258c212de3e84f7db8d5ed" "sha256:cba1ace9d4ff6049b190d8b7991f9c1006b443a5238021aca96dd6ad2ac9da22"
], ],
"version": "==1.9.2" "version": "==2.2.2"
}, },
"base58": { "billiard": {
"hashes": [ "hashes": [
"sha256:aafdd84adf1fbd073eb2fd7f7266d7bd9f2423ee1000ee61cd021b97ed359f39", "sha256:abd9ce008c9a71ccde2c816f8daa36246e92a21e6a799831b887d88277187ecd",
"sha256:97cb4dcbc7a81afb802f41033d5562b6c48633426a67bf41e4cad186f581158c" "sha256:1d7b22bdc47aa52841120fcd22a74ae4fc8c13e9d3935643098184f5788c3ce6"
], ],
"version": "==0.2.4" "version": "==3.5.0.3"
},
"boto3": {
"hashes": [
"sha256:13ad5f64a247d655a27dca83274588e9d14cba61b38d3d4fd2b011b7197d88dd",
"sha256:a56b21efbc994580fc9cef454f0f949745c152326f939aed6609d1c47b2a0f8f"
],
"version": "==1.7.4"
},
"botocore": {
"hashes": [
"sha256:77f2869b8c27afbab78b72ce6b74c75923421f364c7a0153ac1a38858c59cd91",
"sha256:5602738392ecde5c02a06a3b02de07171f440a44cdfef0aadff4b59567359607"
],
"version": "==1.10.4"
}, },
"cachetools": { "cachetools": {
"hashes": [ "hashes": [
@@ -68,18 +54,19 @@
], ],
"version": "==2.0.1" "version": "==2.0.1"
}, },
"celery": {
"hashes": [
"sha256:81a67f0d53a688ec2bc8557bd5d6d7218f925a6f2e6df80e01560de9e28997ec",
"sha256:77ff3730198d6a17b3c1f05579ebe570b579efb35f6d7e13dba3b1368d068b35"
],
"version": "==4.1.0"
},
"certifi": { "certifi": {
"hashes": [ "hashes": [
"sha256:14131608ad2fd56836d33a71ee60fa1c82bc9d2c8d98b7bdbc631fe1b3cd1296", "sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0",
"sha256:edbc3f203427eef571f79a7692bb160a2b0f7ccaa31953e99bd17e307cf63f7d" "sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7"
], ],
"version": "==2018.1.18" "version": "==2018.4.16"
},
"cfn-flip": {
"hashes": [
"sha256:9c61039c71995ab204c005ec46d47d0f7a109e9f1b6d63569397f8bc648a8151"
],
"version": "==1.0.3"
}, },
"chardet": { "chardet": {
"hashes": [ "hashes": [
@@ -95,20 +82,6 @@
], ],
"version": "==6.7" "version": "==6.7"
}, },
"docutils": {
"hashes": [
"sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6",
"sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
"sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274"
],
"version": "==0.14"
},
"durationpy": {
"hashes": [
"sha256:5ef9416b527b50d722f34655becfb75e49228eb82f87b855ed1911b3314b5408"
],
"version": "==0.5"
},
"flask": { "flask": {
"hashes": [ "hashes": [
"sha256:0749df235e3ff61ac108f69ac178c9770caeaccad2509cb762ce1f65570a8856", "sha256:0749df235e3ff61ac108f69ac178c9770caeaccad2509cb762ce1f65570a8856",
@@ -143,12 +116,6 @@
], ],
"version": "==0.14.2" "version": "==0.14.2"
}, },
"future": {
"hashes": [
"sha256:e39ced1ab767b5936646cedba8bcce582398233d6a627067d4c6a454c90cfedb"
],
"version": "==0.16.0"
},
"github-flask": { "github-flask": {
"hashes": [ "hashes": [
"sha256:24600b720f698bac10667b76b136995ba7821d884e58b27e2a18ca0e4760c786" "sha256:24600b720f698bac10667b76b136995ba7821d884e58b27e2a18ca0e4760c786"
@@ -157,10 +124,10 @@
}, },
"google-api-core": { "google-api-core": {
"hashes": [ "hashes": [
"sha256:7618a9c2ee84c0d99f9c7823675c15024b25094bb920f49d204a72107d856aac", "sha256:4885e5298e45aa587185c32bee54f95e79a05a926d69fcfd398c66b12b98b9a7",
"sha256:b4f103de6bd38ab346f7d17236f6098a51ebdff733ff69956a0f1e29cb35f10b" "sha256:d23d5ae89e44ca1ddddec94e5f7c03f52402d192e66345d448b77ad5276b0fbe"
], ],
"version": "==1.1.0" "version": "==1.1.1"
}, },
"google-auth": { "google-auth": {
"hashes": [ "hashes": [
@@ -171,10 +138,10 @@
}, },
"google-cloud-bigquery": { "google-cloud-bigquery": {
"hashes": [ "hashes": [
"sha256:0681c20dbc663ba382397fd4fc45bd6dba92339408ff399365e47303753f3084", "sha256:44d152e1de60cce8fe9d4f5c60ca4cebc88daab02b4d889bb0ebfcc19d54d7ec",
"sha256:f1c274342a364904de0656eeee519ba6c2cf165204b824ccb39370b72f242894" "sha256:aed2b1d4db1e21d891522d6d6bb14476e6ba58c681cbb68eeb42c168a4e3fda9"
], ],
"version": "==0.32.0" "version": "==1.1.0"
}, },
"google-cloud-core": { "google-cloud-core": {
"hashes": [ "hashes": [
@@ -196,12 +163,6 @@
], ],
"version": "==1.5.3" "version": "==1.5.3"
}, },
"hjson": {
"hashes": [
"sha256:1d1727faa6aaef2973921877125a3ab7c5f6d34b93233179d01770f41fab51f9"
],
"version": "==3.0.1"
},
"idna": { "idna": {
"hashes": [ "hashes": [
"sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4", "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4",
@@ -222,25 +183,12 @@
], ],
"version": "==2.10" "version": "==2.10"
}, },
"jmespath": { "kombu": {
"hashes": [ "hashes": [
"sha256:f11b4461f425740a1d908e9a3f7365c3d2e569f6ca68a2ff8bc5bcd9676edd63", "sha256:01f0da9fe222a2183345004243d1518c0fbe5875955f1b24842f2d9c65709ade",
"sha256:6a81d4c9aa62caf061cb517b4d9ad1dd300374cd4706997aff9cd6aedd61fc64" "sha256:4249d9dd9dbf1fcec471d1c2def20653c9310dd1a217272d77e4844f9d5273cb"
], ],
"version": "==0.9.3" "version": "==4.1.0"
},
"kappa": {
"hashes": [
"sha256:4d6b7b3accce4a0aaaac92b36237a6304f0f2fffbbe3caea3f7c9f52d12c9989",
"sha256:4b5b372872f25d619e427e04282551048dc975a107385b076b3ffc6406a15833"
],
"version": "==0.6.0"
},
"lambda-packages": {
"hashes": [
"sha256:cbe35f0642206a4adfb4855f80d55e273bdacc083011eba5f9ed3beedf0879fa"
],
"version": "==0.19.0"
}, },
"mako": { "mako": {
"hashes": [ "hashes": [
@@ -302,12 +250,6 @@
], ],
"version": "==0.22.0" "version": "==0.22.0"
}, },
"placebo": {
"hashes": [
"sha256:8aa848b892924786fa5e37e75524e8ec039b7d54860d35c51ffb4ed3e30590c5"
],
"version": "==0.8.1"
},
"protobuf": { "protobuf": {
"hashes": [ "hashes": [
"sha256:ac0067e3c60737865ed72bb7416e02297d229d960902802d874c0e167128c809", "sha256:ac0067e3c60737865ed72bb7416e02297d229d960902802d874c0e167128c809",
@@ -401,10 +343,10 @@
}, },
"python-dateutil": { "python-dateutil": {
"hashes": [ "hashes": [
"sha256:95511bae634d69bc7329ba55e646499a842bc4ec342ad54a8cdb65645a0aad3c", "sha256:3220490fb9741e2342e1cf29a503394fdac874bc39568288717ee67047ff29df",
"sha256:891c38b2a02f5bb1be3e4793866c8df49c7d19baabf9c1bad62547e0b4866aca" "sha256:9d8074be4c993fbe4947878ce593052f71dac82932a677d49194d8ce9778002e"
], ],
"version": "==2.6.1" "version": "==2.7.2"
}, },
"python-editor": { "python-editor": {
"hashes": [ "hashes": [
@@ -412,13 +354,6 @@
], ],
"version": "==1.0.3" "version": "==1.0.3"
}, },
"python-slugify": {
"hashes": [
"sha256:c3733135d3b184196fdb8844f6a74bbfb9cf6720d1dcce3254bdc434353f938f",
"sha256:57a385df7a1c6dbd15f7666eaff0ff29d3f60363b228b1197c5308ed3ba5f824"
],
"version": "==1.2.4"
},
"pytz": { "pytz": {
"hashes": [ "hashes": [
"sha256:65ae0c8101309c45772196b21b74c46b2e5d11b6275c45d251b150d5da334555", "sha256:65ae0c8101309c45772196b21b74c46b2e5d11b6275c45d251b150d5da334555",
@@ -426,24 +361,12 @@
], ],
"version": "==2018.4" "version": "==2018.4"
}, },
"pyyaml": { "redis": {
"hashes": [ "hashes": [
"sha256:3262c96a1ca437e7e4763e2843746588a965426550f3797a79fca9c6199c431f", "sha256:8a1900a9f2a0a44ecf6e8b5eb3e967a9909dfed219ad66df094f27f7d6f330fb",
"sha256:16b20e970597e051997d90dc2cddc713a2876c47e3d92d59ee198700c5427736", "sha256:a22ca993cea2962dbb588f9f30d0015ac4afcc45bee27d3978c0dbe9e97c6c0f"
"sha256:e863072cdf4c72eebf179342c94e6989c67185842d9997960b3e69290b2fa269",
"sha256:bc6bced57f826ca7cb5125a10b23fd0f2fff3b7c4701d64c439a300ce665fff8",
"sha256:c01b880ec30b5a6e6aa67b09a2fe3fb30473008c85cd6a67359a1b15ed6d83a4",
"sha256:827dc04b8fa7d07c44de11fabbc888e627fa8293b695e0f99cb544fdfa1bf0d1",
"sha256:592766c6303207a20efc445587778322d7f73b161bd994f227adaa341ba212ab",
"sha256:5f84523c076ad14ff5e6c037fe1c89a7f73a3e04cf0377cb4d017014976433f3",
"sha256:0c507b7f74b3d2dd4d1322ec8a94794927305ab4cebbe89cc47fe5e81541e6e8",
"sha256:b4c423ab23291d3945ac61346feeb9a0dc4184999ede5e7c43e1ffb975130ae6",
"sha256:ca233c64c6e40eaa6c66ef97058cdc80e8d0157a443655baa1b2966e812807ca",
"sha256:4474f8ea030b5127225b8894d626bb66c01cda098d47a2b0d3429b6700af9fd8",
"sha256:326420cbb492172dec84b0f65c80942de6cedb5233c413dd824483989c000608",
"sha256:5ac82e411044fb129bae5cfbeb3ba626acb2af31a8d17d175004b70862a741a7"
], ],
"version": "==3.12" "version": "==2.10.6"
}, },
"requests": { "requests": {
"hashes": [ "hashes": [
@@ -459,13 +382,6 @@
], ],
"version": "==3.4.2" "version": "==3.4.2"
}, },
"s3transfer": {
"hashes": [
"sha256:c7a9ec356982d5e9ab2d4b46391a7d6a950e2b04c472419f5fdec70cc0ada72f",
"sha256:90dc18e028989c609146e241ea153250be451e05ecc0c2832565231dacdf59c1"
],
"version": "==0.1.13"
},
"six": { "six": {
"hashes": [ "hashes": [
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb", "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb",
@@ -475,35 +391,9 @@
}, },
"sqlalchemy": { "sqlalchemy": {
"hashes": [ "hashes": [
"sha256:7cb00cc9b9f92ef8b4391c8a2051f81eeafefe32d63c6b395fd51401e9a39edb" "sha256:d6cda03b0187d6ed796ff70e87c9a7dce2c2c9650a7bc3c022cd331416853c31"
], ],
"version": "==1.2.6" "version": "==1.2.7"
},
"toml": {
"hashes": [
"sha256:8e86bd6ce8cc11b9620cb637466453d94f5d57ad86f17e98a98d1f73e3baab2d"
],
"version": "==0.9.4"
},
"tqdm": {
"hashes": [
"sha256:ba650e08b8b102923a05896bf9d7e1c9cdc20b484156df0511a4bbf1f6b6f89b",
"sha256:fa6d2ea6285f56e75d7efe9259805deadc450f16066a1f82ad0629ea9be2cd0f"
],
"version": "==4.19.1"
},
"troposphere": {
"hashes": [
"sha256:e15e2470fe4f02a5c1b70ccd552b09ac664acfff0de74cd4464acf8e6039e118"
],
"version": "==2.2.1"
},
"unidecode": {
"hashes": [
"sha256:72f49d3729f3d8f5799f710b97c1451c5163102e76d64d20e170aedbbd923582",
"sha256:8c33dd588e0c9bc22a76eaa0c715a5434851f726131bd44a6c26471746efabf5"
],
"version": "==1.0.22"
}, },
"urllib3": { "urllib3": {
"hashes": [ "hashes": [
@@ -512,38 +402,25 @@
], ],
"version": "==1.22" "version": "==1.22"
}, },
"vine": {
"hashes": [
"sha256:6849544be74ec3638e84d90bc1cf2e1e9224cc10d96cd4383ec3f69e9bce077b",
"sha256:52116d59bc45392af9fdd3b75ed98ae48a93e822cee21e5fda249105c59a7a72"
],
"version": "==1.1.4"
},
"werkzeug": { "werkzeug": {
"hashes": [ "hashes": [
"sha256:7fce5d96278e9e4132fd0e90ff17d2bcc6e74695d11e619ba4645c0341396810", "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b",
"sha256:f007848ed997101cb5c09a47e46c0b0b6f193d0f8a01cd2af920d77bf1ab4e68" "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c"
], ],
"version": "==0.12" "version": "==0.14.1"
},
"wheel": {
"hashes": [
"sha256:9cdc8ab2cc9c3c2e2727a4b67c22881dbb0e1c503d592992594c5e131c867107",
"sha256:1ae8153bed701cb062913b72429bcf854ba824f973735427681882a688cb55ce"
],
"version": "==0.31.0"
},
"wsgi-request-logger": {
"hashes": [
"sha256:445d7ec52799562f812006394d0b4a7064b37084c6ea6bd74ea7a2136c97ed83"
],
"version": "==0.4.6"
}, },
"wtforms": { "wtforms": {
"hashes": [ "hashes": [
"sha256:ffdf10bd1fa565b8233380cb77a304cd36fd55c73023e91d4b803c96bc11d46f" "sha256:ffdf10bd1fa565b8233380cb77a304cd36fd55c73023e91d4b803c96bc11d46f"
], ],
"version": "==2.1" "version": "==2.1"
},
"zappa": {
"hashes": [
"sha256:cf4654dfa7cd8777403ea2e379139b126c7e47943edb4e5441bb222a555a1aff",
"sha256:827c2c1cc84790674476a98773601b924a2b4f3b0b81684571cd034326231158"
],
"version": "==0.45.1"
} }
}, },
"develop": {} "develop": {}

View File

@@ -5,3 +5,13 @@ A simple analytics dashboard for aggregate data on PyPI downloads. PyPI Stats
is built using Flask with plotly.js and deployed to AWS using Zappa. is built using Flask with plotly.js and deployed to AWS using Zappa.
`PyPI Stats <https://pypistats.org/>`_ `PyPI Stats <https://pypistats.org/>`_
Commands
--------
Beat:
pipenv run celery beat -A pypistats.run.celery --loglevel=INFO
Celery worker:
pipenv run celery -A pypistats.run.celery worker --loglevel=INFO

34
docker-compose.yaml Normal file
View File

@@ -0,0 +1,34 @@
version: '3'
services:
redis:
image: 'redis:alpine'
restart: always
command: redis-server
ports:
- '6379:6379'
flask:
build: .
restart: always
environment:
- FLASK_APP=pypistats/run.py
- ENV=prod
command: 'flask run --host=0.0.0.0'
ports:
- '5000:5000'
celery:
build: .
restart: always
command: 'celery -A pypistats.run.celery worker -l info'
user: nobody
depends_on:
- redis
beat:
build: .
restart: always
command: 'celery beat -A pypistats.run.celery -l info'
depends_on:
- redis

View File

@@ -1,4 +1,6 @@
"""PyPIStats application.""" """PyPIStats application."""
from celery import Celery
from celery import Task
from flask import Flask from flask import Flask
from pypistats import views from pypistats import views
@@ -9,22 +11,29 @@ from pypistats.settings import DevConfig
def create_app(config_object=DevConfig): def create_app(config_object=DevConfig):
"""Create the application. """Create the application."""
app = Flask(__name__.split(".")[0])
:param config_object: The configuration object to use.
"""
app = Flask(__name__.split('.')[0])
app.config.from_object(config_object) app.config.from_object(config_object)
register_extensions(app) register_extensions(app)
register_blueprints(app) register_blueprints(app)
return app return app
def register_extensions(app): def create_celery(app):
"""Register Flask extensions.""" """Create a celery object."""
db.init_app(app) celery = Celery(app.import_name, broker=app.config["CELERY_BROKER_URL"])
github.init_app(app) celery.conf.update(app.config)
migrate.init_app(app, db) celery.config_from_object(app.config)
class ContextTask(Task):
abstract = True
def __call__(self, *args, **kwargs):
with app.app_context():
return Task.__call__(self, *args, **kwargs)
celery.Task = ContextTask
return celery
def register_blueprints(app): def register_blueprints(app):
@@ -33,3 +42,10 @@ def register_blueprints(app):
app.register_blueprint(views.error.blueprint) app.register_blueprint(views.error.blueprint)
app.register_blueprint(views.general.blueprint) app.register_blueprint(views.general.blueprint)
app.register_blueprint(views.user.blueprint) app.register_blueprint(views.user.blueprint)
def register_extensions(app):
"""Register Flask extensions."""
db.init_app(app)
github.init_app(app)
migrate.init_app(app, db)

View File

@@ -41,13 +41,13 @@ class Model(CRUDMixin, db.Model):
class SurrogatePK(object): class SurrogatePK(object):
"""A mixin that adds a surrogate integer 'primary key' column. """A mixin that adds a surrogate integer "primary key" column.
Adds a surrogate integer 'primary key' column named ``id`` to any Adds a surrogate integer "primary key" column named ``id`` to any
declarative-mapped class. declarative-mapped class.
""" """
__table_args__ = {'extend_existing': True} __table_args__ = {"extend_existing": True}
id = Column(db.Integer, primary_key=True) id = Column(db.Integer, primary_key=True)

View File

@@ -5,6 +5,7 @@ from flask import g
from flask import session from flask import session
from pypistats.application import create_app from pypistats.application import create_app
from pypistats.application import create_celery
from pypistats.models.user import User from pypistats.models.user import User
from pypistats.settings import configs from pypistats.settings import configs
@@ -12,8 +13,9 @@ from pypistats.settings import configs
# change this for migrations # change this for migrations
env = os.environ.get("ENV", "dev") env = os.environ.get("ENV", "dev")
print(env)
app = create_app(configs[env]) app = create_app(configs[env])
celery = create_celery(app)
@app.before_request @app.before_request
@@ -21,4 +23,4 @@ def before_request():
"""Execute before requests.""" """Execute before requests."""
g.user = None g.user = None
if "user_id" in session: if "user_id" in session:
g.user = User.query.get(session['user_id']) g.user = User.query.get(session["user_id"])

View File

@@ -2,6 +2,8 @@
import json import json
import os import os
from celery.schedules import crontab
# For local use. # For local use.
def load_env_vars(env="dev"): def load_env_vars(env="dev"):
@@ -10,7 +12,7 @@ def load_env_vars(env="dev"):
os.path.dirname(os.path.abspath(__file__)), os.path.dirname(os.path.abspath(__file__)),
"secret", "secret",
f"env_vars_{env}.json") f"env_vars_{env}.json")
for key, value in json.load(open(local_path, 'r')).items(): for key, value in json.load(open(local_path, "r")).items():
os.environ[key] = value os.environ[key] = value
@@ -30,6 +32,14 @@ class Config(object):
"""Base configuration.""" """Base configuration."""
APP_DIR = os.path.abspath(os.path.dirname(__file__)) APP_DIR = os.path.abspath(os.path.dirname(__file__))
CELERY_BROKER_URL = os.environ.get("CELERY_BROKER_URL"),
CELERY_IMPORTS = ("pypistats.tasks.pypi")
CELERYBEAT_SCHEDULE = {
"update_db": {
"task": "pypistats.tasks.pypi.etl",
"schedule": crontab(hour=1, minute=0), # 1am UTC
},
}
GITHUB_CLIENT_ID = os.environ.get("GITHUB_CLIENT_ID") GITHUB_CLIENT_ID = os.environ.get("GITHUB_CLIENT_ID")
GITHUB_CLIENT_SECRET = os.environ.get("GITHUB_CLIENT_SECRET") GITHUB_CLIENT_SECRET = os.environ.get("GITHUB_CLIENT_SECRET")
PROJECT_ROOT = os.path.abspath(os.path.join(APP_DIR, os.pardir)) PROJECT_ROOT = os.path.abspath(os.path.join(APP_DIR, os.pardir))

View File

@@ -11,6 +11,8 @@ import pandas as pd
import psycopg2 import psycopg2
from psycopg2.extras import execute_values from psycopg2.extras import execute_values
from pypistats.run import celery
# For local use. # For local use.
def load_env_vars(env="dev"): def load_env_vars(env="dev"):
@@ -29,16 +31,6 @@ MIRRORS = ("bandersnatch", "z3c.pypimirror", "Artifactory", "devpi")
# PyPI systems # PyPI systems
SYSTEMS = ("Windows", "Linux", "Darwin") SYSTEMS = ("Windows", "Linux", "Darwin")
# BigQuery definitions
DATASET_ID = "pypistats"
TABLE_ID = "pypistats"
SCHEMA = [
bigquery.SchemaField("package", "STRING", mode="REQUIRED"),
bigquery.SchemaField("category_label", "STRING", mode="REQUIRED"),
bigquery.SchemaField("category", "STRING", mode="NULLABLE"),
bigquery.SchemaField("downloads", "INTEGER", mode="NULLABLE"),
]
# postgresql tables to update for __all__ # postgresql tables to update for __all__
PSQL_TABLES = ["overall", "python_major", "python_minor", "system"] PSQL_TABLES = ["overall", "python_major", "python_minor", "system"]
@@ -69,63 +61,28 @@ def get_google_credentials():
return credentials return credentials
def get_daily_download_stats(event, context): def get_daily_download_stats(env="dev", date=None):
"""Get daily download stats for pypi packages from BigQuery.""" """Get daily download stats for pypi packages from BigQuery."""
start = time.time() start = time.time()
env = event["kwargs"]["env"]
if os.environ.get("ENV", None) is None: if os.environ.get("ENV", None) is None:
load_env_vars(env) load_env_vars(env)
else:
env = os.environ.get("ENV")
job_config = bigquery.QueryJobConfig() job_config = bigquery.QueryJobConfig()
credentials = get_google_credentials() credentials = get_google_credentials()
bq_client = bigquery.Client( bq_client = bigquery.Client(
project=os.environ["GOOGLE_PROJECT_ID"], project=os.environ["GOOGLE_PROJECT_ID"],
credentials=credentials credentials=credentials
) )
date = event["kwargs"].get("date", None)
if date is None: if date is None:
date = str(datetime.date.today() - datetime.timedelta(days=1)) date = str(datetime.date.today() - datetime.timedelta(days=1))
# # Prepare a reference to the new dataset print("Sending query to BigQuery...")
# dataset_ref = bq_client.dataset(DATASET_ID)
# dataset = bigquery.Dataset(dataset_ref)
#
# # Create the dataset
# try:
# dataset = bq_client.create_dataset(dataset)
# except Conflict:
# pass
#
# # Prepare a reference to the table
# table_ref = dataset_ref.table(TABLE_ID)
# table = bigquery.Table(table_ref, schema=SCHEMA)
#
# # Create the table
# try:
# table = bq_client.create_table(table)
# except Conflict:
# pass
# local = False
# if env == "dev":
# try:
# print("Loading from csv...")
# df = pd.read_csv("ignore/sample_data.csv", index_col=0)
# print("Done.")
# # print(set(df["category_label"].values))
# # sys.exit()
# local = True
# except Exception:
# print("Loading failed.")
# if not local:
print("Querying BigQuery...")
# Get and perform the query, writing to destination table
query = get_query(date) query = get_query(date)
print("Done.") print("Sent.")
# job_config.destination = table_ref
# job_config.write_disposition = "WRITE_TRUNCATE"
query_job = bq_client.query(query, job_config=job_config) query_job = bq_client.query(query, job_config=job_config)
iterator = query_job.result() iterator = query_job.result()
print("Downloading results.")
rows = list(iterator) rows = list(iterator)
print(len(rows), "rows from gbq") print(len(rows), "rows from gbq")
@@ -147,11 +104,9 @@ def get_daily_download_stats(event, context):
"downloads", "downloads",
]) ])
# # For local testing
# df.to_csv("ignore/sample_data.csv")
results = update_db(df, env) results = update_db(df, env)
print("Elapsed: " + str(time.time() - start)) print("Elapsed: " + str(time.time() - start))
results["elapsed"] = time.time() - start
return results return results
@@ -174,9 +129,6 @@ def update_db(df, env="dev"):
success[table] = update_table( success[table] = update_table(
connection, cursor, table, df_category, date connection, cursor, table, df_category, date
) )
# update_all_package_stats(cursor, table, date)
# update_recent_stats(cursor, date)
return success return success
@@ -205,18 +157,18 @@ def update_table(connection, cursor, table, df, date):
return False return False
def update_all_package_stats(event, context): def update_all_package_stats(env="dev", date=None):
"""Update stats for __all__ packages.""" """Update stats for __all__ packages."""
print("__all__") print("__all__")
start = time.time() start = time.time()
date = event["kwargs"].get("date", None)
if date is None: if date is None:
date = str(datetime.date.today() - datetime.timedelta(days=1)) date = str(datetime.date.today() - datetime.timedelta(days=1))
env = event["kwargs"]["env"]
if os.environ.get("ENV", None) is None: if os.environ.get("ENV", None) is None:
load_env_vars(env) load_env_vars(env)
else:
env = os.environ.get("ENV")
connection, cursor = get_connection_cursor(env) connection, cursor = get_connection_cursor(env)
@@ -246,21 +198,22 @@ def update_all_package_stats(event, context):
success[table] = False success[table] = False
print("Elapsed: " + str(time.time() - start)) print("Elapsed: " + str(time.time() - start))
success["elapsed"] = time.time() - start
return success return success
def update_recent_stats(event, context): def update_recent_stats(env="dev", date=None):
"""Update daily, weekly, monthly stats for all packages.""" """Update daily, weekly, monthly stats for all packages."""
print("recent") print("recent")
start = time.time() start = time.time()
date = event["kwargs"].get("date", None)
if date is None: if date is None:
date = str(datetime.date.today() - datetime.timedelta(days=1)) date = str(datetime.date.today() - datetime.timedelta(days=1))
env = event["kwargs"]["env"]
if os.environ.get("ENV", None) is None: if os.environ.get("ENV", None) is None:
load_env_vars(env) load_env_vars(env)
else:
env = os.environ.get("ENV")
connection, cursor = get_connection_cursor(env) connection, cursor = get_connection_cursor(env)
@@ -305,6 +258,7 @@ def update_recent_stats(event, context):
success[period] = False success[period] = False
print("Elapsed: " + str(time.time() - start)) print("Elapsed: " + str(time.time() - start))
success["elapsed"] = time.time() - start
return success return success
@@ -322,19 +276,19 @@ def get_connection_cursor(env):
return connection, cursor return connection, cursor
def purge_old_data(event, context): def purge_old_data(env="dev", date=None):
"""Purge old data records.""" """Purge old data records."""
print("Purge") print("Purge")
age = MAX_RECORD_AGE age = MAX_RECORD_AGE
start = time.time() start = time.time()
date = event["kwargs"].get("date", None)
if date is None: if date is None:
date = str(datetime.date.today() - datetime.timedelta(days=1)) date = str(datetime.date.today() - datetime.timedelta(days=1))
env = event["kwargs"]["env"]
if os.environ.get("ENV", None) is None: if os.environ.get("ENV", None) is None:
load_env_vars(env) load_env_vars(env)
else:
env = os.environ.get("ENV")
connection, cursor = get_connection_cursor(env) connection, cursor = get_connection_cursor(env)
@@ -355,6 +309,7 @@ def purge_old_data(event, context):
success[table] = False success[table] = False
print("Elapsed: " + str(time.time() - start)) print("Elapsed: " + str(time.time() - start))
success["elapsed"] = time.time() - start
return success return success
@@ -449,17 +404,28 @@ def get_query(date):
""" """
if __name__ == "__main__": @celery.task
date = "2018-04-18" def etl():
env = "prod" """Perform the stats download."""
event = { results = {
"kwargs": { "downloads": get_daily_download_stats(),
"date": date, "__all__": update_all_package_stats(),
"env": env, "recent": update_recent_stats(),
} "purge": purge_old_data(),
} }
context = None return results
@celery.task
def test():
"""Test task for celery/beat."""
print("hello test.")
if __name__ == "__main__":
date = "2018-04-19"
env = "prod"
print(date, env) print(date, env)
print(get_daily_download_stats(event, context)) print(get_daily_download_stats(env, date))
print(update_all_package_stats(event, context)) print(update_all_package_stats(env, date))
print(update_recent_stats(event, context)) print(update_recent_stats(env, date))

View File

@@ -25,10 +25,6 @@
Host: Host:
<a href="{{url_for('general.package', package='awscli')}}">AWS</a> <a href="{{url_for('general.package', package='awscli')}}">AWS</a>
</li> </li>
<li>
Deployment:
<a href="{{url_for('general.package', package='zappa')}}">Zappa</a>
</li>
<li>Authentication: <li>Authentication:
<a href="{{url_for('general.package', package='github-flask')}}">GitHub OAuth</a> <a href="{{url_for('general.package', package='github-flask')}}">GitHub OAuth</a>
</li> </li>
@@ -65,4 +61,4 @@
<a href="https://flynn.gg">Christopher Flynn</a>. <a href="https://flynn.gg">Christopher Flynn</a>.
</p> </p>
{% endblock %} {% endblock %}

View File

@@ -12,8 +12,7 @@
gtag('config', 'UA-101875606-5'); gtag('config', 'UA-101875606-5');
</script> </script>
<!-- <script type="text/javascript"> // var host = "example.com"; // if ((host == window.location.host) && (window.location.protocol != "https:")) // window.location.protocol = "https"; </script> --> <!-- <script type="text/javascript"> // var host = "example.com"; // if ((host == window.location.host) && (window.location.protocol != "https:")) // window.location.protocol = "https"; </script> -->
<!-- <link rel="stylesheet" href="/static/style.css"> --> <link rel="stylesheet" href="/static/style.css">
<style>a small,a:hover small{color:#777}dt,th{color:#444}dl,hr,ol,p,pre,table,ul{margin:0 0 20px}.btn,.btn:hover,a{text-decoration:none}body{background-color:#fff;padding:.4in;font:16px/1.5 "Noto Sans","Helvetica Neue",Helvetica,Arial,sans-serif;color:#727272;font-weight:400;overflow:auto}footer,header{float:left;position:fixed;-webkit-font-smoothing:subpixel-antialiased}dt,strong{font-weight:700}h1,h2,h3,h4,h5,h6{color:#222;margin:0 0 20px}h1,h2,h3{line-height:1.1}h1{font-size:28px}h2{color:#393939}h3,h4,h5,h6{color:#494949}a{color:#39c}a:hover{color:#069}a small{font-size:11px;margin-top:-.3em;display:block}blockquote{border-left:1px solid #e5e5e5;margin:0;padding:0 0 0 20px;font-style:italic}code,pre{font-family:Monaco,Bitstream Vera Sans Mono,Lucida Console,Terminal,Consolas,Liberation Mono,DejaVu Sans Mono,Courier New,monospace;color:#333;font-size:12px}pre{padding:5px;background:#f8f8f8;border-radius:5px;border:1px solid #e5e5e5;overflow-x:auto}table{border-collapse:collapse}td,th{text-align:left;padding:2px 10px;border-bottom:1px solid #e5e5e5}img{max-width:100%}header{width:200px}header ul{list-style:none;height:40px;padding:0;background:#f4f4f4;border-radius:5px;border:1px solid #e0e0e0;width:270px}header li{width:89px;float:left;border-right:1px solid #e0e0e0;height:40px}header li:first-child a{border-radius:5px 0 0 5px}header li:last-child a{border-radius:0 5px 5px 0}header ul a{line-height:1;font-size:11px;color:#999;display:block;text-align:center;padding-top:6px;height:34px}header ul a:hover{color:#999}header ul a:active{background-color:#f0f0f0}strong{color:#222}header ul li+li+li{border-right:none;width:89px}header ul a strong{font-size:14px;display:block;color:#222}section{padding-left:225px;padding-bottom:20px}small{font-size:11px}hr{border:0;background:#e5e5e5;height:1px}footer{width:200px;bottom:20px}.btn{background:#f5c56c;background-image:-webkit-linear-gradient(top,#f5c56c,#b8842b);background-image:-moz-linear-gradient(top,#f5c56c,#b8842b);background-image:-ms-linear-gradient(top,#f5c56c,#b8842b);background-image:-o-linear-gradient(top,#f5c56c,#b8842b);background-image:linear-gradient(to bottom,#f5c56c,#b8842b);-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;text-shadow:1px 1px 3px #666;font-family:Arial;color:#fff;font-size:14px;padding:5px 10px}.btn:hover{background:#e08c43;background-image:-webkit-linear-gradient(top,#e08c43,#de9347);background-image:-moz-linear-gradient(top,#e08c43,#de9347);background-image:-ms-linear-gradient(top,#e08c43,#de9347);background-image:-o-linear-gradient(top,#e08c43,#de9347);background-image:linear-gradient(to bottom,#e08c43,#de9347)}@media print,screen and (max-width:960px){body{padding:0}div.wrapper{width:auto;margin:0}footer,header,section{float:none;position:static;width:auto}header{padding-right:320px}section{border:1px solid #e5e5e5;border-width:1px 0;padding:20px 0;margin:0 0 20px}header a small{display:inline}header ul{position:absolute;right:50px;top:52px}}@media print,screen and (max-width:720px){body{word-wrap:break-word}header{padding:0}header p.view,header ul{position:static}code,pre{word-wrap:normal}}@media print,screen and (max-width:480px){body{padding:0}header ul{width:99%}header li,header ul li+li+li{width:33%}}@media print{body{font-size:12pt;color:#444}}</style>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1"> <meta http-equiv="X-UA-Compatible" content="chrome=1">
<title> <title>

View File

@@ -21,7 +21,6 @@ from pypistats.models.download import PythonMinorDownloadCount
from pypistats.models.download import RECENT_CATEGORIES from pypistats.models.download import RECENT_CATEGORIES
from pypistats.models.download import RecentDownloadCount from pypistats.models.download import RecentDownloadCount
from pypistats.models.download import SystemDownloadCount from pypistats.models.download import SystemDownloadCount
from sqlalchemy import distinct
blueprint = Blueprint("general", __name__, template_folder="templates") blueprint = Blueprint("general", __name__, template_folder="templates")
@@ -49,7 +48,6 @@ def index():
return redirect(f"/search/{package}") return redirect(f"/search/{package}")
package_count = \ package_count = \
RecentDownloadCount.query.filter_by(category="month").count() RecentDownloadCount.query.filter_by(category="month").count()
print(package_count)
return render_template( return render_template(
"index.html", "index.html",
form=form, form=form,
@@ -104,7 +102,6 @@ def package(package):
if metadata["info"].get("requires_dist", None): if metadata["info"].get("requires_dist", None):
metadata["requires"] = [] metadata["requires"] = []
for required in metadata["info"]["requires_dist"]: for required in metadata["info"]["requires_dist"]:
print(package, re.split(r"[^0-9a-zA-Z_.-]+", required))
metadata["requires"].append( metadata["requires"].append(
re.split(r"[^0-9a-zA-Z_.-]+", required)[0] re.split(r"[^0-9a-zA-Z_.-]+", required)[0]
) )

44
requirements.txt Normal file
View File

@@ -0,0 +1,44 @@
alembic==0.9.9 --hash=sha256:85bd3ea7633024e4930900bc64fb58f9742dedbc6ebb6ecf25be2ea9a3c1b32e
amqp==2.2.2 --hash=sha256:4e28d3ea61a64ae61830000c909662cb053642efddbe96503db0e7783a6ee85b --hash=sha256:cba1ace9d4ff6049b190d8b7991f9c1006b443a5238021aca96dd6ad2ac9da22
billiard==3.5.0.3 --hash=sha256:abd9ce008c9a71ccde2c816f8daa36246e92a21e6a799831b887d88277187ecd --hash=sha256:1d7b22bdc47aa52841120fcd22a74ae4fc8c13e9d3935643098184f5788c3ce6
cachetools==2.0.1 --hash=sha256:4319bbb78172e7bcf99423e1ecd6914b32336ccfe97d2058ffe62e641a7f3abe --hash=sha256:ede01f2d3cbd6ddc9e35e16c2b0ce011d8bb70ce0dbaf282f5b4df24b213bc5d
celery==4.1.0 --hash=sha256:81a67f0d53a688ec2bc8557bd5d6d7218f925a6f2e6df80e01560de9e28997ec --hash=sha256:77ff3730198d6a17b3c1f05579ebe570b579efb35f6d7e13dba3b1368d068b35
certifi==2018.4.16 --hash=sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0 --hash=sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7
chardet==3.0.4 --hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691 --hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae
click==6.7 --hash=sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d --hash=sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b
flask==0.12.2 --hash=sha256:0749df235e3ff61ac108f69ac178c9770caeaccad2509cb762ce1f65570a8856 --hash=sha256:49f44461237b69ecd901cc7ce66feea0319b9158743dd27a2899962ab214dac1
flask-login==0.4.1 --hash=sha256:c815c1ac7b3e35e2081685e389a665f2c74d7e077cb93cecabaea352da4752ec
flask-migrate==2.1.1 --hash=sha256:493f9b3795985b9b4915bf3b7d16946697f027b73545384e7d9e3a79f989d2fe --hash=sha256:b709ca8642559c3c5a81a33ab10839fa052177accd5ba821047a99db635255ed
flask-sqlalchemy==2.3.2 --hash=sha256:3bc0fac969dd8c0ace01b32060f0c729565293302f0c4269beed154b46bec50b --hash=sha256:5971b9852b5888655f11db634e87725a9031e170f37c0ce7851cf83497f56e53
flask-wtf==0.14.2 --hash=sha256:d9a9e366b32dcbb98ef17228e76be15702cd2600675668bca23f63a7947fd5ac --hash=sha256:5d14d55cfd35f613d99ee7cba0fc3fbbe63ba02f544d349158c14ca15561cc36
github-flask==3.2.0 --hash=sha256:24600b720f698bac10667b76b136995ba7821d884e58b27e2a18ca0e4760c786
google-api-core==1.1.1 --hash=sha256:4885e5298e45aa587185c32bee54f95e79a05a926d69fcfd398c66b12b98b9a7 --hash=sha256:d23d5ae89e44ca1ddddec94e5f7c03f52402d192e66345d448b77ad5276b0fbe
google-auth==1.4.1 --hash=sha256:34088434cb2a2409360b8f3cbc04195a465df1fb2aafad71ebbded77cbf08803 --hash=sha256:9051802d3dae256036cca9e34633a32c0ed1427730d4ebc513dff91ec8b6dd45
google-cloud-bigquery==1.1.0 --hash=sha256:44d152e1de60cce8fe9d4f5c60ca4cebc88daab02b4d889bb0ebfcc19d54d7ec --hash=sha256:aed2b1d4db1e21d891522d6d6bb14476e6ba58c681cbb68eeb42c168a4e3fda9
google-cloud-core==0.28.1 --hash=sha256:0090df83dbc5cb2405fa90844366d13176d1c0b48181c1807ab15f53be403f73 --hash=sha256:89e8140a288acec20c5e56159461d3afa4073570c9758c05d4e6cb7f2f8cc440
google-resumable-media==0.3.1 --hash=sha256:116de90b9cd483b17c53618ee6a5a20f33e741c648140c8cc9c2141e07616ff1 --hash=sha256:97de518f8166d442cc0b61fab308bcd319dbb970981e667ec8ded44f5ce49836
googleapis-common-protos==1.5.3 --hash=sha256:c075eddaa2628ab519e01b7d75b76e66c40eaa50fc52758d8225f84708950ef2
idna==2.6 --hash=sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4 --hash=sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f
itsdangerous==0.24 --hash=sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519
jinja2==2.10 --hash=sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd --hash=sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4
kombu==4.1.0 --hash=sha256:01f0da9fe222a2183345004243d1518c0fbe5875955f1b24842f2d9c65709ade --hash=sha256:4249d9dd9dbf1fcec471d1c2def20653c9310dd1a217272d77e4844f9d5273cb
mako==1.0.7 --hash=sha256:4e02fde57bd4abb5ec400181e4c314f56ac3e49ba4fb8b0d50bba18cb27d25ae
markupsafe==1.0 --hash=sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665
numpy==1.14.2 --hash=sha256:719d914f564f35cce4dc103808f8297c807c9f0297ac183ed81ae8b5650e698e --hash=sha256:0f6a5ed0cd7ab1da11f5c07a8ecada73fc55a70ef7bb6311a4109891341d7277 --hash=sha256:d0928076d9bd8a98de44e79b1abe50c1456e7abbb40af7ef58092086f1a6c729 --hash=sha256:d858423f5ed444d494b15c4cc90a206e1b8c31354c781ac7584da0d21c09c1c3 --hash=sha256:20cac3123d791e4bf8482a580d98d6b5969ba348b9d5364df791ba3a666b660d --hash=sha256:528ce59ded2008f9e8543e0146acb3a98a9890da00adf8904b1e18c82099418b --hash=sha256:56e392b7c738bd70e6f46cf48c8194d3d1dd4c5a59fae4b30c58bb6ef86e5233 --hash=sha256:99051e03b445117b26028623f1a487112ddf61a09a27e2d25e6bc07d37d94f25 --hash=sha256:768e777cc1ffdbf97c507f65975c8686ebafe0f3dc8925d02ac117acc4669ce9 --hash=sha256:675e0f23967ce71067d12b6944add505d5f0a251f819cfb44bdf8ee7072c090d --hash=sha256:a958bf9d4834c72dee4f91a0476e7837b8a2966dc6fcfc42c421405f98d0da51 --hash=sha256:bb370120de6d26004358611441e07acda26840e41dfedc259d7f8cc613f96495 --hash=sha256:f2b1378b63bdb581d5d7af2ec0373c8d40d651941d283a2afd7fc71184b3f570 --hash=sha256:a1413d06abfa942ca0553bf3bccaff5fdb36d55b84f2248e36228db871147dab --hash=sha256:7f76d406c6b998d6410198dcb82688dcdaec7d846aa87e263ccf52efdcfeba30 --hash=sha256:a7157c9ac6bddd2908c35ef099e4b643bc0e0ebb4d653deb54891d29258dd329 --hash=sha256:0fd65cbbfdbf76bbf80c445d923b3accefea0fe2c2082049e0ce947c81fe1d3f --hash=sha256:8c18ee4dddd5c6a811930c0a7c7947bf16387da3b394725f6063f1366311187d --hash=sha256:0739146eaf4985962f07c62f7133aca89f3a600faac891ce6c7f3a1e2afe5272 --hash=sha256:07e21f14490324cc1160db101e9b6c1233c33985af4cb1d301dd02650fea1d7f --hash=sha256:e6120d63b50e2248219f53302af7ec6fa2a42ed1f37e9cda2c76dbaca65036a7 --hash=sha256:6be6b0ca705321c178c9858e5ad5611af664bbdfae1df1541f938a840a103888 --hash=sha256:facc6f925c3099ac01a1f03758100772560a0b020fb9d70f210404be08006bcb
pandas==0.22.0 --hash=sha256:68ac484e857dcbbd07ea7c6f516cc67f7f143f5313d9bc661470e7f473528882 --hash=sha256:12f2a19d0b0adf31170d98d0e8bcbc59add0965a9b0c65d39e0665400491c0c5 --hash=sha256:68b121d13177f5128a4c118bb4f73ba40df28292c038389961aa55ea5a996427 --hash=sha256:06efae5c00b9f4c6e6d3fe1eb52e590ff0ea8e5cb58032c724e04d31c540de53 --hash=sha256:02541a4fdd31315f213a5c8e18708abad719ee03eda05f603c4fe973e9b9d770 --hash=sha256:2907f3fe91ca2119ac3c38de6891bbbc83333bfe0d98309768fee28de563ee7a --hash=sha256:052a66f58783a59ea38fdfee25de083b107baa81fdbe38fabd169d0f9efce2bf --hash=sha256:244ae0b9e998cfa88452a49b20e29bf582cc7c0e69093876d505aec4f8e1c7fe --hash=sha256:66403162c8b45325a995493bdd78ad4d8be085e527d721dbfa773d56fbba9c88 --hash=sha256:af0dbac881f6f87acd325415adea0ce8cccf28f5d4ad7a54b6a1e176e2f7bf70 --hash=sha256:c2cd884794924687edbaad40d18ac984054d247bb877890932c4d41e3c3aba31 --hash=sha256:c372db80a5bcb143c9cb254d50f902772c3b093a4f965275197ec2d2184b1e61 --hash=sha256:97c8223d42d43d86ca359a57b4702ca0529c6553e83d736e93a5699951f0f8db --hash=sha256:587a9816cc663c958fcff7907c553b73fe196604f990bc98e1b71ebf07e45b44 --hash=sha256:44a94091dd71f05922eec661638ec1a35f26d573c119aa2fad964f10a2880e6c
protobuf==3.5.2.post1 --hash=sha256:ac0067e3c60737865ed72bb7416e02297d229d960902802d874c0e167128c809 --hash=sha256:5c1c8f6a0a68a874e3beff89255959dd80fad45870e96c88944a1b81a22dd5f5 --hash=sha256:7c193e6964e752bd056735594826c5b03274ceb8f07349d3ae47d9766250ba96 --hash=sha256:bcfa99f5a82f5eaaf6e5cee5bfdca5a1670f5740aec1d93dae170645ed1a16b0 --hash=sha256:e269ab7a50bf0fa6fe6a88ea7dcc7a1079ae9450d9ab9b7730ac32916d55508b --hash=sha256:01ccd6d03449ae75b779fb5bf4ed62177d61afe3c5e6465ccf3f8b2e1a84afbe --hash=sha256:628a3bf0794a8b3cabb18db11eb67cc10e0cc6e5525d557ae7b682bb73fa2018 --hash=sha256:242e4c7ae565267a8bc8b92d707177f915607ea4bd73244bec6cbf4a49b96661 --hash=sha256:e7fd33a3474cbe18fd5b5620784a0fa21fcae3e402b1806e29c6b450c7f61706 --hash=sha256:cc94079ae6cbcea5ae194464a30f3223f075e06a0446f52bca9ddbeb6e9f412a --hash=sha256:7222d6616108b33ad6cbeff8117062a73c43cdc8fa8f64f6a322ebeb663e710e --hash=sha256:3f655e1f99c3e14d56ca900af1b9a4715b691319a295cc38939d7f77eabd5e7c --hash=sha256:76ef6ca3c50e4cfd044861586d5f1b352e0fe7f17f883df6c165bad5b4d0e10a --hash=sha256:560a38e692a69957a70ba0e5839aa67430efd63072bf91b0539dac19055694cd --hash=sha256:d5d9edfdc5a3a01d06062d677b121081629782edf0e05ca1be14f15bb947eeee --hash=sha256:869e12bcfb5759e683f53ec1dd6155b7be034065431da289f0cb4510040a0799 --hash=sha256:905414e5ea6cdb78d8730f66335755152b46685fcb9fc2f2134024e3ea9e8dcc --hash=sha256:adf716a89c9cc1891ead79a861c427071ef59172f0e11967b00565a9547b3bd0 --hash=sha256:1d92cc30b0b46cced33adde5853d920179eb5ea8eecdee9552502a7f29cc3f21 --hash=sha256:3b60685732bd0cbdc802dfcb6071efbcf5d927ce3127c13c33ea1a8efae3aa76
psycopg2==2.7.4 --hash=sha256:aeaba399254ca79c299d9fe6aa811d3c3eac61458dee10270de7f4e71c624998 --hash=sha256:1d90379d01d0dc50ae9b40c863933d87ff82d51dd7d52cea5d1cb7019afd72cd --hash=sha256:36030ca7f4b4519ee4f52a74edc4ec73c75abfb6ea1d80ac7480953d1c0aa3c3 --hash=sha256:7cbc3b21ce2f681ca9ad2d8c0901090b23a30c955e980ebf1006d41f37068a95 --hash=sha256:b178e0923c93393e16646155794521e063ec17b7cc9f943f15b7d4b39776ea2c --hash=sha256:fe6a7f87356116f5ea840c65b032af17deef0e1a5c34013a2962dd6f99b860dd --hash=sha256:6f302c486132f8dd11f143e919e236ea4467d53bf18c451cac577e6988ecbd05 --hash=sha256:888bba7841116e529f407f15c6d28fe3ef0760df8c45257442ec2f14f161c871 --hash=sha256:932a4c101af007cb3132b1f8a9ffef23386acc53dad46536dc5ba43a3235ae02 --hash=sha256:179c52eb870110a8c1b460c86d4f696d58510ea025602cd3f81453746fccb94f --hash=sha256:33f9e1032095e1436fa9ec424abcbd4c170da934fb70e391c5d78275d0307c75 --hash=sha256:092a80da1b052a181b6e6c765849c9b32d46c5dac3b81bf8c9b83e697f3cdbe8 --hash=sha256:f3d3a88128f0c219bdc5b2d9ccd496517199660cea021c560a3252116df91cbd --hash=sha256:19983b77ec1fc2a210092aa0333ee48811fd9fb5f194c6cd5b927ed409aea5f8 --hash=sha256:027ae518d0e3b8fff41990e598bc7774c3d08a3a20e9ecc0b59fb2aaaf152f7f --hash=sha256:363fbbf4189722fc46779be1fad2597e2c40b3f577dc618f353a46391cf5d235 --hash=sha256:d74cf9234ba76426add5e123449be08993a9b13ff434c6efa3a07caa305a619f --hash=sha256:32702e3bd8bfe12b36226ba9846ed9e22336fc4bd710039d594b36bd432ae255 --hash=sha256:8eb94c0625c529215b53c08fb4e461546e2f3fc96a49c13d5474b5ad7aeab6cf --hash=sha256:8ebba5314c609a05c6955e5773c7e0e57b8dd817e4f751f30de729be58fa5e78 --hash=sha256:27467fd5af1dcc0a82d72927113b8f92da8f44b2efbdb8906bd76face95b596d --hash=sha256:b68e89bb086a9476fa85298caab43f92d0a6af135a5f433d1f6b6d82cafa7b55 --hash=sha256:0b9851e798bae024ed1a2a6377a8dab4b8a128a56ed406f572f9f06194e4b275 --hash=sha256:733166464598c239323142c071fa4c9b91c14359176e5ae7e202db6bcc1d2eb5 --hash=sha256:ad75fe10bea19ad2188c5cb5fc4cdf53ee808d9b44578c94a3cd1e9fc2beb656 --hash=sha256:8966829cb0d21a08a3c5ac971a2eb67c3927ae27c247300a8476554cc0ce2ae8 --hash=sha256:8bf51191d60f6987482ef0cfe8511bbf4877a5aa7f313d7b488b53189cf26209
pyasn1==0.4.2 --hash=sha256:f81c96761fca60d64b1c9b79ec2e40cf9495a745cf570613079ef324aeb9672b --hash=sha256:7d626683e3d792cccc608da02498aff37ab4f3dafd8905d6bf755d11f9b26b43 --hash=sha256:e85895087905c65b5b594eb91f7522664c85545b147d5f4d4e7b1b07da8dcbdc --hash=sha256:5a0db897b311d265cde49615cf783f1c78613138605cdd0f907ecfa5b2aba3ee --hash=sha256:d5cd6ed995dba16fad0c521cfe31cd2d68400b53fcc2bce93326829be73ab6d1 --hash=sha256:a7efe807c4b83a859e2735c692b92ed7b567cfddc4163763412920041d876c2b --hash=sha256:b5a9ca48055b9a20f6d1b3d68e38692e5431c86a0f99ea602e61294e891fee5b --hash=sha256:c07d6e587b2f928366b1f67c09bda026a3e6fcc99e80a744dc67f8fca3895626 --hash=sha256:d84c2aea3cf43780e9e6a19f4e4dddee9f6976519020e64e47c57e5c7a8c3dd2 --hash=sha256:758cb50abddc03e4563fd9e7f03db56e3e87b58c0bd01247360326e5c0c7ffa5 --hash=sha256:0d7f6e959fe53f3960a23d73f35e1fce61348b30915b6664309ca756de7c1f89 --hash=sha256:d258b0a71994f7770599835249cece1caef3c70def868c4915e6e5ca49b67d15
pyasn1-modules==0.2.1 --hash=sha256:b1f395cae2d669e0830cb023aa86f9f283b7a9aa32317d7f80d8e78aa2745812 --hash=sha256:854700bbdd01394e2ada9c1bfbd0ed9f5d0c551350dbbd023e88b11d2771ae06 --hash=sha256:598a6004ec26a8ab40a39ea955068cf2a3949ad9c0030da970f2e1ca4c9f1cc9 --hash=sha256:f53fe5bcebdf318f51399b250fe8325ef3a26d927f012cc0c8e0f9e9af7f9deb --hash=sha256:47fb6757ab78fe966e7c58b2030b546854f78416d653163f0ce9290cf2278e8b --hash=sha256:041e9fbafac548d095f5b6c3b328b80792f006196e15a232b731a83c93d59493 --hash=sha256:0cea139045c38f84abaa803bcb4b5e8775ea12a42af10019d942f227acc426c3 --hash=sha256:0cdca76a68dcb701fff58c397de0ef9922b472b1cb3ea9695ca19d03f1869787 --hash=sha256:72fd8b0c11191da088147c6e4678ec53e573923ecf60b57eeac9e97433e09fc2 --hash=sha256:c6747146e95d2b14cc2a8399b2b0bde3f93778f8f9ec704690d2b589c376c137 --hash=sha256:0f2e50d20bc670be170966638fa0ae603f0bc9ed6ebe8e97a6d1d4cef30cc889 --hash=sha256:af00ea8f2022b6287dc375b2c70f31ab5af83989fc6fe9eacd4976ce26cd7ccc
python-dateutil==2.7.2 --hash=sha256:3220490fb9741e2342e1cf29a503394fdac874bc39568288717ee67047ff29df --hash=sha256:9d8074be4c993fbe4947878ce593052f71dac82932a677d49194d8ce9778002e
python-editor==1.0.3 --hash=sha256:a3c066acee22a1c94f63938341d4fb374e3fdd69366ed6603d7b24bed1efc565
pytz==2018.4 --hash=sha256:65ae0c8101309c45772196b21b74c46b2e5d11b6275c45d251b150d5da334555 --hash=sha256:c06425302f2cf668f1bba7a0a03f3c1d34d4ebeef2c72003da308b3947c7f749
redis==2.10.6 --hash=sha256:8a1900a9f2a0a44ecf6e8b5eb3e967a9909dfed219ad66df094f27f7d6f330fb --hash=sha256:a22ca993cea2962dbb588f9f30d0015ac4afcc45bee27d3978c0dbe9e97c6c0f
requests==2.18.4 --hash=sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b --hash=sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e
rsa==3.4.2 --hash=sha256:43f682fea81c452c98d09fc316aae12de6d30c4b5c84226642cf8f8fd1c93abd --hash=sha256:25df4e10c263fb88b5ace923dd84bf9aa7f5019687b5e55382ffcdb8bede9db5
six==1.11.0 --hash=sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb --hash=sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9
sqlalchemy==1.2.7 --hash=sha256:d6cda03b0187d6ed796ff70e87c9a7dce2c2c9650a7bc3c022cd331416853c31
urllib3==1.22 --hash=sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b --hash=sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f
vine==1.1.4 --hash=sha256:6849544be74ec3638e84d90bc1cf2e1e9224cc10d96cd4383ec3f69e9bce077b --hash=sha256:52116d59bc45392af9fdd3b75ed98ae48a93e822cee21e5fda249105c59a7a72
werkzeug==0.14.1 --hash=sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b --hash=sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c
wtforms==2.1 --hash=sha256:ffdf10bd1fa565b8233380cb77a304cd36fd55c73023e91d4b803c96bc11d46f

2
run.sh Normal file → Executable file
View File

@@ -1,3 +1,3 @@
export FLASK_APP=pypistats/run.py export FLASK_APP=pypistats/run.py
export FLASK_DEBUG=1 export FLASK_DEBUG=1
flask run flask run --host=0.0.0.0

View File

@@ -1,119 +0,0 @@
{
"dev": {
"app_function": "pypistats.run.app",
"aws_region": "REDACTED",
"certificate_arn": "REDACTED",
"delete_local_zip": true,
"domain": "dev.pypistats.org",
"environment_variables": {
"ENV": "dev"
},
"events": [
{
"function": "pypistats.tasks.pypi.get_daily_download_stats",
"kwargs": {"env": "dev"},
"expression": "cron(0 1 * * ? *)"
},
{
"function": "pypistats.tasks.pypi.update_all_package_stats",
"kwargs": {"env": "dev"},
"expression": "cron(10 1 * * ? *)"
},
{
"function": "pypistats.tasks.pypi.update_recent_stats",
"kwargs": {"env": "dev"},
"expression": "cron(15 1 * * ? *)"
},
{
"function": "pypistats.tasks.pypi.purge_old_data",
"kwargs": {"env": "dev"},
"expression": "cron(20 1 * * ? *)"
}
],
"exclude": [
"docs/",
"ignore/",
"migrations/",
"tests/",
"pypistats/secret/",
"pypistats/static/",
"boto3*",
"botocore*"
],
"keep_warm": false,
"profile_name": "REDACTED",
"project_name": "pypistats",
"memory_size": 128,
"remote_env": "REDACTED",
"route53_enabled": true,
"runtime": "python3.6",
"s3_bucket": "pypistats",
"slim_handler": false,
"timeout_seconds": 30,
"vpc_config" : {
"SubnetIds": [
"REDACTED",
],
"SecurityGroupIds": ["REDACTED"]
}
},
"prod": {
"app_function": "pypistats.run.app",
"aws_region": "REDACTED",
"certificate_arn": "REDACTED",
"delete_local_zip": true,
"domain": "pypistats.org",
"environment_variables": {
"ENV": "prod"
},
"events": [
{
"function": "pypistats.tasks.pypi.get_daily_download_stats",
"kwargs": {"env": "prod"},
"expression": "cron(0 1 * * ? *)"
},
{
"function": "pypistats.tasks.pypi.update_all_package_stats",
"kwargs": {"env": "prod"},
"expression": "cron(10 1 * * ? *)"
},
{
"function": "pypistats.tasks.pypi.update_recent_stats",
"kwargs": {"env": "prod"},
"expression": "cron(15 1 * * ? *)"
},
{
"function": "pypistats.tasks.pypi.purge_old_data",
"kwargs": {"env": "prod"},
"expression": "cron(20 1 * * ? *)"
}
],
"exclude": [
"docs/",
"ignore/",
"migrations/",
"tests/",
"pypistats/secret/",
"pypistats/static/",
"boto3*",
"botocore*"
],
"keep_warm": true,
"keep_warm_expression": "rate(4 minutes)",
"profile_name": "REDACTED",
"project_name": "pypistats",
"memory_size": 128,
"remote_env": "REDACTED",
"route53_enabled": true,
"runtime": "python3.6",
"s3_bucket": "REDACTED",
"slim_handler": false,
"timeout_seconds": 30,
"vpc_config" : {
"SubnetIds": [
"REDACTED",
],
"SecurityGroupIds": ["REDACTED"]
}
}
}