From 609eb5d952a0d96791e82a32ff26edef492ec8df Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Fri, 27 Apr 2018 09:41:21 +0200 Subject: Declaring the encoding to be utf-8 is not necessary in Python3 projects, as this is the default encoding. Encoding declarations are only useful in py3 if you want to declare it to be something _other_ than utf-8. This was, however, a very useful convention in py2. (#56) --- app.py | 2 -- gunicorn_config.py | 1 - pysite/__init__.py | 1 - pysite/base_route.py | 1 - pysite/constants.py | 2 -- pysite/decorators.py | 1 - pysite/logs.py | 1 - pysite/mixins.py | 1 - pysite/route_manager.py | 1 - pysite/rst/__init__.py | 1 - pysite/rst/directives/__init__.py | 1 - pysite/rst/roles.py | 1 - pysite/views/api/__init__.py | 1 - pysite/views/api/bot/hiphopify.py | 1 - pysite/views/api/bot/tags.py | 2 -- pysite/views/api/bot/user.py | 1 - pysite/views/api/error_view.py | 1 - pysite/views/api/healthcheck.py | 1 - pysite/views/api/index.py | 1 - pysite/views/error_handlers/http_4xx.py | 1 - pysite/views/error_handlers/http_5xx.py | 1 - pysite/views/main/__init__.py | 1 - pysite/views/main/abort.py | 1 - pysite/views/main/about/__init__.py | 1 - pysite/views/main/about/index.py | 1 - pysite/views/main/about/partners.py | 1 - pysite/views/main/about/rules.py | 1 - pysite/views/main/error.py | 1 - pysite/views/main/index.py | 1 - pysite/views/main/info/__init__.py | 1 - pysite/views/main/info/help.py | 1 - pysite/views/main/info/index.py | 1 - pysite/views/main/info/jams.py | 1 - pysite/views/main/info/resources.py | 1 - pysite/views/main/redirects/github.py | 1 - pysite/views/main/redirects/invite.py | 1 - pysite/views/main/redirects/stats.py | 1 - pysite/views/main/ws_test.py | 1 - pysite/views/main/ws_test_rst.py | 1 - pysite/views/staff/index.py | 1 - pysite/views/tests/index.py | 2 -- pysite/views/wiki/edit.py | 1 - pysite/views/wiki/history/compare.py | 1 - pysite/views/wiki/history/show.py | 1 - pysite/views/wiki/index.py | 1 - pysite/views/wiki/page.py | 1 - pysite/views/wiki/render.py | 1 - pysite/views/wiki/source.py | 1 - pysite/views/ws/echo.py | 1 - pysite/views/ws/rst.py | 1 - pysite/websockets.py | 1 - 51 files changed, 55 deletions(-) diff --git a/app.py b/app.py index 0b15d49f..5e55bc07 100644 --- a/app.py +++ b/app.py @@ -1,5 +1,3 @@ -# coding=utf-8 - from os import environ from pysite.route_manager import RouteManager diff --git a/gunicorn_config.py b/gunicorn_config.py index 5b9f9055..0e374fdd 100644 --- a/gunicorn_config.py +++ b/gunicorn_config.py @@ -1,4 +1,3 @@ -# coding=utf-8 def when_ready(server=None): """ server hook that only runs when the gunicorn master process loads """ diff --git a/pysite/__init__.py b/pysite/__init__.py index 93362f6a..98e66630 100644 --- a/pysite/__init__.py +++ b/pysite/__init__.py @@ -1,4 +1,3 @@ -# coding=utf-8 import logging import sys from logging import Logger, StreamHandler diff --git a/pysite/base_route.py b/pysite/base_route.py index 1d30669d..e9df7afe 100644 --- a/pysite/base_route.py +++ b/pysite/base_route.py @@ -1,4 +1,3 @@ -# coding=utf-8 from collections import Iterable from typing import Any diff --git a/pysite/constants.py b/pysite/constants.py index 4eff3606..225550fe 100644 --- a/pysite/constants.py +++ b/pysite/constants.py @@ -1,5 +1,3 @@ -# coding=utf-8 - from enum import Enum, IntEnum from os import environ diff --git a/pysite/decorators.py b/pysite/decorators.py index 0b02ebde..0c31fe6e 100644 --- a/pysite/decorators.py +++ b/pysite/decorators.py @@ -1,4 +1,3 @@ -# coding=utf-8 import os from functools import wraps from json import JSONDecodeError diff --git a/pysite/logs.py b/pysite/logs.py index 301cb98b..e789b1ea 100644 --- a/pysite/logs.py +++ b/pysite/logs.py @@ -1,4 +1,3 @@ -# coding=utf-8 from logging.handlers import SocketHandler diff --git a/pysite/mixins.py b/pysite/mixins.py index 5108a9a1..a3edc4f2 100644 --- a/pysite/mixins.py +++ b/pysite/mixins.py @@ -1,4 +1,3 @@ -# coding=utf-8 from weakref import ref from flask import Blueprint diff --git a/pysite/route_manager.py b/pysite/route_manager.py index e6d2c92c..429a553e 100644 --- a/pysite/route_manager.py +++ b/pysite/route_manager.py @@ -1,4 +1,3 @@ -# coding=utf-8 import importlib import inspect import logging diff --git a/pysite/rst/__init__.py b/pysite/rst/__init__.py index 74f19285..ae79f529 100644 --- a/pysite/rst/__init__.py +++ b/pysite/rst/__init__.py @@ -1,4 +1,3 @@ -# coding=utf-8 import re from docutils.core import publish_parts diff --git a/pysite/rst/directives/__init__.py b/pysite/rst/directives/__init__.py index 9bad5790..e69de29b 100644 --- a/pysite/rst/directives/__init__.py +++ b/pysite/rst/directives/__init__.py @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/pysite/rst/roles.py b/pysite/rst/roles.py index acba31e4..00d12dba 100644 --- a/pysite/rst/roles.py +++ b/pysite/rst/roles.py @@ -1,4 +1,3 @@ -# coding=utf-8 from docutils import nodes from docutils.parsers.rst.roles import set_classes from docutils.parsers.rst.states import Inliner diff --git a/pysite/views/api/__init__.py b/pysite/views/api/__init__.py index 9bad5790..e69de29b 100644 --- a/pysite/views/api/__init__.py +++ b/pysite/views/api/__init__.py @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/pysite/views/api/bot/hiphopify.py b/pysite/views/api/bot/hiphopify.py index 7ebf47e1..bb85d5b5 100644 --- a/pysite/views/api/bot/hiphopify.py +++ b/pysite/views/api/bot/hiphopify.py @@ -1,4 +1,3 @@ -# coding=utf-8 import datetime import logging diff --git a/pysite/views/api/bot/tags.py b/pysite/views/api/bot/tags.py index ee1a1bee..c901347e 100644 --- a/pysite/views/api/bot/tags.py +++ b/pysite/views/api/bot/tags.py @@ -1,5 +1,3 @@ -# coding=utf-8 - from flask import jsonify from schema import Optional, Schema diff --git a/pysite/views/api/bot/user.py b/pysite/views/api/bot/user.py index 3d8d7271..1394e699 100644 --- a/pysite/views/api/bot/user.py +++ b/pysite/views/api/bot/user.py @@ -1,4 +1,3 @@ -# coding=utf-8 import logging from flask import jsonify, request diff --git a/pysite/views/api/error_view.py b/pysite/views/api/error_view.py index 30e133f9..89b4d6ad 100644 --- a/pysite/views/api/error_view.py +++ b/pysite/views/api/error_view.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import jsonify from werkzeug.exceptions import HTTPException diff --git a/pysite/views/api/healthcheck.py b/pysite/views/api/healthcheck.py index d57f61fa..c873d674 100644 --- a/pysite/views/api/healthcheck.py +++ b/pysite/views/api/healthcheck.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import jsonify from pysite.base_route import APIView diff --git a/pysite/views/api/index.py b/pysite/views/api/index.py index e2bd8fe0..5111162c 100644 --- a/pysite/views/api/index.py +++ b/pysite/views/api/index.py @@ -1,4 +1,3 @@ -# coding=utf-8 from pysite.base_route import APIView from pysite.constants import ErrorCodes diff --git a/pysite/views/error_handlers/http_4xx.py b/pysite/views/error_handlers/http_4xx.py index 2d6c54c6..69c0bdda 100644 --- a/pysite/views/error_handlers/http_4xx.py +++ b/pysite/views/error_handlers/http_4xx.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import request from werkzeug.exceptions import HTTPException diff --git a/pysite/views/error_handlers/http_5xx.py b/pysite/views/error_handlers/http_5xx.py index 46c65e38..5a4fbdc2 100644 --- a/pysite/views/error_handlers/http_5xx.py +++ b/pysite/views/error_handlers/http_5xx.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import request from werkzeug.exceptions import HTTPException, InternalServerError diff --git a/pysite/views/main/__init__.py b/pysite/views/main/__init__.py index 9bad5790..e69de29b 100644 --- a/pysite/views/main/__init__.py +++ b/pysite/views/main/__init__.py @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/pysite/views/main/abort.py b/pysite/views/main/abort.py index d9e3282f..ecfe8f91 100644 --- a/pysite/views/main/abort.py +++ b/pysite/views/main/abort.py @@ -1,4 +1,3 @@ -# coding=utf-8 from werkzeug.exceptions import InternalServerError from pysite.base_route import RouteView diff --git a/pysite/views/main/about/__init__.py b/pysite/views/main/about/__init__.py index 9bad5790..e69de29b 100644 --- a/pysite/views/main/about/__init__.py +++ b/pysite/views/main/about/__init__.py @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/pysite/views/main/about/index.py b/pysite/views/main/about/index.py index a3fecc31..9f211702 100644 --- a/pysite/views/main/about/index.py +++ b/pysite/views/main/about/index.py @@ -1,4 +1,3 @@ -# coding=utf-8 from pysite.base_route import RouteView diff --git a/pysite/views/main/about/partners.py b/pysite/views/main/about/partners.py index b5e7f587..4fe321a5 100644 --- a/pysite/views/main/about/partners.py +++ b/pysite/views/main/about/partners.py @@ -1,4 +1,3 @@ -# coding=utf-8 import json from logging import getLogger diff --git a/pysite/views/main/about/rules.py b/pysite/views/main/about/rules.py index 805936a8..22e79afa 100644 --- a/pysite/views/main/about/rules.py +++ b/pysite/views/main/about/rules.py @@ -1,4 +1,3 @@ -# coding=utf-8 from pysite.base_route import RouteView diff --git a/pysite/views/main/error.py b/pysite/views/main/error.py index 2e432102..07286eb4 100644 --- a/pysite/views/main/error.py +++ b/pysite/views/main/error.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import abort from pysite.base_route import RouteView diff --git a/pysite/views/main/index.py b/pysite/views/main/index.py index 210eb057..ef5ed700 100644 --- a/pysite/views/main/index.py +++ b/pysite/views/main/index.py @@ -1,4 +1,3 @@ -# coding=utf-8 from pysite.base_route import RouteView diff --git a/pysite/views/main/info/__init__.py b/pysite/views/main/info/__init__.py index 9bad5790..e69de29b 100644 --- a/pysite/views/main/info/__init__.py +++ b/pysite/views/main/info/__init__.py @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/pysite/views/main/info/help.py b/pysite/views/main/info/help.py index 868b969f..a47362fc 100644 --- a/pysite/views/main/info/help.py +++ b/pysite/views/main/info/help.py @@ -1,4 +1,3 @@ -# coding=utf-8 from pysite.base_route import RouteView diff --git a/pysite/views/main/info/index.py b/pysite/views/main/info/index.py index 3f36e50f..f9fab682 100644 --- a/pysite/views/main/info/index.py +++ b/pysite/views/main/info/index.py @@ -1,4 +1,3 @@ -# coding=utf-8 from pysite.base_route import RouteView diff --git a/pysite/views/main/info/jams.py b/pysite/views/main/info/jams.py index 19e4cb9c..9158091f 100644 --- a/pysite/views/main/info/jams.py +++ b/pysite/views/main/info/jams.py @@ -1,4 +1,3 @@ -# coding=utf-8 from pysite.base_route import RouteView diff --git a/pysite/views/main/info/resources.py b/pysite/views/main/info/resources.py index 2642e1ec..541b9ba1 100644 --- a/pysite/views/main/info/resources.py +++ b/pysite/views/main/info/resources.py @@ -1,4 +1,3 @@ -# coding=utf-8 import json from logging import getLogger diff --git a/pysite/views/main/redirects/github.py b/pysite/views/main/redirects/github.py index d2ceaf49..f861a91c 100644 --- a/pysite/views/main/redirects/github.py +++ b/pysite/views/main/redirects/github.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import redirect from pysite.base_route import RouteView diff --git a/pysite/views/main/redirects/invite.py b/pysite/views/main/redirects/invite.py index 5f31d7db..1895d36a 100644 --- a/pysite/views/main/redirects/invite.py +++ b/pysite/views/main/redirects/invite.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import redirect from pysite.base_route import RouteView diff --git a/pysite/views/main/redirects/stats.py b/pysite/views/main/redirects/stats.py index 7766f9ed..935f8539 100644 --- a/pysite/views/main/redirects/stats.py +++ b/pysite/views/main/redirects/stats.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import redirect from pysite.base_route import RouteView diff --git a/pysite/views/main/ws_test.py b/pysite/views/main/ws_test.py index c53515c5..a0b6215f 100644 --- a/pysite/views/main/ws_test.py +++ b/pysite/views/main/ws_test.py @@ -1,4 +1,3 @@ -# coding=utf-8 import os from pysite.base_route import RouteView diff --git a/pysite/views/main/ws_test_rst.py b/pysite/views/main/ws_test_rst.py index 9c2ee805..e80acc55 100644 --- a/pysite/views/main/ws_test_rst.py +++ b/pysite/views/main/ws_test_rst.py @@ -1,4 +1,3 @@ -# coding=utf-8 import os from pysite.base_route import RouteView diff --git a/pysite/views/staff/index.py b/pysite/views/staff/index.py index 7569ba32..11447f87 100644 --- a/pysite/views/staff/index.py +++ b/pysite/views/staff/index.py @@ -1,4 +1,3 @@ -# coding=utf-8 from pprint import pformat from flask import current_app diff --git a/pysite/views/tests/index.py b/pysite/views/tests/index.py index 3071bf0e..b96590c0 100644 --- a/pysite/views/tests/index.py +++ b/pysite/views/tests/index.py @@ -1,5 +1,3 @@ -# coding=utf-8 - from flask import jsonify from schema import Schema diff --git a/pysite/views/wiki/edit.py b/pysite/views/wiki/edit.py index 9cff9da0..2cd4181c 100644 --- a/pysite/views/wiki/edit.py +++ b/pysite/views/wiki/edit.py @@ -1,4 +1,3 @@ -# coding=utf-8 import datetime import difflib diff --git a/pysite/views/wiki/history/compare.py b/pysite/views/wiki/history/compare.py index d42a6b36..6296f734 100644 --- a/pysite/views/wiki/history/compare.py +++ b/pysite/views/wiki/history/compare.py @@ -1,4 +1,3 @@ -# coding=utf-8 import difflib from pygments import highlight diff --git a/pysite/views/wiki/history/show.py b/pysite/views/wiki/history/show.py index e18b017e..50fc5d73 100644 --- a/pysite/views/wiki/history/show.py +++ b/pysite/views/wiki/history/show.py @@ -1,4 +1,3 @@ -# coding=utf-8 import datetime from werkzeug.exceptions import NotFound diff --git a/pysite/views/wiki/index.py b/pysite/views/wiki/index.py index 778a808c..8290eac9 100644 --- a/pysite/views/wiki/index.py +++ b/pysite/views/wiki/index.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import url_for from werkzeug.utils import redirect diff --git a/pysite/views/wiki/page.py b/pysite/views/wiki/page.py index 500d5c04..26edfcc4 100644 --- a/pysite/views/wiki/page.py +++ b/pysite/views/wiki/page.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import redirect, url_for from werkzeug.exceptions import NotFound diff --git a/pysite/views/wiki/render.py b/pysite/views/wiki/render.py index 9d3e8cc3..b08f54dd 100644 --- a/pysite/views/wiki/render.py +++ b/pysite/views/wiki/render.py @@ -1,4 +1,3 @@ -# coding=utf-8 import re from docutils.utils import SystemMessage diff --git a/pysite/views/wiki/source.py b/pysite/views/wiki/source.py index 80f362df..83674447 100644 --- a/pysite/views/wiki/source.py +++ b/pysite/views/wiki/source.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import redirect, url_for from pygments import highlight from pygments.formatters.html import HtmlFormatter diff --git a/pysite/views/ws/echo.py b/pysite/views/ws/echo.py index 7e6b036f..b6f11168 100644 --- a/pysite/views/ws/echo.py +++ b/pysite/views/ws/echo.py @@ -1,4 +1,3 @@ -# coding=utf-8 import logging from geventwebsocket.websocket import WebSocket diff --git a/pysite/views/ws/rst.py b/pysite/views/ws/rst.py index 24bdb3ca..f2b2db24 100644 --- a/pysite/views/ws/rst.py +++ b/pysite/views/ws/rst.py @@ -1,4 +1,3 @@ -# coding=utf-8 import logging from geventwebsocket.websocket import WebSocket diff --git a/pysite/websockets.py b/pysite/websockets.py index 1e7960f7..19f9bf83 100644 --- a/pysite/websockets.py +++ b/pysite/websockets.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import Blueprint from geventwebsocket.websocket import WebSocket -- cgit v1.2.3 From 4327d9fe1fb82c8f8e25ce866487e65ba0b7e810 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Fri, 27 Apr 2018 13:09:23 +0200 Subject: Added books and courses (#59) * Added books and courses * Alphabetized all the things, but maintained groupings of free, optional, paid within each section, and still have Tutorials on the top, since it's probably the most relevant category. --- static/resources.json | 564 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 374 insertions(+), 190 deletions(-) diff --git a/static/resources.json b/static/resources.json index 210021d1..9bca279b 100644 --- a/static/resources.json +++ b/static/resources.json @@ -1,192 +1,376 @@ { - "Learning Resources": { - "description": "Tutorials and references for those that are just getting started with python", - "resources": { - "Automate the Boring Stuff with Python": { - "description": "One of the best books out there for Python beginners. You can buy a copy, but there's also a free online version.", - "urls": [ - { - "title": "Website", - "url": "https://automatetheboringstuff.com/", - "icon": "regular/link" - }, { - "title": "Amazon", - "url": "http://www.amazon.com/gp/product/1593275994/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1593275994&linkCode=as2&tag=playwithpyth-20&linkId=HDM7V3T6RHC5VVN4", - "icon": "branding/amazon" - } - ], - "payment": "optional", - "payment_description": "A free version is available online, with the option to buy a physical copy" - }, - "Code Combat": { - "description": "Learn Python while gaming - an open-source project with thousands of contributors, which teaches you Python through a deep, top-down RPG.", - "urls": [ - { - "title": "Website", - "url": "https://codecombat.com/", - "icon": "regular/link" - }, - { - "title": "GitHub", - "url": "https://github.com/codecombat/codecombat", - "icon": "branding/github" - } - ], - "payment": "optional", - "payment_description": "A wealth of free content is available, but you can also pay for more" - }, - "Get Started with Flask Web Development": { - "description": "A fully featured mega-tutorial for learning how to create web applications with the Flask framework.", - "urls": [ - { - "title": "Website", - "url": "https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world", - "icon": "regular/link" - } - ], - "payment": "free", - "payment_description": null - }, - "Getting Started for Non-Programmers": { - "description": "The list of resources for non-programmers from Python's official beginners' guide", - "urls": [ - { - "title": "Python Wiki", - "url": "https://wiki.python.org/moin/BeginnersGuide/NonProgrammers", - "icon": "regular/link" - } - ], - "payment": "free", - "payment_description": null - }, - "Getting Started for Programmers": { - "description": "The list of resources for programmers from Python's official beginners' guide", - "urls": [ - { - "title": "Python Wiki", - "url": "https://wiki.python.org/moin/BeginnersGuide/Programmers", - "icon": "regular/link" - } - ], - "payment": "free", - "payment_description": null - }, - "A Simple Guide to Git": { - "description": "A simple, no-nonsense guide to the basics of using Git.", - "urls": [ - { - "title": "Website", - "url": "http://rogerdudler.github.io/git-guide/", - "icon": "regular/link" - } - ], - "payment": "free", - "payment_description": null - }, - "Python Cheat Sheet": { - "description": "A Python 3 cheat sheet with useful information and tips, as well as common pitfalls for beginners. This is a PDF.", - "urls": [ - { - "title": "Website", - "url": "https://perso.limsi.fr/pointal/_media/python:cours:mementopython3-english.pdf", - "icon": "regular/link" - } - ], - "payment": "free", - "payment_description": null - }, - "Python Tutorials by Corey Schafer on YouTube": { - "description": "An in-depth look at the Python programming language, from one of YouTube's most popular Python tutors.", - "urls": [ - { - "title": "YouTube", - "url": "https://www.youtube.com/playlist?list=PL-osiE80TeTt2d9bfVyTiXJA-UTHn6WwU", - "icon": "branding/youtube" - } - ], - "payment": "free", - "payment_description": null - } + "Tutorials": { + "description": "Tutorials and references for those that are just getting started with python", + "resources": { + "A Simple Guide to Git": { + "description": "A simple, no-nonsense guide to the basics of using Git.", + "payment": "free", + "payment_description": null, + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "http://rogerdudler.github.io/git-guide/" + } + ] + }, + "Get Started with Flask Web Development": { + "description": "A fully featured mega-tutorial for learning how to create web applications with the Flask framework.", + "payment": "free", + "payment_description": null, + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world" + } + ] + }, + "Getting Started with Python": { + "description": "The list of resources for programmers and non-programmers from Python's official beginners' guide", + "payment": "free", + "payment_description": null, + "urls": [ + { + "icon": "regular/link", + "title": "Beginners Guide for Non-Programmers", + "url": "https://wiki.python.org/moin/BeginnersGuide/NonProgrammers" + }, + { + "icon": "regular/link", + "title": "Beginners Guide for Programmers", + "url": "https://wiki.python.org/moin/BeginnersGuide/Programmers" + } + ] + }, + "Python Cheat Sheet": { + "description": "A Python 3 cheat sheet with useful information and tips, as well as common pitfalls for beginners. This is a PDF.", + "payment": "free", + "payment_description": null, + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://perso.limsi.fr/pointal/_media/python:cours:mementopython3-english.pdf" + } + ] + } + } + }, + "Books": { + "description": "The best books for learning Python or Python Frameworks", + "resources": { + "A Byte of Python": { + "description": "A free book on programming using the Python language. It serves as a tutorial or guide to the Python language for a beginner audience. If all you know about computers is how to save text files, then this is the book for you.", + "payment": "optional", + "payment_description": "A free e-book is available online, a paper version can be bought from lulu.com.", + "urls": [ + { + "icon": "regular/link", + "title": "E-book", + "url": "https://python.swaroopch.com/" + }, + { + "icon": "regular/book", + "title": "Buy the book", + "url": "http://www.lulu.com/shop/swaroop-c-h/a-byte-of-python/paperback/product-21142968.html" + }, + { + "icon": "regular/tablet-alt", + "title": "Kindle edition", + "url": "https://www.amazon.com/Byte-Python-Swaroop-C-H-ebook/dp/B00FJ7S2JU/ref=sr_1_1?ie=UTF8&qid=1524816076&sr=8-1&keywords=a+byte+of+python" + } + ] + }, + "Automate the Boring Stuff with Python": { + "description": "One of the best books out there for Python beginners. This book will teach you the basics of Python, while also teaching invaluable automation tools and techniques for solving common problems. You'll learn how to go about scraping the web, manipulating files and automating keyboard and mouse input. Ideal for an office worker who wants to make himself more useful.", + "payment": "optional", + "payment_description": "A free e-book is available on the website, but you can buy it on Amazon if you want to support the author.", + "urls": [ + { + "icon": "regular/link", + "title": "E-book", + "url": "https://automatetheboringstuff.com/" + }, + { + "icon": "branding/amazon", + "title": "Amazon", + "url": "http://www.amazon.com/gp/product/1593275994/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1593275994&linkCode=as2&tag=playwithpyth-20&linkId=HDM7V3T6RHC5VVN4" + } + ] + }, + "Effective Python": { + "description": "A book that gives 59 best practices for writing excellent Python. Great for intermediates.", + "payment": "paid", + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://effectivepython.com/" + }, + { + "icon": "branding/amazon", + "title": "Amazon", + "url": "https://www.amazon.com/Effective-Python-Specific-Software-Development/dp/0134034287" + }, + { + "icon": "branding/github", + "title": "GitHub", + "url": "https://github.com/bslatkin/effectivepython" + } + ] + }, + "Flask Web Development": { + "description": "A comprehensive Flask walkthrough that has you building a complete social blogging application from scratch.", + "payment": "paid", + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "http://shop.oreilly.com/product/0636920031116.do" + }, + { + "icon": "branding/amazon", + "title": "Amazon", + "url": "https://www.amazon.com/Flask-Web-Development-Developing-Applications/dp/1449372627" + }, + { + "icon": "branding/github", + "title": "GitHub", + "url": "https://github.com/miguelgrinberg/flasky" + } + ] + }, + "Fluent Python": { + "description": "A veritable tome of intermediate and advanced Python information. A must-read for any Python professional.", + "payment": "paid", + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://www.safaribooksonline.com/library/view/fluent-python/9781491946237/" + }, + { + "icon": "branding/amazon", + "title": "Amazon", + "url": "https://www.amazon.com/Fluent-Python-Concise-Effective-Programming/dp/1491946008" + }, + { + "icon": "branding/github", + "title": "GitHub", + "url": "https://github.com/fluentpython" + } + ] + }, + "Python Cookbook": { + "description": "Complete with 'recipes' for various Python topics, including moving from Python 2 to Python 3.3", + "payment": "paid", + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "http://shop.oreilly.com/product/0636920027072.do" + }, + { + "icon": "branding/amazon", + "title": "Amazon", + "url": "https://www.amazon.com/Python-Cookbook-Third-David-Beazley/dp/1449340377" + }, + { + "icon": "branding/github", + "title": "GitHub", + "url": "https://github.com/dabeaz/python-cookbook" + } + ] + }, + "Two Scoops of Django": { + "description": "This book is chock-full of material that will help you with your Django projects.", + "payment": "paid", + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://twoscoopspress.com/products/two-scoops-of-django-1-11" + }, + { + "icon": "branding/amazon", + "title": "Amazon", + "url": "https://www.amazon.com/Two-Scoops-Django-Best-Practices/dp/0981467342" + }, + { + "icon": "branding/github", + "title": "GitHub", + "url": "https://github.com/twoscoops/two-scoops-of-django-2.0-code-examples" + } + ] + } + } + }, + "Courses": { + "description": "Online courses that relate to Python.", + "resources": { + "Python Tutorials by Corey Schafer on YouTube": { + "description": "An in-depth look at the Python programming language, from one of YouTube's most popular Python tutors.", + "payment": "free", + "payment_description": null, + "urls": [ + { + "icon": "branding/youtube", + "title": "YouTube", + "url": "https://www.youtube.com/playlist?list=PL-osiE80TeTt2d9bfVyTiXJA-UTHn6WwU" + } + ] + }, + "Code Combat": { + "description": "Learn Python while gaming - an open-source project with thousands of contributors, which teaches you Python through a deep, top-down RPG.", + "payment": "optional", + "payment_description": "A wealth of free content is available, but you can also pay for more", + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://codecombat.com/" + }, + { + "icon": "branding/github", + "title": "GitHub", + "url": "https://github.com/codecombat/codecombat" + } + ] + }, + "MIT: Introduction to Computer Science and Programming Using Python": { + "description": "This MITx offering teaches computer science with Python. It covers computational thinking, algorithms, data structures and the Python programming language itself.", + "payment": "optional", + "payment_description": "You can pay to enroll for a graded certificate, or choose to take the full course for free.", + "urls": [ + { + "icon": "regular/graduation-cap", + "title": "edX Course", + "url": "https://www.edx.org/course/introduction-computer-science-mitx-6-00-1x-11" + } + ] + }, + "University of Michigan: Programming for Everybody": { + "description": "A 5-part specialization course that teaches Python from scratch. The course has no pre-requisites and avoids all but the simplest mathematics.", + "payment": "optional", + "payment_description": "You can pay to enroll for a graded certificate and a capstone project, or choose to audit for free.", + "urls": [ + { + "icon": "regular/graduation-cap", + "title": "Python for Everyone Specialization", + "url": "https://www.coursera.org/learn/python" + } + ] + }, + "University of Toronto: Learn to Program": { + "description": "A 2-part course that teaches Python. Primarily intended for high school students and first-year university students who want to learn programming.", + "payment": "optional", + "payment_description": "You can pay to enroll for a graded certificate, or choose to audit for free.", + "urls": [ + { + "icon": "regular/graduation-cap", + "title": "Part 1: The Fundamentals", + "url": "https://www.coursera.org/learn/learn-to-program" + }, + { + "icon": "regular/graduation-cap", + "title": "Part 2: Crafting Quality Code", + "url": "https://www.coursera.org/learn/program-code" + } + ] + }, + "Automate the Boring Stuff with Python": { + "description": "The interactive course version of Al Sweigart's excellent book for beginners, taught by the author himself. This link has a discounted version of the course which will always cost 10 dollars. Thanks, Al!", + "payment": "paid", + "payment_description": "You can pay to enroll for a graded certificate, or choose to take the full course for free.", + "urls": [ + { + "icon": "regular/graduation-cap", + "title": "Udemy Course", + "url": "https://www.udemy.com/automate/?couponCode=FOR_LIKE_10_BUCKS" + } + ] + } + } + }, + "Editors": { + "description": "Lightweight code editors supporting Python", + "resources": { + "Atom": { + "description": "A free Electron-based editor, a \"hackable text editor for the 21st century\", maintained by the GitHub team.", + "payment": "free", + "payment_description": null, + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://atom.io/" + }, + { + "icon": "branding/github", + "title": "GitHub", + "url": "https://github.com/atom/atom" + } + ] + }, + "Visual Studio Code": { + "description": "A fully-featured editor based on Electron, extendable with plugins.", + "payment": "free", + "payment_description": null, + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://code.visualstudio.com/" + } + ] + }, + "Sublime Text": { + "description": "A powerful Python-backed editor with great community support and a wealth of extensions.", + "payment": "optional", + "payment_description": "Nagware; will ask you to buy the full version after every X saves", + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://www.sublimetext.com/" + } + ] + } + } + }, + "IDEs": { + "description": "Fully-integrated development environments for serious Python work", + "resources": { + "Spyder": { + "description": "The Scientific PYthon Development EnviRonment. Simpler and lighter than PyCharm, but still packs a punch.", + "payment": "free", + "payment_description": null, + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://pythonhosted.org/spyder/" + }, + { + "icon": "branding/github", + "title": "GitHub", + "url": "https://github.com/spyder-ide/spyder" + } + ] + }, + "PyCharm": { + "description": "The very best Python IDE, with a wealth of advanced features and convenience functions.", + "payment": "optional", + "payment_description": "There's a free Community Edition and a paid-for Professional Edition with more features available", + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://www.jetbrains.com/pycharm/" + } + ] + } + } } - }, - "Editors": { - "description": "Lightweight code editors supporting Python", - "resources": { - "Atom": { - "description": "A free Electron-based editor, a \"hackable text editor for the 21st century\", maintained by the GitHub team.", - "urls": [ - { - "title": "Website", - "url": "https://atom.io/", - "icon": "regular/link" - }, - { - "title": "GitHub", - "url": "https://github.com/atom/atom", - "icon": "branding/github" - } - ], - "payment": "free", - "payment_description": null - }, - "Sublime Text": { - "description": "A powerful Python-backed editor with great community support and a wealth of extensions.", - "urls": [ - { - "title": "Website", - "url": "https://www.sublimetext.com/", - "icon": "regular/link" - } - ], - "payment": "optional", - "payment_description": "Nagware; will ask you to buy the full version after every X saves" - }, - "Visual Studio Code": { - "description": "A fully-featured editor based on Electron, extendable with plugins.", - "urls": [ - { - "title": "Website", - "url": "https://code.visualstudio.com/", - "icon": "regular/link" - } - ], - "payment": "free", - "payment_description": null - } - } - }, - "IDEs": { - "description": "Fully-integrated development environments for serious Python work", - "resources": { - "PyCharm": { - "description": "The very best Python IDE, with a wealth of advanced features and convenience functions.", - "urls": [ - { - "title": "Website", - "url": "https://www.jetbrains.com/pycharm/", - "icon": "regular/link" - } - ], - "payment": "optional", - "payment_description": "There's a free Community Edition and a paid-for Professional Edition with more features available" - }, - "Spyder": { - "description": "The Scientific PYthon Development EnviRonment. Simpler and lighter than PyCharm, but still packs a punch.", - "urls": [ - { - "title": "Website", - "url": "https://pythonhosted.org/spyder/", - "icon": "regular/link" - }, - { - "title": "GitHub", - "url": "https://github.com/spyder-ide/spyder", - "icon": "branding/github" - } - ], - "payment": "free", - "payment_description": null - } - } - } -} +} \ No newline at end of file -- cgit v1.2.3 From 2a0a4472945d1757693b9014fb672cc8d6fef4b6 Mon Sep 17 00:00:00 2001 From: Gareth Coles Date: Fri, 27 Apr 2018 12:38:47 +0100 Subject: [Wiki] Fix left sidebar width on some devices --- static/style.css | 6 +++++- templates/wiki/base.html | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/static/style.css b/static/style.css index dc16f6d7..04f83fa7 100644 --- a/static/style.css +++ b/static/style.css @@ -133,4 +133,8 @@ div#partner-cards div.uk-card-default { /* Resize navbar to correct proportions */ img.navbar-logo { max-width: 110%; -} \ No newline at end of file +} + +#wiki-nav uk-nav-divider { + min-width: 7rem; +} diff --git a/templates/wiki/base.html b/templates/wiki/base.html index 87686a83..f53eea65 100644 --- a/templates/wiki/base.html +++ b/templates/wiki/base.html @@ -32,7 +32,7 @@ {% include "main/navigation.html" %}
-
    +
      {% if data is defined %} {% if "headers" in data and data.headers %}
    • Contents
    • -- cgit v1.2.3 From 0829ce9cfcf9927b31ed634885bca3cf32972ced Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Fri, 27 Apr 2018 15:36:17 +0200 Subject: Minor adjustments to payment icon alignment and margins (#60) --- static/style.css | 9 +++++++++ templates/main/info/resources.html | 23 +++++++++++++++-------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/static/style.css b/static/style.css index 04f83fa7..0120f56c 100644 --- a/static/style.css +++ b/static/style.css @@ -138,3 +138,12 @@ img.navbar-logo { #wiki-nav uk-nav-divider { min-width: 7rem; } + +/* Resource page styling */ +div.payment-icon img { + height: 2em; +} + +div.payment-icon { + margin-right: 1em; +} \ No newline at end of file diff --git a/templates/main/info/resources.html b/templates/main/info/resources.html index c947d4ed..ae416d33 100644 --- a/templates/main/info/resources.html +++ b/templates/main/info/resources.html @@ -28,15 +28,22 @@ a resource or not. You can also hover them for more information on the payment (or tap them on mobile).

      -

      - - Free - - Payment Optional - - Paid -

      +
      +
      + + Free +
      +
      + + Payment optional +
      + +
      + + Paid +
      +
      {% if categories is none %}

      -- cgit v1.2.3 From d2b884655618b208526dd656a4d1eda8c420c38f Mon Sep 17 00:00:00 2001 From: Gareth Coles Date: Fri, 27 Apr 2018 15:00:42 +0100 Subject: [Wiki] Dumb CSS typo --- static/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/style.css b/static/style.css index 0120f56c..78a00706 100644 --- a/static/style.css +++ b/static/style.css @@ -135,7 +135,7 @@ img.navbar-logo { max-width: 110%; } -#wiki-nav uk-nav-divider { +#wiki-nav .uk-nav-divider { min-width: 7rem; } -- cgit v1.2.3 From f57942f2575dc26c9487688ded773a0abdab5c61 Mon Sep 17 00:00:00 2001 From: Christopher Baklid Date: Sun, 29 Apr 2018 20:03:50 +0200 Subject: pipenv and dockerfile (#62) pipenv and dockerfile --- .dockerignore | 14 + .travis.yml | 22 +- Dockerfile | 20 ++ Dockerfile.base | 20 ++ Pipfile | 43 +++ Pipfile.lock | 612 +++++++++++++++++++++++++++++++++++++++++++ Vagrant_bootstrap.sh | 87 ------ Vagrantfile | 2 +- deploy.py | 20 -- requirements-ci.txt | 11 - requirements.txt | 14 - scripts/deploy.py | 20 ++ scripts/deploy.sh | 18 ++ scripts/vagrant_bootstrap.sh | 87 ++++++ tox.ini | 4 +- 15 files changed, 853 insertions(+), 141 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 Dockerfile.base create mode 100644 Pipfile create mode 100644 Pipfile.lock delete mode 100644 Vagrant_bootstrap.sh delete mode 100644 deploy.py delete mode 100644 requirements-ci.txt delete mode 100644 requirements.txt create mode 100644 scripts/deploy.py create mode 100644 scripts/deploy.sh create mode 100644 scripts/vagrant_bootstrap.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..797f4db4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +.venv +scripts +htmlcov +__pycache__ +.vagrant +.pytest_cache +.git +.github +.cache +Vagrantfile +.coverage +.coveragerc +.gitignore +.travis.yml diff --git a/.travis.yml b/.travis.yml index 21e52051..4e2516be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,16 +9,26 @@ branches: only: - "master" +sudo: required + +services: + - docker + +env: + global: + - PIPENV_VENV_IN_PROJECT=1 + - PIPENV_IGNORE_VIRTUALENVS=1 + install: - - pip install -r requirements.txt - - pip install -r requirements-ci.txt + - pip install pipenv + - pipenv sync --dev --three script: - - flake8 + - pipenv run lint - python gunicorn_config.py - - py.test app_test.py --cov pysite --cov-report term-missing -v - - coveralls + - pipenv run test + - pipenv run coveralls after_success: - - python deploy.py + - bash scripts/deploy.sh cache: pip diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..3899084a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +FROM pythondiscord/site-base:latest + +ENV PIPENV_VENV_IN_PROJECT=1 +ENV PIPENV_IGNORE_VIRTUALENVS=1 +ENV PIPENV_NOSPIN=1 +ENV PIPENV_HIDE_EMOJIS=1 + +RUN pip install pipenv + +COPY . /site +WORKDIR /site +ENV PYTHONPATH=/site + +RUN pipenv clean +RUN pipenv sync + +EXPOSE 10012 + +ENTRYPOINT ["/sbin/tini", "--"] +CMD ["pipenv", "run", "start"] diff --git a/Dockerfile.base b/Dockerfile.base new file mode 100644 index 00000000..c5234997 --- /dev/null +++ b/Dockerfile.base @@ -0,0 +1,20 @@ +FROM python:3.6-alpine + +RUN apk add --update tini +RUN apk add --update git +RUN apk add --update build-base + +ENV PIPENV_VENV_IN_PROJECT=1 +ENV PIPENV_IGNORE_VIRTUALENVS=1 +ENV PIPENV_NOSPIN=1 +ENV PIPENV_HIDE_EMOJIS=1 + +RUN pip install pipenv + +RUN mkdir /site +COPY Pipfile /site +COPY Pipfile.lock /site +WORKDIR /site +ENV PYTHONPATH=/site + +RUN pipenv sync diff --git a/Pipfile b/Pipfile new file mode 100644 index 00000000..13811259 --- /dev/null +++ b/Pipfile @@ -0,0 +1,43 @@ +[[source]] +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +flask = "==0.12.2" +rethinkdb = "*" +requests = "*" +gevent = "*" +"gevent-websocket" = "*" +wsaccel = "*" +ujson = "*" +schema = "*" +"flask_sockets" = "*" +"Flask-Dance" = "*" +"logmatic-python" = "*" +"Flask-WTF" = "*" +docutils = "*" +pygments = "*" +gunicorn = "*" + +[dev-packages] +"flake8" = "*" +"flake8-bugbear" = "*" +"flake8-bandit" = "*" +"flake8-import-order" = "*" +"flake8-tidy-imports" = "*" +"flake8-string-format" = "*" +requests = "*" +"Flask-Testing" = "*" +pytest = "*" +pytest-cov = "*" +python-coveralls = "*" + +[requires] +python_version = "3.6" + +[scripts] +start = "gunicorn -w 12 -b 0.0.0.0:10012 -c gunicorn_config.py --log-level info -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker app:app" +lint = "python -m flake8" +test = "py.test app_test.py --cov pysite --cov-report term-missing -v" +clean = "rm -rf __pycache__ htmlcov .coverage .pytest_cache" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 00000000..fbabe5bb --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,612 @@ +{ + "_meta": { + "hash": { + "sha256": "a824288bd4a4c6498aa926af19245920da11113f087729774d53ce1fb4468469" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.6" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.python.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "certifi": { + "hashes": [ + "sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7", + "sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0" + ], + "version": "==2018.4.16" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "click": { + "hashes": [ + "sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d", + "sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b" + ], + "version": "==6.7" + }, + "docutils": { + "hashes": [ + "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", + "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274", + "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6" + ], + "index": "pypi", + "version": "==0.14" + }, + "flask": { + "hashes": [ + "sha256:0749df235e3ff61ac108f69ac178c9770caeaccad2509cb762ce1f65570a8856", + "sha256:49f44461237b69ecd901cc7ce66feea0319b9158743dd27a2899962ab214dac1" + ], + "index": "pypi", + "version": "==0.12.2" + }, + "flask-dance": { + "hashes": [ + "sha256:0c608d9f003a38493fdff092a2eb482c2c6b768ef878112e0d03676a6a92fa67", + "sha256:2cea678b882f94e04f82545dd0fcf751376ff58b5cd8e3af489529b11bdeb63d", + "sha256:56b50af359842e767a9b20d1ea2afea2a7268558e76c1fbadc652aa840abec7d" + ], + "index": "pypi", + "version": "==0.14.0" + }, + "flask-sockets": { + "hashes": [ + "sha256:072927da8edca0e81e024f5787e643c87d80b351b714de95d723becb30e0643b", + "sha256:350a76d55f5889f64afd2ca9b32f262680b7960965f0830365576307d30cfe1e" + ], + "index": "pypi", + "version": "==0.2.1" + }, + "flask-wtf": { + "hashes": [ + "sha256:5d14d55cfd35f613d99ee7cba0fc3fbbe63ba02f544d349158c14ca15561cc36", + "sha256:d9a9e366b32dcbb98ef17228e76be15702cd2600675668bca23f63a7947fd5ac" + ], + "index": "pypi", + "version": "==0.14.2" + }, + "gevent": { + "hashes": [ + "sha256:0901975628790e8a57fc92bb7062e5b856edea48c8de9caf36cfda14eae07329", + "sha256:1af93825db5753550fa8ff5ab2f2132e8733170b3f8d38347b34fa4a984cb624", + "sha256:2ff045a91509c35664c27a849c8cbf742a227f587b7cdbc88301e9c85dcaedff", + "sha256:33fa6759eabc9176ddbe0d29b66867a82e19a61f06eb7cfabbac35343c0ecf24", + "sha256:35790f1a3c8e431ada3471b70bb2105050009ea4beb15cbe41b86bc716a7ffa9", + "sha256:4791c8ae9c57d6f153354736e1ccab1e2baf6c8d9ae5a77a9ac90f41e2966b2d", + "sha256:4f098002126ebef7f2907188b6c8b09e5193161ce968847d9e6a8bc832b0db9a", + "sha256:552719cec4721673b8c7d2f9de666e3f7591b9b182f801ecaef1c76e638052aa", + "sha256:59e9237af027f8db85e5d78a9da2e328ae96f01d67a0d62abcecad3db7876908", + "sha256:60109741377367eef8ded9283a1bf629621b73acaf3e1e8aac9d1a0f50fa0f05", + "sha256:6892fabc9051e8c0a171d543b6536859aabeb6d169db79b2f45d64dc2a15808c", + "sha256:70558dd45c7a1f8046ba45792e489dd0f409bd8a3b7a0635ca9d3055223b3dff", + "sha256:74bce0c30bb2240e3d5d515ba8cb3eadf840c2bde7109a1979c7a26c9d0f5a6a", + "sha256:7f93b67b680f4a921f517294048d05f8f6f0ed5962b78d6685a6cf0fcd7d8202", + "sha256:81cb24e0f7bd9888596364e8d8ed0d65c2547c84884c67bb46d956faeed67396", + "sha256:833bebdc36bfeeedefc200ca9aee9b8eddd80f56b63ca1e886e18b97b1240edd", + "sha256:8a710eddb3e9e5f22bdbd458b5f211b94f59409ecd6896f15b9fee2cba266a59", + "sha256:9b492bb1a043540abb6e54fdb5537531e24962ca49c09f3b47dc4f9c37f6297c", + "sha256:a0ed8ba787b9c0c1c565c2675d71652e6c1e2d4e91f53530860d0303e867fe85", + "sha256:a16db4f56699ef07f0249b953ff949aae641e50b2bdc4710f11c0d8d9089b296", + "sha256:a66cf99f08da65c501826a19e30f5a6e7ba942fdd79baba5ce2d51eebaa13444", + "sha256:b67a10799923f9fed546ca5f8b93a2819c71a60132d7a97b4a13fbdab66b278a", + "sha256:b7e0e6400c2f3ce78a9ae1cdd55b53166feedd003d60c033863881227129a4d3", + "sha256:c35b29de49211014ec66d056fd4f9ba7a04795e2a654697f72879c0cf365d6d4", + "sha256:c9dd6534c46ed782e2d7236767cd07115cb29ce8670c2fc0794f264de9024fe0", + "sha256:de13a8e378103af84a8bf6015ad1d2761d46f29b8393e8dd6d9bb7cb51bbb713", + "sha256:deafd70d04ab62428d4e291e8e2c0fb22f38690e6a9f23a67ee6c304087634da", + "sha256:df52e06a2754c2d905aad75a7dc06a732c804d9edbc87f06f47c8f483ba98bca", + "sha256:fce894a64db3911897cdad6c37fbb23dfb18b7bf8b9cb8c00a8ea0a7253651c9" + ], + "index": "pypi", + "version": "==1.2.2" + }, + "gevent-websocket": { + "hashes": [ + "sha256:17b67d91282f8f4c973eba0551183fc84f56f1c90c8f6b6b30256f31f66f5242", + "sha256:7eaef32968290c9121f7c35b973e2cc302ffb076d018c9068d2f5ca8b2d85fb0" + ], + "index": "pypi", + "version": "==0.10.1" + }, + "greenlet": { + "hashes": [ + "sha256:09ef2636ea35782364c830f07127d6c7a70542b178268714a9a9ba16318e7e8b", + "sha256:0fef83d43bf87a5196c91e73cb9772f945a4caaff91242766c5916d1dd1381e4", + "sha256:1b7df09c6598f5cfb40f843ade14ed1eb40596e75cd79b6fa2efc750ba01bb01", + "sha256:1fff21a2da5f9e03ddc5bd99131a6b8edf3d7f9d6bc29ba21784323d17806ed7", + "sha256:42118bf608e0288e35304b449a2d87e2ba77d1e373e8aa221ccdea073de026fa", + "sha256:50643fd6d54fd919f9a0a577c5f7b71f5d21f0959ab48767bd4bb73ae0839500", + "sha256:58798b5d30054bb4f6cf0f712f08e6092df23a718b69000786634a265e8911a9", + "sha256:5b49b3049697aeae17ef7bf21267e69972d9e04917658b4e788986ea5cc518e8", + "sha256:75c413551a436b462d5929255b6dc9c0c3c2b25cbeaee5271a56c7fda8ca49c0", + "sha256:769b740aeebd584cd59232be84fdcaf6270b8adc356596cdea5b2152c82caaac", + "sha256:ad2383d39f13534f3ca5c48fe1fc0975676846dc39c2cece78c0f1f9891418e0", + "sha256:b417bb7ff680d43e7bd7a13e2e08956fa6acb11fd432f74c97b7664f8bdb6ec1", + "sha256:b6ef0cabaf5a6ecb5ac122e689d25ba12433a90c7b067b12e5f28bdb7fb78254", + "sha256:c2de19c88bdb0366c976cc125dca1002ec1b346989d59524178adfd395e62421", + "sha256:c7b04a6dc74087b1598de8d713198de4718fa30ec6cbb84959b26426c198e041", + "sha256:f8f2a0ae8de0b49c7b5b2daca4f150fdd9c1173e854df2cce3b04123244f9f45", + "sha256:fcfadaf4bf68a27e5dc2f42cbb2f4b4ceea9f05d1d0b8f7787e640bed2801634" + ], + "version": "==0.4.13" + }, + "gunicorn": { + "hashes": [ + "sha256:eb8d8924b117a609fae9f8cd85df0cad3535dd613fdbcdbba3ee88d5459f1d4f", + "sha256:f5ca088d029fe3cea166c59bb43b7ccc9c850fe25af3da61350fe712c5cc5aa2" + ], + "index": "pypi", + "version": "==19.8.0" + }, + "idna": { + "hashes": [ + "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f", + "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4" + ], + "version": "==2.6" + }, + "itsdangerous": { + "hashes": [ + "sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519" + ], + "version": "==0.24" + }, + "jinja2": { + "hashes": [ + "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", + "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" + ], + "version": "==2.10" + }, + "lazy": { + "hashes": [ + "sha256:c80a77bf7106ba7b27378759900cfefef38271088dc63b014bcfe610c8e68e3d" + ], + "version": "==1.3" + }, + "logmatic-python": { + "hashes": [ + "sha256:0c15ac9f5faa6a60059b28910db642c3dc7722948c3cc940923f8c9039604342" + ], + "index": "pypi", + "version": "==0.1.7" + }, + "markupsafe": { + "hashes": [ + "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" + ], + "version": "==1.0" + }, + "oauthlib": { + "hashes": [ + "sha256:09d438bcac8f004ae348e721e9d8a7792a9e23cd574634e973173344046287f5", + "sha256:909665297635fa11fe9914c146d875f2ed41c8c2d78e21a529dd71c0ba756508" + ], + "version": "==2.0.7" + }, + "pygments": { + "hashes": [ + "sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d", + "sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc" + ], + "index": "pypi", + "version": "==2.2.0" + }, + "python-json-logger": { + "hashes": [ + "sha256:30999d1d742ecf6645991a2ce9273188505e98b713ad63be06aabff47dd1b3c4", + "sha256:8205cfe7061715de5cd1b37e3565d5b97d0ac13b30ff3ee612554abb6093d640" + ], + "version": "==0.1.8" + }, + "requests": { + "hashes": [ + "sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b", + "sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e" + ], + "index": "pypi", + "version": "==2.18.4" + }, + "requests-oauthlib": { + "hashes": [ + "sha256:50a8ae2ce8273e384895972b56193c7409601a66d4975774c60c2aed869639ca", + "sha256:883ac416757eada6d3d07054ec7092ac21c7f35cb1d2cf82faf205637081f468" + ], + "version": "==0.8.0" + }, + "rethinkdb": { + "hashes": [ + "sha256:b5354ecd896b59065693e4139c067f401c9f57970268e9b93f83d869709d1c17" + ], + "index": "pypi", + "version": "==2.3.0.post6" + }, + "schema": { + "hashes": [ + "sha256:410f44cb025384959d20deef00b4e1595397fa30959947a4f0d92e9c84616f35", + "sha256:a058daf5d926e4ece9f13c4c2366a836143ca7913ef053c5023c569e00175b2a" + ], + "index": "pypi", + "version": "==0.6.7" + }, + "six": { + "hashes": [ + "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", + "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" + ], + "version": "==1.11.0" + }, + "ujson": { + "hashes": [ + "sha256:f66073e5506e91d204ab0c614a148d5aa938bdbf104751be66f8ad7a222f5f86" + ], + "index": "pypi", + "version": "==1.35" + }, + "urllib3": { + "hashes": [ + "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b", + "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f" + ], + "version": "==1.22" + }, + "urlobject": { + "hashes": [ + "sha256:47b2e20e6ab9c8366b2f4a3566b6ff4053025dad311c4bb71279bbcfa2430caa" + ], + "version": "==2.4.3" + }, + "werkzeug": { + "hashes": [ + "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c", + "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b" + ], + "version": "==0.14.1" + }, + "wsaccel": { + "hashes": [ + "sha256:425706acf0724d2f6bfa391ec37b4ef121d3432c956029de3cea4e101c218e0c" + ], + "index": "pypi", + "version": "==0.6.2" + }, + "wtforms": { + "hashes": [ + "sha256:ffdf10bd1fa565b8233380cb77a304cd36fd55c73023e91d4b803c96bc11d46f" + ], + "version": "==2.1" + } + }, + "develop": { + "attrs": { + "hashes": [ + "sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9", + "sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450" + ], + "version": "==17.4.0" + }, + "bandit": { + "hashes": [ + "sha256:cb977045497f83ec3a02616973ab845c829cdab8144ce2e757fe031104a9abd4", + "sha256:de4cc19d6ba32d6f542c6a1ddadb4404571347d83ef1ed1e7afb7d0b38e0c25b" + ], + "version": "==1.4.0" + }, + "certifi": { + "hashes": [ + "sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7", + "sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0" + ], + "version": "==2018.4.16" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "click": { + "hashes": [ + "sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d", + "sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b" + ], + "version": "==6.7" + }, + "coverage": { + "hashes": [ + "sha256:00d464797a236f654337181af72b4baea3d35d056ca480e45e9163bb5df496b8", + "sha256:0a90afa6f5ea08889da9066dca3ce2ef85d47587e3f66ca06a4fa8d3a0053acc", + "sha256:0ba6c4345e3c197f6a3ba924d155c402ad28c080ac0d79529493eb17582fbc41", + "sha256:2be3748f45d2eb0259c3c93abccc15c10725ef715bf0817a4c0a1a1dad2abc6a", + "sha256:50727512afe77e044c7d7f2fd4cd0fe62b06527f965b335a810d956748e0514d", + "sha256:6c2fd127cd4e2decb0ab41fe3ac2948b87ad2ea0470e24b4be5f7e7fdfef8df3", + "sha256:6ed521ed3800d8f8911642b9b3c3891780a929db5e572c88c4713c1032530f82", + "sha256:76a73a48a308fb87a4417d630b0345d36166f489ef17ea5aa8e4596fb50a2296", + "sha256:7eaa0a33423476ed63317ee0a53cc07c0e36b5a390e3e95b95152e7eb6b3a6f6", + "sha256:845d0f8a1765074b3256f07ddbce2969e5a5316dfd0eb3289137010d7677326a", + "sha256:85b1275b6d7a61ccc8024a4e9a4c9e896394776edce1a5d075ec116f91925462", + "sha256:8e60e720cad3ee6b0a32f475ae4040552c5623870a9ca0d3d4263faa89a8d96b", + "sha256:93c50475f189cd226e9688b9897a0cd3c4c5d9c90b1733fa8f6445cfc0182c51", + "sha256:94c1e66610807a7917d967ed6415b9d5fde7487ab2a07bb5e054567865ef6ef0", + "sha256:964f86394cb4d0fd2bb40ffcddca321acf4323b48d1aa5a93db8b743c8a00f79", + "sha256:99043494b28d6460035dd9410269cdb437ee460edc7f96f07ab45c57ba95e651", + "sha256:addf63b5e39d573c459c3930b25176146395c1dc1afce4710067bb5e6dc4ea58", + "sha256:af2f59ce312523c384a7826821cae0b95f320fee1751387abba4f00eed737166", + "sha256:af6ed80340e5e1b89fa794f730ce7597651fbda3312e500002688b679c184ef9", + "sha256:beb96d32ce8cfa47ec6433d95a33e4afaa97c19ac1b4a47ea40a424fedfee7c2", + "sha256:c00bac0f6b35b82ace069a6a0d88e8fd4cd18d964fc5e47329cd02b212397fbe", + "sha256:d079e36baceea9707fd50b268305654151011274494a33c608c075808920eda8", + "sha256:d3188345f1c7161d701fd2ea9150f9bb6e2df890f3ddd6c0aea1f525e21d1544", + "sha256:e65c78bde155a734f0d624647c4d6e0f47fb4875355a0b95c37d537788737f4f", + "sha256:e813cba9ff0e3d37ad31dc127fac85d23f9a26d0461ef8042ac4539b2045e781", + "sha256:e96c13a40df389ce8cbb5ec108e5fb834989d1bedff5d8846e5aa3d270a5f3b6", + "sha256:ee2338539157cfc35fb1d6757dd799126804df39393c4a6c5fe88b402c8c0ab4" + ], + "version": "==4.0.3" + }, + "flake8": { + "hashes": [ + "sha256:7253265f7abd8b313e3892944044a365e3f4ac3fcdcfb4298f55ee9ddf188ba0", + "sha256:c7841163e2b576d435799169b78703ad6ac1bbb0f199994fc05f700b2a90ea37" + ], + "index": "pypi", + "version": "==3.5.0" + }, + "flake8-bandit": { + "hashes": [ + "sha256:a66c7b42af9530d5e988851ccee02958a51a85d46f1f4609ecc3546948f809b8", + "sha256:f7c3421fd9aebc63689c0693511e16dcad678fd4a0ce624b78ca91ae713eacdc" + ], + "index": "pypi", + "version": "==1.0.2" + }, + "flake8-bugbear": { + "hashes": [ + "sha256:541746f0f3b2f1a8d7278e1d2d218df298996b60b02677708560db7c7e620e3b", + "sha256:5f14a99d458e29cb92be9079c970030e0dd398b2decb179d76d39a5266ea1578" + ], + "index": "pypi", + "version": "==18.2.0" + }, + "flake8-import-order": { + "hashes": [ + "sha256:40d2a39ed91e080f3285f4c16256b252d7c31070e7f11b7854415bb9f924ea81", + "sha256:68d430781a9ef15c85a0121500cf8462f1a4bc7672acb2a32bfdbcab044ae0b7" + ], + "index": "pypi", + "version": "==0.17.1" + }, + "flake8-polyfill": { + "hashes": [ + "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9", + "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda" + ], + "version": "==1.0.2" + }, + "flake8-string-format": { + "hashes": [ + "sha256:68ea72a1a5b75e7018cae44d14f32473c798cf73d75cbaed86c6a9a907b770b2", + "sha256:774d56103d9242ed968897455ef49b7d6de272000cfa83de5814273a868832f1" + ], + "index": "pypi", + "version": "==0.2.3" + }, + "flake8-tidy-imports": { + "hashes": [ + "sha256:5fc28c82bba16abb4f1154dc59a90487f5491fbdb27e658cbee241e8fddc1b91", + "sha256:c05c9f7dadb5748a04b6fa1c47cb6ae5a8170f03cfb1dca8b37aec58c1ee6d15" + ], + "index": "pypi", + "version": "==1.1.0" + }, + "flask": { + "hashes": [ + "sha256:0749df235e3ff61ac108f69ac178c9770caeaccad2509cb762ce1f65570a8856", + "sha256:49f44461237b69ecd901cc7ce66feea0319b9158743dd27a2899962ab214dac1" + ], + "index": "pypi", + "version": "==0.12.2" + }, + "flask-testing": { + "hashes": [ + "sha256:dc076623d7d850653a018cb64f500948334c8aeb6b10a5a842bf1bcfb98122bc" + ], + "index": "pypi", + "version": "==0.7.1" + }, + "gitdb2": { + "hashes": [ + "sha256:b60e29d4533e5e25bb50b7678bbc187c8f6bcff1344b4f293b2ba55c85795f09", + "sha256:cf9a4b68e8c4da8d42e48728c944ff7af2d8c9db303ac1ab32eac37aa4194b0e" + ], + "version": "==2.0.3" + }, + "gitpython": { + "hashes": [ + "sha256:05069e26177c650b3cb945dd543a7ef7ca449f8db5b73038b465105673c1ef61", + "sha256:c47cc31af6e88979c57a33962cbc30a7c25508d74a1b3a19ec5aa7ed64b03129" + ], + "version": "==2.1.9" + }, + "idna": { + "hashes": [ + "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f", + "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4" + ], + "version": "==2.6" + }, + "itsdangerous": { + "hashes": [ + "sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519" + ], + "version": "==0.24" + }, + "jinja2": { + "hashes": [ + "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", + "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" + ], + "version": "==2.10" + }, + "markupsafe": { + "hashes": [ + "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" + ], + "version": "==1.0" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "more-itertools": { + "hashes": [ + "sha256:0dd8f72eeab0d2c3bd489025bb2f6a1b8342f9b198f6fc37b52d15cfa4531fea", + "sha256:11a625025954c20145b37ff6309cd54e39ca94f72f6bb9576d1195db6fa2442e", + "sha256:c9ce7eccdcb901a2c75d326ea134e0886abfbea5f93e91cc95de9507c0816c44" + ], + "version": "==4.1.0" + }, + "pbr": { + "hashes": [ + "sha256:4e8a0ed6a8705a26768f4c3da26026013b157821fe5f95881599556ea9d91c19", + "sha256:dae4aaa78eafcad10ce2581fc34d694faa616727837fd8e55c1a00951ad6744f" + ], + "version": "==4.0.2" + }, + "pluggy": { + "hashes": [ + "sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff", + "sha256:d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c", + "sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5" + ], + "version": "==0.6.0" + }, + "py": { + "hashes": [ + "sha256:29c9fab495d7528e80ba1e343b958684f4ace687327e6f789a94bf3d1915f881", + "sha256:983f77f3331356039fdd792e9220b7b8ee1aa6bd2b25f567a963ff1de5a64f6a" + ], + "version": "==1.5.3" + }, + "pycodestyle": { + "hashes": [ + "sha256:1ec08a51c901dfe44921576ed6e4c1f5b7ecbad403f871397feedb5eb8e4fa14", + "sha256:5ff2fbcbab997895ba9ead77e1b38b3ebc2e5c3b8a6194ef918666e4c790a00e", + "sha256:682256a5b318149ca0d2a9185d365d8864a768a28db66a84a2ea946bcc426766", + "sha256:6c4245ade1edfad79c3446fadfc96b0de2759662dc29d07d80a6f27ad1ca6ba9" + ], + "version": "==2.3.1" + }, + "pyflakes": { + "hashes": [ + "sha256:08bd6a50edf8cffa9fa09a463063c425ecaaf10d1eb0335a7e8b1401aef89e6f", + "sha256:8d616a382f243dbf19b54743f280b80198be0bca3a5396f1d2e1fca6223e8805" + ], + "version": "==1.6.0" + }, + "pytest": { + "hashes": [ + "sha256:54713b26c97538db6ff0703a12b19aeaeb60b5e599de542e7fca0ec83b9038e8", + "sha256:829230122facf05a5f81a6d4dfe6454a04978ea3746853b2b84567ecf8e5c526" + ], + "index": "pypi", + "version": "==3.5.1" + }, + "pytest-cov": { + "hashes": [ + "sha256:03aa752cf11db41d281ea1d807d954c4eda35cfa1b21d6971966cc041bbf6e2d", + "sha256:890fe5565400902b0c78b5357004aab1c814115894f4f21370e2433256a3eeec" + ], + "index": "pypi", + "version": "==2.5.1" + }, + "python-coveralls": { + "hashes": [ + "sha256:1748272081e0fc21e2c20c12e5bd18cb13272db1b130758df0d473da0cb31087", + "sha256:736dda01f64beda240e1500d5f264b969495b05fcb325c7c0eb7ebbfd1210b70" + ], + "index": "pypi", + "version": "==2.9.1" + }, + "pyyaml": { + "hashes": [ + "sha256:0c507b7f74b3d2dd4d1322ec8a94794927305ab4cebbe89cc47fe5e81541e6e8", + "sha256:16b20e970597e051997d90dc2cddc713a2876c47e3d92d59ee198700c5427736", + "sha256:3262c96a1ca437e7e4763e2843746588a965426550f3797a79fca9c6199c431f", + "sha256:326420cbb492172dec84b0f65c80942de6cedb5233c413dd824483989c000608", + "sha256:4474f8ea030b5127225b8894d626bb66c01cda098d47a2b0d3429b6700af9fd8", + "sha256:592766c6303207a20efc445587778322d7f73b161bd994f227adaa341ba212ab", + "sha256:5ac82e411044fb129bae5cfbeb3ba626acb2af31a8d17d175004b70862a741a7", + "sha256:5f84523c076ad14ff5e6c037fe1c89a7f73a3e04cf0377cb4d017014976433f3", + "sha256:827dc04b8fa7d07c44de11fabbc888e627fa8293b695e0f99cb544fdfa1bf0d1", + "sha256:b4c423ab23291d3945ac61346feeb9a0dc4184999ede5e7c43e1ffb975130ae6", + "sha256:bc6bced57f826ca7cb5125a10b23fd0f2fff3b7c4701d64c439a300ce665fff8", + "sha256:c01b880ec30b5a6e6aa67b09a2fe3fb30473008c85cd6a67359a1b15ed6d83a4", + "sha256:ca233c64c6e40eaa6c66ef97058cdc80e8d0157a443655baa1b2966e812807ca", + "sha256:e863072cdf4c72eebf179342c94e6989c67185842d9997960b3e69290b2fa269" + ], + "version": "==3.12" + }, + "requests": { + "hashes": [ + "sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b", + "sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e" + ], + "index": "pypi", + "version": "==2.18.4" + }, + "six": { + "hashes": [ + "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", + "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" + ], + "version": "==1.11.0" + }, + "smmap2": { + "hashes": [ + "sha256:b78ee0f1f5772d69ff50b1cbdb01b8c6647a8354f02f23b488cf4b2cfc923956", + "sha256:c7530db63f15f09f8251094b22091298e82bf6c699a6b8344aaaef3f2e1276c3" + ], + "version": "==2.0.3" + }, + "stevedore": { + "hashes": [ + "sha256:e3d96b2c4e882ec0c1ff95eaebf7b575a779fd0ccb4c741b9832bed410d58b3d", + "sha256:f1c7518e7b160336040fee272174f1f7b29a46febb3632502a8f2055f973d60b" + ], + "version": "==1.28.0" + }, + "urllib3": { + "hashes": [ + "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b", + "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f" + ], + "version": "==1.22" + }, + "werkzeug": { + "hashes": [ + "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c", + "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b" + ], + "version": "==0.14.1" + } + } +} diff --git a/Vagrant_bootstrap.sh b/Vagrant_bootstrap.sh deleted file mode 100644 index 307107d4..00000000 --- a/Vagrant_bootstrap.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/bash - -# Dependencies -apt-get update -apt-get install -y software-properties-common -apt-get install -y python-software-properties -apt-get install -y curl -apt-get install -y apt-transport-https -add-apt-repository -y ppa:jonathonf/python-3.6 -echo "deb http://download.rethinkdb.com/apt xenial main" | sudo tee /etc/apt/sources.list.d/rethinkdb.list -wget -qO- https://download.rethinkdb.com/apt/pubkey.gpg | sudo apt-key add - -apt-get update - -# Python3.6 -apt-get install -y python3.6 -apt-get install -y python3.6-dev -apt-get install -y build-essential -curl -s https://bootstrap.pypa.io/get-pip.py | python3.6 - -python3.6 -m pip install -r /vagrant/requirements.txt -python3.6 -m pip install -r /vagrant/requirements-ci.txt -python3.6 -m pip install gunicorn - -# RethinkDB -apt-get install -y rethinkdb - -tee /etc/rethinkdb/instances.d/rethinkdb.conf < Date: Sun, 29 Apr 2018 20:27:49 +0100 Subject: Fix for wiki.history.show with slashes in URL --- pysite/views/wiki/history/show.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysite/views/wiki/history/show.py b/pysite/views/wiki/history/show.py index 50fc5d73..00a1dc27 100644 --- a/pysite/views/wiki/history/show.py +++ b/pysite/views/wiki/history/show.py @@ -8,7 +8,7 @@ from pysite.mixins import DBMixin class RevisionsListView(RouteView, DBMixin): - path = "/history/show/" + path = "/history/show/" name = "history.show" table_name = "wiki_revisions" -- cgit v1.2.3 From 75094be179495890594ff7a3321033ec3b44c377 Mon Sep 17 00:00:00 2001 From: Gareth Coles Date: Mon, 30 Apr 2018 10:33:51 +0100 Subject: [Wiki] In-page headers may have icons --- templates/wiki/base.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/wiki/base.html b/templates/wiki/base.html index f53eea65..bc5845ac 100644 --- a/templates/wiki/base.html +++ b/templates/wiki/base.html @@ -39,10 +39,10 @@ {% for header in data.headers %} {% if "sub_headers" in header %}

    • - {{ header.title }} + {{ header.title | safe }}
    • -- cgit v1.2.3 From e71ebff22de819bb6ba3335a5b12b2025f039394 Mon Sep 17 00:00:00 2001 From: Gareth Coles Date: Mon, 30 Apr 2018 10:54:06 +0100 Subject: [Wiki] Small template fixes --- templates/wiki/base.html | 2 +- templates/wiki/page_in_use.html | 1 - templates/wiki/revision_list.html | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/templates/wiki/base.html b/templates/wiki/base.html index bc5845ac..aeb64a2a 100644 --- a/templates/wiki/base.html +++ b/templates/wiki/base.html @@ -47,7 +47,7 @@
    {% else %} -
  • {{ header.title }}
  • +
  • {{ header.title | safe }}
  • {% endif %} {% endfor %}
  • diff --git a/templates/wiki/page_in_use.html b/templates/wiki/page_in_use.html index 4110ee17..1707845c 100644 --- a/templates/wiki/page_in_use.html +++ b/templates/wiki/page_in_use.html @@ -5,7 +5,6 @@ {% block content %}
    -

    The page you requested is currently being edited

    Please try again in a little bit when the lock has expired.

    diff --git a/templates/wiki/revision_list.html b/templates/wiki/revision_list.html index 6eb5b6a8..a1936c32 100644 --- a/templates/wiki/revision_list.html +++ b/templates/wiki/revision_list.html @@ -30,7 +30,7 @@ Compare selections
    {% endblock %} -- cgit v1.2.3 From 87d3c8b8c87144fb527c0811e36165c329388cea Mon Sep 17 00:00:00 2001 From: Gareth Coles Date: Mon, 30 Apr 2018 11:01:22 +0100 Subject: [Wiki] Header icons need a space afterwards --- pysite/rst/__init__.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/pysite/rst/__init__.py b/pysite/rst/__init__.py index ae79f529..97a77f40 100644 --- a/pysite/rst/__init__.py +++ b/pysite/rst/__init__.py @@ -67,12 +67,23 @@ def render(rst: str): if depth == 1: # Top-level header, so just store it in the current header current_header["id"] = match.group(1) - current_header["title"] = match.group(2) + + title = match.group(2) + + if title.startswith(" ", "  ") + + current_header["title"] = title else: # Second-level (or deeper) header, should be stored in a list of sub-headers under the current sub_headers = current_header.get("sub_headers", []) + title = match.group(2) + + if title.startswith(" ", "  ") + sub_headers.append({ "id": match.group(1), - "title": match.group(2) + "title": title }) current_header["sub_headers"] = sub_headers -- cgit v1.2.3 From a1b8dc5e9bfc021a78f73a3ffecd39827327d6a8 Mon Sep 17 00:00:00 2001 From: Gareth Coles Date: Mon, 30 Apr 2018 11:09:51 +0100 Subject: [Wiki] This should completely make headers uniform --- templates/wiki/base.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/templates/wiki/base.html b/templates/wiki/base.html index aeb64a2a..67a60706 100644 --- a/templates/wiki/base.html +++ b/templates/wiki/base.html @@ -39,10 +39,14 @@ {% for header in data.headers %} {% if "sub_headers" in header %}
  • - {{ header.title | safe }} + + {{ header.title | safe }} +
  • -- cgit v1.2.3 From ba68c031aa3a8dc1c0eae9952ab23a6bc1d8eb4a Mon Sep 17 00:00:00 2001 From: Gareth Coles Date: Mon, 30 Apr 2018 11:18:22 +0100 Subject: [Wiki] Icons should all be the same width --- pysite/rst/roles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysite/rst/roles.py b/pysite/rst/roles.py index 00d12dba..abade243 100644 --- a/pysite/rst/roles.py +++ b/pysite/rst/roles.py @@ -40,7 +40,7 @@ def icon_role(_role: str, rawtext: str, text: str, lineno: int, inliner: Inliner return [prb], [msg] - html = f"""""" + html = f"""""" node = nodes.raw(html, html, format="html", **options) return [node], [] -- cgit v1.2.3 From a895e2ebf157d8bb95a3c4693b6d1c52e87e845c Mon Sep 17 00:00:00 2001 From: Gareth Coles Date: Mon, 30 Apr 2018 11:36:12 +0100 Subject: [Wiki] Add Minecraft to the sidebar --- templates/wiki/base.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/templates/wiki/base.html b/templates/wiki/base.html index 67a60706..c6f8deca 100644 --- a/templates/wiki/base.html +++ b/templates/wiki/base.html @@ -66,6 +66,9 @@
  •  Contributing
  • +
  • +  Minecraft +
  • {#
  • active
  • #} {#
  • #} {# Contributing#} -- cgit v1.2.3 From a796d3d76fc1c12bb85659197add8b8805bbf9ba Mon Sep 17 00:00:00 2001 From: Christopher Baklid Date: Mon, 30 Apr 2018 16:16:32 +0200 Subject: restructure docker --- .dockerignore | 1 + Dockerfile | 20 -------------------- Dockerfile.base | 20 -------------------- docker/Dockerfile | 21 +++++++++++++++++++++ docker/Dockerfile.base | 20 ++++++++++++++++++++ scripts/deploy.sh | 2 +- 6 files changed, 43 insertions(+), 41 deletions(-) delete mode 100644 Dockerfile delete mode 100644 Dockerfile.base create mode 100644 docker/Dockerfile create mode 100644 docker/Dockerfile.base diff --git a/.dockerignore b/.dockerignore index 797f4db4..210f85f9 100644 --- a/.dockerignore +++ b/.dockerignore @@ -12,3 +12,4 @@ Vagrantfile .coveragerc .gitignore .travis.yml +docker diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 3899084a..00000000 --- a/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM pythondiscord/site-base:latest - -ENV PIPENV_VENV_IN_PROJECT=1 -ENV PIPENV_IGNORE_VIRTUALENVS=1 -ENV PIPENV_NOSPIN=1 -ENV PIPENV_HIDE_EMOJIS=1 - -RUN pip install pipenv - -COPY . /site -WORKDIR /site -ENV PYTHONPATH=/site - -RUN pipenv clean -RUN pipenv sync - -EXPOSE 10012 - -ENTRYPOINT ["/sbin/tini", "--"] -CMD ["pipenv", "run", "start"] diff --git a/Dockerfile.base b/Dockerfile.base deleted file mode 100644 index c5234997..00000000 --- a/Dockerfile.base +++ /dev/null @@ -1,20 +0,0 @@ -FROM python:3.6-alpine - -RUN apk add --update tini -RUN apk add --update git -RUN apk add --update build-base - -ENV PIPENV_VENV_IN_PROJECT=1 -ENV PIPENV_IGNORE_VIRTUALENVS=1 -ENV PIPENV_NOSPIN=1 -ENV PIPENV_HIDE_EMOJIS=1 - -RUN pip install pipenv - -RUN mkdir /site -COPY Pipfile /site -COPY Pipfile.lock /site -WORKDIR /site -ENV PYTHONPATH=/site - -RUN pipenv sync diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 00000000..cb2b1b5f --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,21 @@ +FROM pythondiscord/site-base:latest + +ENV PIPENV_VENV_IN_PROJECT=1 +ENV PIPENV_IGNORE_VIRTUALENVS=1 +ENV PIPENV_NOSPIN=1 +ENV PIPENV_HIDE_EMOJIS=1 + +RUN pip install pipenv + +RUN mkdir -p /site +COPY . /site +WORKDIR /site +ENV PYTHONPATH=/site + +RUN pipenv clean +RUN pipenv sync + +EXPOSE 10012 + +ENTRYPOINT ["/sbin/tini", "--"] +CMD ["pipenv", "run", "start"] diff --git a/docker/Dockerfile.base b/docker/Dockerfile.base new file mode 100644 index 00000000..87c6fd73 --- /dev/null +++ b/docker/Dockerfile.base @@ -0,0 +1,20 @@ +FROM python:3.6-alpine + +RUN apk add --update tini +RUN apk add --update git +RUN apk add --update build-base + +ENV PIPENV_VENV_IN_PROJECT=1 +ENV PIPENV_IGNORE_VIRTUALENVS=1 +ENV PIPENV_NOSPIN=1 +ENV PIPENV_HIDE_EMOJIS=1 + +RUN pip install pipenv + +RUN mkdir -p /site +COPY Pipfile /site +COPY Pipfile.lock /site +WORKDIR /site +ENV PYTHONPATH=/site + +RUN pipenv sync diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 9bdff580..96723aa6 100644 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -6,7 +6,7 @@ if [[ $TRAVIS_BRANCH == 'master' && $TRAVIS_PULL_REQUEST == 'false' ]]; then echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin echo "Building image" - docker build -t pythondiscord/site:latest . + docker build -t pythondiscord/site:latest -f docker/Dockerfile . echo "Pushing image" docker push pythondiscord/site:latest -- cgit v1.2.3