├── .devcontainer └── devcontainer.json ├── .dockerignore ├── .github └── dependabot.yml ├── .gitignore ├── .vscode ├── launch.json └── settings.json ├── Dockerfile ├── LICENSE ├── README.md ├── SECURITY.md ├── hello_app ├── __init__.py ├── static │ ├── data.json │ └── site.css ├── templates │ ├── about.html │ ├── contact.html │ ├── hello_there.html │ ├── home.html │ └── layout.html ├── views.py └── webapp.py ├── requirements.txt ├── startup.py ├── startup.txt ├── test_test1.py └── uwsgi.ini /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/python 3 | { 4 | "name": "Python VS Code Flask Tutorial", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/python:1-3.12-bullseye", 7 | 8 | // Features to add to the dev container. More info: https://containers.dev/features. 9 | // "features": {}, 10 | 11 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 12 | // "forwardPorts": [], 13 | 14 | // Use 'postCreateCommand' to run commands after the container is created. 15 | "postCreateCommand": "pip3 install --user -r requirements.txt", 16 | 17 | // Configure tool-specific properties. 18 | "customizations": { 19 | "vscode": { 20 | "extensions": [ 21 | "ms-python.python", 22 | "ms-python.black-formatter", 23 | "ms-python.vscode-pylance", 24 | "charliermarsh.ruff", 25 | "ms-python.debugpy" 26 | ] 27 | } 28 | } 29 | 30 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 31 | // "remoteUser": "root" 32 | } 33 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | Dockerfile* 4 | docker-compose* 5 | .dockerignore 6 | .git 7 | .gitignore 8 | README.md 9 | LICENSE 10 | .vscode 11 | __pycache__ 12 | env 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for more information: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | # https://containers.dev/guide/dependabot 6 | 7 | version: 2 8 | updates: 9 | - package-ecosystem: "devcontainers" 10 | directory: "/" 11 | schedule: 12 | interval: weekly 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | .vscode/ 107 | settings.json 108 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python Debugger: Flask", 9 | "type": "debugpy", 10 | "request": "launch", 11 | "module": "flask", 12 | "env": { 13 | "FLASK_APP": "hello_app.webapp", 14 | "FLASK_DEBUG": "1" 15 | }, 16 | "args": [ 17 | "run", 18 | "--no-debugger", 19 | "--no-reload" 20 | ], 21 | "jinja": true, 22 | "justMyCode": true 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": "${workspaceFolder}\\env\\Scripts\\python.exe" 3 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Pull a pre-built alpine docker image with nginx and python3 installed 2 | FROM tiangolo/uwsgi-nginx:python3.8-alpine-2020-12-19 3 | 4 | # Set the port on which the app runs; make both values the same. 5 | # 6 | # IMPORTANT: When deploying to Azure App Service, go to the App Service on the Azure 7 | # portal, navigate to the Applications Settings blade, and create a setting named 8 | # WEBSITES_PORT with a value that matches the port here (the Azure default is 80). 9 | # You can also create a setting through the App Service Extension in VS Code. 10 | ENV LISTEN_PORT=5000 11 | EXPOSE 5000 12 | 13 | # Indicate where uwsgi.ini lives 14 | ENV UWSGI_INI uwsgi.ini 15 | 16 | # Tell nginx where static files live. Typically, developers place static files for 17 | # multiple apps in a shared folder, but for the purposes here we can use the one 18 | # app's folder. Note that when multiple apps share a folder, you should create subfolders 19 | # with the same name as the app underneath "static" so there aren't any collisions 20 | # when all those static files are collected together. 21 | ENV STATIC_URL /hello_app/static 22 | 23 | # Set the folder where uwsgi looks for the app 24 | WORKDIR /hello_app 25 | 26 | # Copy the app contents to the image 27 | COPY . /hello_app 28 | 29 | # If you have additional requirements beyond Flask (which is included in the 30 | # base image), generate a requirements.txt file with pip freeze and uncomment 31 | # the next three lines. 32 | #COPY requirements.txt / 33 | #RUN pip install --no-cache-dir -U pip 34 | #RUN pip install --no-cache-dir -r /requirements.txt 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python/Flask Tutorial for Visual Studio Code 2 | 3 | * This sample contains the completed program from the tutorial, make sure to visit the link: [Using Flask in Visual Studio Code](https://code.visualstudio.com/docs/python/tutorial-flask). Intermediate steps are not included. 4 | 5 | * It also contains the *Dockerfile* and *uwsgi.ini* files necessary to build a container with a production server. The resulting image works both locally and when deployed to Azure App Service. See [Deploy Python using Docker containers](https://code.visualstudio.com/docs/python/tutorial-deploy-containers). 6 | 7 | * To run the app locally: 8 | 1. Run the command `cd hello_app`, to change into the folder that contains the Flask app. 9 | 1. Run the command `set FLASK_APP=webapp` (Windows cmd) or `FLASK_APP=webapp` (macOS/Linux) to point to the app module. 10 | 1. Start the Flask server with `flask run`. 11 | 12 | ## The startup.py file 13 | 14 | In the root folder, the `startup.py` file is specifically for deploying to Azure App Service on Linux without using a containerized version of the app (that is, deploying the code directly, not as a container). 15 | 16 | Because the app code is in its own *module* in the `hello_app` folder (which has an `__init__.py`), trying to start the Gunicorn server within App Service on Linux produces an "Attempted relative import in non-package" error. 17 | 18 | The `startup.py` file, therefore, is a shim to import the app object from the `hello_app` module, which then allows you to use startup:app in the Gunicorn command line (see `startup.txt`). 19 | 20 | ## Contributing 21 | 22 | Contributions to the sample are welcome. When submitting changes, also consider submitting matching changes to the tutorial, the source file for which is [tutorial-flask.md](https://github.com/Microsoft/vscode-docs/blob/master/docs/python/tutorial-flask.md). 23 | 24 | Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com. 25 | 26 | When you submit a pull request, a CLA-bot automatically determines whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. 27 | 28 | ## Additional details 29 | 30 | * This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 31 | * For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 32 | * Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 33 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /hello_app/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Flask # Import the Flask class 2 | app = Flask(__name__) # Create an instance of the class for our use 3 | -------------------------------------------------------------------------------- /hello_app/static/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "01": { 3 | "note" : "Data is very simple because we're demonstrating only the mechanism." 4 | } 5 | } -------------------------------------------------------------------------------- /hello_app/static/site.css: -------------------------------------------------------------------------------- 1 | .message { 2 | font-weight: 600; 3 | color: blue; 4 | } 5 | 6 | .navbar { 7 | background-color: lightslategray; 8 | font-size: 1em; 9 | font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; 10 | color: white; 11 | padding: 8px 5px 8px 5px; 12 | } 13 | 14 | .navbar a { 15 | text-decoration: none; 16 | color: inherit; 17 | } 18 | 19 | .navbar-brand { 20 | font-size: 1.2em; 21 | font-weight: 600; 22 | } 23 | 24 | .navbar-item { 25 | font-variant: small-caps; 26 | margin-left: 30px; 27 | } 28 | 29 | .body-content { 30 | padding: 5px; 31 | font-family:'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; 32 | } -------------------------------------------------------------------------------- /hello_app/templates/about.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %} 3 | About us 4 | {% endblock %} 5 | {% block content %} 6 |

