├── .gitignore ├── README.md ├── docker-compose.yml ├── flask ├── Dockerfile ├── app.ini ├── bot │ └── __init__.py ├── main.py └── requirements.txt ├── img ├── line-bot webhook-url.png ├── sslforfree.png ├── step1 create gcp server.png └── step2 gcp ssh 連線.png ├── nginx ├── Dockerfile └── nginx.conf ├── poetry.lock └── pyproject.toml /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | 10 | # custom 11 | api-key.json 12 | ssl.csr 13 | ssl.key 14 | .flaskenv 15 | 16 | # Distribution / packaging 17 | .Python 18 | build/ 19 | develop-eggs/ 20 | dist/ 21 | downloads/ 22 | eggs/ 23 | .eggs/ 24 | lib/ 25 | lib64/ 26 | parts/ 27 | sdist/ 28 | var/ 29 | wheels/ 30 | pip-wheel-metadata/ 31 | share/python-wheels/ 32 | *.egg-info/ 33 | .installed.cfg 34 | *.egg 35 | MANIFEST 36 | 37 | # PyInstaller 38 | # Usually these files are written by a python script from a template 39 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 40 | *.manifest 41 | *.spec 42 | 43 | # Installer logs 44 | pip-log.txt 45 | pip-delete-this-directory.txt 46 | 47 | # Unit test / coverage reports 48 | htmlcov/ 49 | .tox/ 50 | .nox/ 51 | .coverage 52 | .coverage.* 53 | .cache 54 | nosetests.xml 55 | coverage.xml 56 | *.cover 57 | *.py,cover 58 | .hypothesis/ 59 | .pytest_cache/ 60 | 61 | # Translations 62 | *.mo 63 | *.pot 64 | 65 | # Django stuff: 66 | *.log 67 | local_settings.py 68 | db.sqlite3 69 | db.sqlite3-journal 70 | 71 | # Flask stuff: 72 | instance/ 73 | .webassets-cache 74 | 75 | # Scrapy stuff: 76 | .scrapy 77 | 78 | # Sphinx documentation 79 | docs/_build/ 80 | 81 | # PyBuilder 82 | target/ 83 | 84 | # Jupyter Notebook 85 | .ipynb_checkpoints 86 | 87 | # IPython 88 | profile_default/ 89 | ipython_config.py 90 | 91 | # pyenv 92 | .python-version 93 | 94 | # pipenv 95 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 96 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 97 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 98 | # install all needed dependencies. 99 | #Pipfile.lock 100 | 101 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 102 | __pypackages__/ 103 | 104 | # Celery stuff 105 | celerybeat-schedule 106 | celerybeat.pid 107 | 108 | # SageMath parsed files 109 | *.sage.py 110 | 111 | # Environments 112 | .env 113 | .venv 114 | env/ 115 | venv/ 116 | ENV/ 117 | env.bak/ 118 | venv.bak/ 119 | 120 | # Spyder project settings 121 | .spyderproject 122 | .spyproject 123 | 124 | # Rope project settings 125 | .ropeproject 126 | 127 | # mkdocs documentation 128 | /site 129 | 130 | # mypy 131 | .mypy_cache/ 132 | .dmypy.json 133 | dmypy.json 134 | 135 | # Pyre type checker 136 | .pyre/ 137 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flask-LINE-Bot-GCP 2 | 3 | ### 一. 建立 LINE-Bot 機器人 4 | 5 | #### 1.事前準備 6 | 7 | 首先建立 LINE develops 帳戶,請參考這篇 [Flask – LINE Bot 教學 事前準備篇 (一)](https://www.maxlist.xyz/2020/11/16/flask-line-bot-pre-set/) 8 | * 確認取得 Channel secret 9 | * 確認取得 Channel access token 10 | 11 | #### 2. 建立 Project 12 | 這次的範例 Code,都存放在這邊 [Flask-LINE-Bot-GCP](https://github.com/hsuanchi/Flask-LINE-Bot-GCP),歡迎給星和 Fork 使用 13 | 14 | 2.1 先移動到資料夾 flask 的位置 15 | ``` 16 | $ cd /Flask-LINE-Bot-GCP/flask/ 17 | ``` 18 | 19 | 接下來我們會在資料夾中建立 `.flaskenv` 並將 token 環境變數放進去: 20 | ``` 21 | $ vim .flaskenv 22 | ``` 23 | 24 | ``` 25 | export CHANNEL_ACCESS_TOKEN="/pg7A9LjzlJ0Bxxxx...省略...cDnyilFU=" 26 | export CHANNEL_SECRET='9c5d20481...省略...f81f' 27 | ``` 28 | 29 | 30 | 2.2 再來需要建立 SSL Certificates,因為 LINE 只接收 Https 的協議, 31 | 建議可以使用 https://www.sslforfree.com/ 提供的 SSL Certificates 32 | 33 | 34 | 將拿到的 ssl.csr 和 ssl.key 放在 `nginx` 資料夾中就完成,最後就只剩下部署到 GCP 上囉! 35 | 36 | ### 二. 建立 GCP 虛擬主機 37 | 38 | 在 [Google Cloud Platform](https://cloud.google.com/gcp/?hl=zh-tw) > 選 Compute Engine > 選建立 VM 執行個體,接下來會進入如下附圖畫面: 39 | 40 | 41 | 42 | 1. 選擇想要的地區 43 | 2. 選擇想要的機器類型 44 | 3. 下方防火牆部分,要把允許 HTTP & HTTPS 流量打勾 45 | 46 | 筆者推薦主機部分可以選擇以下三個美國地區,和主機類型選 f1-micro VM 主機 (1 vCPU,0.6 GB 記憶體),因為會適用於 GCP 免費方案 (過試用期後,不會收費),可以參考 [Google 官方文件](https://cloud.google.com/free/docs/gcp-free-tier?hl=zh-TW#always-free) 說明: 47 | 48 | * 奧勒岡州:us-west1 49 | * 愛荷華州:us-central1 50 | * 南卡羅來納州:us-east1 51 | 52 | ### 三. 開始部署 LINE-Bot 於 GCP 上 53 | 54 | 建置好主機後,點擊下圖紅框框內 SSH 進入連線 55 | 56 | 57 | 58 | 59 | 60 | 首先先將權限切換到 root,待會安裝比較方便: 61 | ``` 62 | $ sudo su 63 | ``` 64 | 65 | 接下來我們會需要安裝 git & docker & docker-compose 66 | 1.安裝 Git 67 | ``` 68 | $ sudo apt-get install git 69 | ``` 70 | 2.安裝 curl & Docker 71 | ``` 72 | $ sudo apt-get install -y curl 73 | $ curl -s https://get.docker.com | sudo sh 74 | ``` 75 | 3.安裝 [docker-compose](https://docs.docker.com/compose/install/) 76 | 77 | ``` 78 | $ sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 79 | 80 | $ sudo chmod +x /usr/local/bin/docker-compose 81 | ``` 82 | 4.將剛剛建立好的專案 git clone 到虛擬主機中 83 | ``` 84 | $ git clone https://github.com/hsuanchi/Flask-LINE-Bot-GCP.git 85 | ``` 86 | 87 | 5.移動到資料節內,並使用 docker-compose 啟動 88 | ``` 89 | $ cd Flask-LINE-Bot-GCP 90 | $ docker-compose up --build 91 | ``` 92 | 93 | 94 | 最後只需要將 ip 位置放在 LINE 的 webhook url 上完成啦! 95 | 96 | 97 | 98 | 99 | 本篇文章同步刊登於 [ [Flask 教學] LINE-Bot GCP 部署(Docker+Flask+Nginx)](https://www.maxlist.xyz/2020/12/01/flask-line-bot-docker-flask-nginx-gcp/),如果有遇到任何問題,歡迎私訊或留言,我會盡快回覆您 100 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.7" 2 | 3 | services: 4 | 5 | flask: 6 | build: ./flask 7 | expose: 8 | - 8080 9 | environment: 10 | - TZ=Asia/Taipei 11 | 12 | nginx: 13 | build: ./nginx 14 | ports: 15 | - "80:80" 16 | - "443:443" 17 | depends_on: 18 | - flask 19 | -------------------------------------------------------------------------------- /flask/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | # Use the Python3.7.2 image 3 | FROM python:3.7.2-stretch 4 | 5 | # Set the working directory to /app 6 | WORKDIR /app 7 | 8 | # Install the dependencies 9 | ADD requirements.txt /app/requirements.txt 10 | RUN pip install -r requirements.txt 11 | 12 | # Copy the current directory contents into the container at /app 13 | ADD . /app 14 | 15 | CMD ["uwsgi", "app.ini"] 16 | -------------------------------------------------------------------------------- /flask/app.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | wsgi-file = main.py 3 | callable = app 4 | socket = :8080 5 | processes = 4 6 | threads = 2 7 | master = true 8 | chmod-socket = 660 9 | vacuum = true 10 | die-on-term = true -------------------------------------------------------------------------------- /flask/bot/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from flask import Flask, abort, request 4 | 5 | # https://github.com/line/line-bot-sdk-python 6 | from linebot import LineBotApi, WebhookHandler 7 | from linebot.exceptions import InvalidSignatureError 8 | from linebot.models import MessageEvent, TextMessage, TextSendMessage 9 | 10 | 11 | def create_app(): 12 | 13 | app = Flask(__name__) 14 | 15 | line_bot_api = LineBotApi(os.environ.get("CHANNEL_ACCESS_TOKEN")) 16 | handler = WebhookHandler(os.environ.get("CHANNEL_SECRET")) 17 | 18 | @app.route("/", methods=["GET", "POST"]) 19 | def callback(): 20 | 21 | if request.method == "GET": 22 | return "Hello GCP" 23 | if request.method == "POST": 24 | signature = request.headers["X-Line-Signature"] 25 | body = request.get_data(as_text=True) 26 | 27 | try: 28 | handler.handle(body, signature) 29 | except InvalidSignatureError: 30 | abort(400) 31 | 32 | return "OK" 33 | 34 | 35 | @handler.add(MessageEvent, message=TextMessage) 36 | def handle_message(event): 37 | get_message = event.message.text 38 | 39 | # Send To Line 40 | reply = TextSendMessage(text=f"{get_message}") 41 | line_bot_api.reply_message(event.reply_token, reply) 42 | 43 | 44 | return app 45 | -------------------------------------------------------------------------------- /flask/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from dotenv import load_dotenv 4 | 5 | from bot import create_app 6 | 7 | dotenv_path = os.path.join(os.path.dirname(__file__), ".flaskenv") 8 | if os.path.exists(dotenv_path): 9 | load_dotenv(dotenv_path, override=True) 10 | 11 | 12 | app = create_app() 13 | -------------------------------------------------------------------------------- /flask/requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2020.11.8; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" 2 | chardet==3.0.4; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" 3 | click==7.1.2; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" 4 | flask==1.1.2; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.5.0") 5 | future==0.18.2; python_version >= "2.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" 6 | idna==2.10; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" 7 | itsdangerous==1.1.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" 8 | jinja2==2.11.2; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" 9 | line-bot-sdk==1.17.0 10 | markupsafe==1.1.1; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" 11 | python-dotenv==0.15.0 12 | requests==2.25.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" 13 | urllib3==1.26.2; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version < "4" 14 | uwsgi==2.0.19.1 15 | werkzeug==1.0.1; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" 16 | -------------------------------------------------------------------------------- /img/line-bot webhook-url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hsuanchi/Flask-LINE-Bot-GCP/71aa86d085eb3ee8c27fdd6675dab9cb566e6ec3/img/line-bot webhook-url.png -------------------------------------------------------------------------------- /img/sslforfree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hsuanchi/Flask-LINE-Bot-GCP/71aa86d085eb3ee8c27fdd6675dab9cb566e6ec3/img/sslforfree.png -------------------------------------------------------------------------------- /img/step1 create gcp server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hsuanchi/Flask-LINE-Bot-GCP/71aa86d085eb3ee8c27fdd6675dab9cb566e6ec3/img/step1 create gcp server.png -------------------------------------------------------------------------------- /img/step2 gcp ssh 連線.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hsuanchi/Flask-LINE-Bot-GCP/71aa86d085eb3ee8c27fdd6675dab9cb566e6ec3/img/step2 gcp ssh 連線.png -------------------------------------------------------------------------------- /nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use the Nginx image 2 | FROM nginx 3 | 4 | # Remove the default nginx.conf 5 | RUN rm /etc/nginx/conf.d/default.conf 6 | 7 | # Replace with our own nginx.conf 8 | COPY nginx.conf /etc/nginx/conf.d/ 9 | COPY ssl.csr /etc/nginx/ssl.csr 10 | COPY ssl.key /etc/nginx/ssl.key 11 | -------------------------------------------------------------------------------- /nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | 2 | server { 3 | listen 80; 4 | location / { 5 | expires 1d; 6 | include uwsgi_params; 7 | uwsgi_pass flask:8080; 8 | } 9 | } 10 | 11 | server { 12 | listen 443 ssl; 13 | location / { 14 | expires 1d; 15 | include uwsgi_params; 16 | uwsgi_pass flask:8080; 17 | } 18 | # 憑證與金鑰的路徑 19 | ssl_certificate /etc/nginx/ssl.csr; 20 | ssl_certificate_key /etc/nginx/ssl.key; 21 | } 22 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "appdirs" 3 | version = "1.4.4" 4 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 5 | category = "dev" 6 | optional = false 7 | python-versions = "*" 8 | 9 | [[package]] 10 | name = "black" 11 | version = "20.8b1" 12 | description = "The uncompromising code formatter." 13 | category = "dev" 14 | optional = false 15 | python-versions = ">=3.6" 16 | 17 | [package.dependencies] 18 | appdirs = "*" 19 | click = ">=7.1.2" 20 | mypy-extensions = ">=0.4.3" 21 | pathspec = ">=0.6,<1" 22 | regex = ">=2020.1.8" 23 | toml = ">=0.10.1" 24 | typed-ast = ">=1.4.0" 25 | typing-extensions = ">=3.7.4" 26 | 27 | [package.extras] 28 | colorama = ["colorama (>=0.4.3)"] 29 | d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] 30 | 31 | [[package]] 32 | name = "certifi" 33 | version = "2020.11.8" 34 | description = "Python package for providing Mozilla's CA Bundle." 35 | category = "main" 36 | optional = false 37 | python-versions = "*" 38 | 39 | [[package]] 40 | name = "chardet" 41 | version = "3.0.4" 42 | description = "Universal encoding detector for Python 2 and 3" 43 | category = "main" 44 | optional = false 45 | python-versions = "*" 46 | 47 | [[package]] 48 | name = "click" 49 | version = "7.1.2" 50 | description = "Composable command line interface toolkit" 51 | category = "main" 52 | optional = false 53 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 54 | 55 | [[package]] 56 | name = "flake8" 57 | version = "3.8.4" 58 | description = "the modular source code checker: pep8 pyflakes and co" 59 | category = "dev" 60 | optional = false 61 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" 62 | 63 | [package.dependencies] 64 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 65 | mccabe = ">=0.6.0,<0.7.0" 66 | pycodestyle = ">=2.6.0a1,<2.7.0" 67 | pyflakes = ">=2.2.0,<2.3.0" 68 | 69 | [[package]] 70 | name = "flask" 71 | version = "1.1.2" 72 | description = "A simple framework for building complex web applications." 73 | category = "main" 74 | optional = false 75 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 76 | 77 | [package.dependencies] 78 | click = ">=5.1" 79 | itsdangerous = ">=0.24" 80 | Jinja2 = ">=2.10.1" 81 | Werkzeug = ">=0.15" 82 | 83 | [package.extras] 84 | dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"] 85 | docs = ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"] 86 | dotenv = ["python-dotenv"] 87 | 88 | [[package]] 89 | name = "future" 90 | version = "0.18.2" 91 | description = "Clean single-source support for Python 3 and 2" 92 | category = "main" 93 | optional = false 94 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 95 | 96 | [[package]] 97 | name = "idna" 98 | version = "2.10" 99 | description = "Internationalized Domain Names in Applications (IDNA)" 100 | category = "main" 101 | optional = false 102 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 103 | 104 | [[package]] 105 | name = "importlib-metadata" 106 | version = "3.1.0" 107 | description = "Read metadata from Python packages" 108 | category = "dev" 109 | optional = false 110 | python-versions = ">=3.6" 111 | 112 | [package.dependencies] 113 | zipp = ">=0.5" 114 | 115 | [package.extras] 116 | docs = ["sphinx", "rst.linker"] 117 | testing = ["packaging", "pep517", "unittest2", "importlib-resources (>=1.3)"] 118 | 119 | [[package]] 120 | name = "itsdangerous" 121 | version = "1.1.0" 122 | description = "Various helpers to pass data to untrusted environments and back." 123 | category = "main" 124 | optional = false 125 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 126 | 127 | [[package]] 128 | name = "jinja2" 129 | version = "2.11.2" 130 | description = "A very fast and expressive template engine." 131 | category = "main" 132 | optional = false 133 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 134 | 135 | [package.dependencies] 136 | MarkupSafe = ">=0.23" 137 | 138 | [package.extras] 139 | i18n = ["Babel (>=0.8)"] 140 | 141 | [[package]] 142 | name = "line-bot-sdk" 143 | version = "1.17.0" 144 | description = "LINE Messaging API SDK for Python" 145 | category = "main" 146 | optional = false 147 | python-versions = "*" 148 | 149 | [package.dependencies] 150 | future = "*" 151 | requests = ">=2.0" 152 | 153 | [[package]] 154 | name = "markupsafe" 155 | version = "1.1.1" 156 | description = "Safely add untrusted strings to HTML/XML markup." 157 | category = "main" 158 | optional = false 159 | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" 160 | 161 | [[package]] 162 | name = "mccabe" 163 | version = "0.6.1" 164 | description = "McCabe checker, plugin for flake8" 165 | category = "dev" 166 | optional = false 167 | python-versions = "*" 168 | 169 | [[package]] 170 | name = "mypy-extensions" 171 | version = "0.4.3" 172 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 173 | category = "dev" 174 | optional = false 175 | python-versions = "*" 176 | 177 | [[package]] 178 | name = "pathspec" 179 | version = "0.8.1" 180 | description = "Utility library for gitignore style pattern matching of file paths." 181 | category = "dev" 182 | optional = false 183 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 184 | 185 | [[package]] 186 | name = "pycodestyle" 187 | version = "2.6.0" 188 | description = "Python style guide checker" 189 | category = "dev" 190 | optional = false 191 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 192 | 193 | [[package]] 194 | name = "pyflakes" 195 | version = "2.2.0" 196 | description = "passive checker of Python programs" 197 | category = "dev" 198 | optional = false 199 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 200 | 201 | [[package]] 202 | name = "python-dotenv" 203 | version = "0.15.0" 204 | description = "Add .env support to your django/flask apps in development and deployments" 205 | category = "main" 206 | optional = false 207 | python-versions = "*" 208 | 209 | [package.extras] 210 | cli = ["click (>=5.0)"] 211 | 212 | [[package]] 213 | name = "regex" 214 | version = "2020.11.13" 215 | description = "Alternative regular expression module, to replace re." 216 | category = "dev" 217 | optional = false 218 | python-versions = "*" 219 | 220 | [[package]] 221 | name = "requests" 222 | version = "2.25.0" 223 | description = "Python HTTP for Humans." 224 | category = "main" 225 | optional = false 226 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 227 | 228 | [package.dependencies] 229 | certifi = ">=2017.4.17" 230 | chardet = ">=3.0.2,<4" 231 | idna = ">=2.5,<3" 232 | urllib3 = ">=1.21.1,<1.27" 233 | 234 | [package.extras] 235 | security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] 236 | socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] 237 | 238 | [[package]] 239 | name = "toml" 240 | version = "0.10.2" 241 | description = "Python Library for Tom's Obvious, Minimal Language" 242 | category = "dev" 243 | optional = false 244 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 245 | 246 | [[package]] 247 | name = "typed-ast" 248 | version = "1.4.1" 249 | description = "a fork of Python 2 and 3 ast modules with type comment support" 250 | category = "dev" 251 | optional = false 252 | python-versions = "*" 253 | 254 | [[package]] 255 | name = "typing-extensions" 256 | version = "3.7.4.3" 257 | description = "Backported and Experimental Type Hints for Python 3.5+" 258 | category = "dev" 259 | optional = false 260 | python-versions = "*" 261 | 262 | [[package]] 263 | name = "urllib3" 264 | version = "1.26.2" 265 | description = "HTTP library with thread-safe connection pooling, file post, and more." 266 | category = "main" 267 | optional = false 268 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" 269 | 270 | [package.extras] 271 | brotli = ["brotlipy (>=0.6.0)"] 272 | secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] 273 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] 274 | 275 | [[package]] 276 | name = "uwsgi" 277 | version = "2.0.19.1" 278 | description = "The uWSGI server" 279 | category = "main" 280 | optional = false 281 | python-versions = "*" 282 | 283 | [[package]] 284 | name = "werkzeug" 285 | version = "1.0.1" 286 | description = "The comprehensive WSGI web application library." 287 | category = "main" 288 | optional = false 289 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 290 | 291 | [package.extras] 292 | dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"] 293 | watchdog = ["watchdog"] 294 | 295 | [[package]] 296 | name = "zipp" 297 | version = "3.4.0" 298 | description = "Backport of pathlib-compatible object wrapper for zip files" 299 | category = "dev" 300 | optional = false 301 | python-versions = ">=3.6" 302 | 303 | [package.extras] 304 | docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] 305 | testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] 306 | 307 | [metadata] 308 | lock-version = "1.1" 309 | python-versions = "^3.7" 310 | content-hash = "18d934f9419b8c87cb42537c3d9ce13a733472989fc859e973f98add949366c8" 311 | 312 | [metadata.files] 313 | appdirs = [ 314 | {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, 315 | {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, 316 | ] 317 | black = [ 318 | {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, 319 | ] 320 | certifi = [ 321 | {file = "certifi-2020.11.8-py2.py3-none-any.whl", hash = "sha256:1f422849db327d534e3d0c5f02a263458c3955ec0aae4ff09b95f195c59f4edd"}, 322 | {file = "certifi-2020.11.8.tar.gz", hash = "sha256:f05def092c44fbf25834a51509ef6e631dc19765ab8a57b4e7ab85531f0a9cf4"}, 323 | ] 324 | chardet = [ 325 | {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, 326 | {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, 327 | ] 328 | click = [ 329 | {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, 330 | {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, 331 | ] 332 | flake8 = [ 333 | {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"}, 334 | {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"}, 335 | ] 336 | flask = [ 337 | {file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"}, 338 | {file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"}, 339 | ] 340 | future = [ 341 | {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, 342 | ] 343 | idna = [ 344 | {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, 345 | {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, 346 | ] 347 | importlib-metadata = [ 348 | {file = "importlib_metadata-3.1.0-py2.py3-none-any.whl", hash = "sha256:590690d61efdd716ff82c39ca9a9d4209252adfe288a4b5721181050acbd4175"}, 349 | {file = "importlib_metadata-3.1.0.tar.gz", hash = "sha256:d9b8a46a0885337627a6430db287176970fff18ad421becec1d64cfc763c2099"}, 350 | ] 351 | itsdangerous = [ 352 | {file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"}, 353 | {file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"}, 354 | ] 355 | jinja2 = [ 356 | {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, 357 | {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"}, 358 | ] 359 | line-bot-sdk = [ 360 | {file = "line-bot-sdk-1.17.0.tar.gz", hash = "sha256:5df41f9abc405a9a58a653f2bd39de40ad55a9f69c1e867be761f4e060e14ac1"}, 361 | {file = "line_bot_sdk-1.17.0-py2.py3-none-any.whl", hash = "sha256:8e0d21b03e906f2db5e52aaa470741b843c1e289a92193d5b6d23ecfbb6f2b41"}, 362 | ] 363 | markupsafe = [ 364 | {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, 365 | {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, 366 | {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, 367 | {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, 368 | {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, 369 | {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, 370 | {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, 371 | {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, 372 | {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, 373 | {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, 374 | {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, 375 | {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, 376 | {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, 377 | {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, 378 | {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, 379 | {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, 380 | {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, 381 | {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, 382 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, 383 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, 384 | {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, 385 | {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, 386 | {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, 387 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, 388 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, 389 | {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, 390 | {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, 391 | {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, 392 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, 393 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, 394 | {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, 395 | {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, 396 | {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, 397 | ] 398 | mccabe = [ 399 | {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, 400 | {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, 401 | ] 402 | mypy-extensions = [ 403 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 404 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 405 | ] 406 | pathspec = [ 407 | {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, 408 | {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, 409 | ] 410 | pycodestyle = [ 411 | {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, 412 | {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, 413 | ] 414 | pyflakes = [ 415 | {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, 416 | {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, 417 | ] 418 | python-dotenv = [ 419 | {file = "python-dotenv-0.15.0.tar.gz", hash = "sha256:587825ed60b1711daea4832cf37524dfd404325b7db5e25ebe88c495c9f807a0"}, 420 | {file = "python_dotenv-0.15.0-py2.py3-none-any.whl", hash = "sha256:0c8d1b80d1a1e91717ea7d526178e3882732420b03f08afea0406db6402e220e"}, 421 | ] 422 | regex = [ 423 | {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, 424 | {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, 425 | {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, 426 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, 427 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, 428 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, 429 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, 430 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, 431 | {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, 432 | {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, 433 | {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, 434 | {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, 435 | {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, 436 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, 437 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, 438 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, 439 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, 440 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, 441 | {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, 442 | {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, 443 | {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, 444 | {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, 445 | {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, 446 | {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, 447 | {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, 448 | {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, 449 | {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, 450 | {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, 451 | {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, 452 | {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, 453 | {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, 454 | {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, 455 | {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, 456 | {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, 457 | {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, 458 | {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, 459 | {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, 460 | {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, 461 | {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, 462 | {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, 463 | {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, 464 | ] 465 | requests = [ 466 | {file = "requests-2.25.0-py2.py3-none-any.whl", hash = "sha256:e786fa28d8c9154e6a4de5d46a1d921b8749f8b74e28bde23768e5e16eece998"}, 467 | {file = "requests-2.25.0.tar.gz", hash = "sha256:7f1a0b932f4a60a1a65caa4263921bb7d9ee911957e0ae4a23a6dd08185ad5f8"}, 468 | ] 469 | toml = [ 470 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 471 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 472 | ] 473 | typed-ast = [ 474 | {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, 475 | {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"}, 476 | {file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"}, 477 | {file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"}, 478 | {file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"}, 479 | {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"}, 480 | {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"}, 481 | {file = "typed_ast-1.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:fcf135e17cc74dbfbc05894ebca928ffeb23d9790b3167a674921db19082401f"}, 482 | {file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"}, 483 | {file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"}, 484 | {file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"}, 485 | {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"}, 486 | {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"}, 487 | {file = "typed_ast-1.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:f208eb7aff048f6bea9586e61af041ddf7f9ade7caed625742af423f6bae3298"}, 488 | {file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"}, 489 | {file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"}, 490 | {file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"}, 491 | {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"}, 492 | {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"}, 493 | {file = "typed_ast-1.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:7e4c9d7658aaa1fc80018593abdf8598bf91325af6af5cce4ce7c73bc45ea53d"}, 494 | {file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"}, 495 | {file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"}, 496 | {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, 497 | {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:92c325624e304ebf0e025d1224b77dd4e6393f18aab8d829b5b7e04afe9b7a2c"}, 498 | {file = "typed_ast-1.4.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d648b8e3bf2fe648745c8ffcee3db3ff903d0817a01a12dd6a6ea7a8f4889072"}, 499 | {file = "typed_ast-1.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fac11badff8313e23717f3dada86a15389d0708275bddf766cca67a84ead3e91"}, 500 | {file = "typed_ast-1.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:0d8110d78a5736e16e26213114a38ca35cb15b6515d535413b090bd50951556d"}, 501 | {file = "typed_ast-1.4.1-cp39-cp39-win32.whl", hash = "sha256:b52ccf7cfe4ce2a1064b18594381bccf4179c2ecf7f513134ec2f993dd4ab395"}, 502 | {file = "typed_ast-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:3742b32cf1c6ef124d57f95be609c473d7ec4c14d0090e5a5e05a15269fb4d0c"}, 503 | {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, 504 | ] 505 | typing-extensions = [ 506 | {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, 507 | {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, 508 | {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, 509 | ] 510 | urllib3 = [ 511 | {file = "urllib3-1.26.2-py2.py3-none-any.whl", hash = "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"}, 512 | {file = "urllib3-1.26.2.tar.gz", hash = "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08"}, 513 | ] 514 | uwsgi = [ 515 | {file = "uWSGI-2.0.19.1.tar.gz", hash = "sha256:faa85e053c0b1be4d5585b0858d3a511d2cd10201802e8676060fd0a109e5869"}, 516 | ] 517 | werkzeug = [ 518 | {file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"}, 519 | {file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"}, 520 | ] 521 | zipp = [ 522 | {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, 523 | {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, 524 | ] 525 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "flask-line-bot-gcp" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["hsuanchi "] 6 | 7 | [tool.poetry.dependencies] 8 | python = "^3.7" 9 | Flask = "^1.1.2" 10 | line-bot-sdk = "^1.17.0" 11 | python-dotenv = "^0.15.0" 12 | uWSGI = "^2.0.19" 13 | 14 | [tool.poetry.dev-dependencies] 15 | flake8 = "^3.8.4" 16 | black = "^20.8b1" 17 | 18 | [build-system] 19 | requires = ["poetry-core>=1.0.0"] 20 | build-backend = "poetry.core.masonry.api" 21 | --------------------------------------------------------------------------------