About page for the Visual Studio Code Flask tutorial.

7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /hello_app/templates/contact.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %} 3 | Contact us 4 | {% endblock %} 5 | {% block content %} 6 |

Contact page for the Visual Studio Code Flask tutorial.

7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /hello_app/templates/hello_there.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Hello, Flask 7 | 8 | 9 | {%if name %} 10 | Hello there, {{ name }}! It's {{ date.strftime("%A, %d %B, %Y at %X") }}. 11 | {% else %} 12 | What's your name? Provide it after /hello/ in the URL. 13 | {% endif %} 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /hello_app/templates/home.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %} 3 | Home 4 | {% endblock %} 5 | {% block content %} 6 |

Home page for the Visual Studio Code Flask tutorial.

7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /hello_app/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% block title %}{% endblock %} 6 | 7 | 8 | 9 | 10 | 15 | 16 |
17 | {% block content %} 18 | {% endblock %} 19 |
20 | 23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /hello_app/views.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from flask import Flask, render_template 3 | from . import app 4 | 5 | @app.route("/") 6 | def home(): 7 | return render_template("home.html") 8 | 9 | @app.route("/about/") 10 | def about(): 11 | return render_template("about.html") 12 | 13 | @app.route("/contact/") 14 | def contact(): 15 | return render_template("contact.html") 16 | 17 | @app.route("/hello/") 18 | @app.route("/hello/") 19 | def hello_there(name = None): 20 | return render_template( 21 | "hello_there.html", 22 | name=name, 23 | date=datetime.now() 24 | ) 25 | 26 | @app.route("/api/data") 27 | def get_data(): 28 | return app.send_static_file("data.json") 29 | -------------------------------------------------------------------------------- /hello_app/webapp.py: -------------------------------------------------------------------------------- 1 | # Entry point for the application. 2 | from . import app # For application discovery by the 'flask' command. 3 | from . import views # For import side-effects of setting up routes. 4 | 5 | # Time-saver: output a URL to the VS Code terminal so you can easily Ctrl+click to open a browser 6 | # print('http://127.0.0.1:5000/hello/VSCode') 7 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask 2 | -------------------------------------------------------------------------------- /startup.py: -------------------------------------------------------------------------------- 1 | """ 2 | In this sample, the Flask app object is contained within the hello_app *module*; 3 | that is, hello_app contains an __init__.py along with relative imports. Because 4 | of this structure, a file like webapp.py cannot be run directly as the startup 5 | file through Gunicorn; the result is "Attempted relative import in non-package". 6 | 7 | The solution is to provide a simple alternate startup file, like this present 8 | startup.py, that just imports the app object. You can then just specify 9 | startup:app in the Gunicorn command. 10 | """ 11 | 12 | from hello_app.webapp import app 13 | -------------------------------------------------------------------------------- /startup.txt: -------------------------------------------------------------------------------- 1 | gunicorn --bind=0.0.0.0 --workers=4 startup:app 2 | -------------------------------------------------------------------------------- /test_test1.py: -------------------------------------------------------------------------------- 1 | def test_mock(): 2 | assert True 3 | -------------------------------------------------------------------------------- /uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | module = hello_app.webapp 3 | callable = app 4 | uid = 1000 5 | master = true 6 | threads = 2 7 | processes = 4 8 | --------------------------------------------------------------------------------