diff --git a/README.md b/README.md index b00ef6ba9..889a89ed7 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,8 @@ FastAPI stands on the shoulders of giants: ## Installation +Create and activate a virtual environment and then install FastAPI: +
```console diff --git a/docs/en/docs/advanced/settings.md b/docs/en/docs/advanced/settings.md index b78f83953..22bf7de20 100644 --- a/docs/en/docs/advanced/settings.md +++ b/docs/en/docs/advanced/settings.md @@ -6,135 +6,17 @@ Most of these settings are variable (can change), like database URLs. And many c For this reason it's common to provide them in environment variables that are read by the application. -## Environment Variables - -/// tip - -If you already know what "environment variables" are and how to use them, feel free to skip to the next section below. - -/// - -An environment variable (also known as "env var") is a variable that lives outside of the Python code, in the operating system, and could be read by your Python code (or by other programs as well). - -You can create and use environment variables in the shell, without needing Python: - -//// tab | Linux, macOS, Windows Bash - -
- -```console -// You could create an env var MY_NAME with -$ export MY_NAME="Wade Wilson" - -// Then you could use it with other programs, like -$ echo "Hello $MY_NAME" - -Hello Wade Wilson -``` - -
- -//// - -//// tab | Windows PowerShell - -
- -```console -// Create an env var MY_NAME -$ $Env:MY_NAME = "Wade Wilson" - -// Use it with other programs, like -$ echo "Hello $Env:MY_NAME" - -Hello Wade Wilson -``` - -
- -//// - -### Read env vars in Python - -You could also create environment variables outside of Python, in the terminal (or with any other method), and then read them in Python. - -For example you could have a file `main.py` with: - -```Python hl_lines="3" -import os - -name = os.getenv("MY_NAME", "World") -print(f"Hello {name} from Python") -``` - -/// tip - -The second argument to `os.getenv()` is the default value to return. - -If not provided, it's `None` by default, here we provide `"World"` as the default value to use. - -/// - -Then you could call that Python program: - -
- -```console -// Here we don't set the env var yet -$ python main.py - -// As we didn't set the env var, we get the default value - -Hello World from Python - -// But if we create an environment variable first -$ export MY_NAME="Wade Wilson" - -// And then call the program again -$ python main.py - -// Now it can read the environment variable - -Hello Wade Wilson from Python -``` - -
- -As environment variables can be set outside of the code, but can be read by the code, and don't have to be stored (committed to `git`) with the rest of the files, it's common to use them for configurations or settings. - -You can also create an environment variable only for a specific program invocation, that is only available to that program, and only for its duration. - -To do that, create it right before the program itself, on the same line: - -
- -```console -// Create an env var MY_NAME in line for this program call -$ MY_NAME="Wade Wilson" python main.py - -// Now it can read the environment variable - -Hello Wade Wilson from Python - -// The env var no longer exists afterwards -$ python main.py - -Hello World from Python -``` - -
- /// tip -You can read more about it at The Twelve-Factor App: Config. +To understand environment variables you can read [Environment Variables](../environment-variables.md){.internal-link target=_blank}. /// -### Types and validation +## Types and validation These environment variables can only handle text strings, as they are external to Python and have to be compatible with other programs and the rest of the system (and even with different operating systems, as Linux, Windows, macOS). -That means that any value read in Python from an environment variable will be a `str`, and any conversion to a different type or validation has to be done in code. +That means that any value read in Python from an environment variable will be a `str`, and any conversion to a different type or any validation has to be done in code. ## Pydantic `Settings` @@ -142,7 +24,7 @@ Fortunately, Pydantic provides a great utility to handle these settings coming f ### Install `pydantic-settings` -First, install the `pydantic-settings` package: +First, make sure you create your [virtual environment](../virtual-environments.md){.internal-link target=_blank}, activate it, and then install the `pydantic-settings` package:
diff --git a/docs/en/docs/advanced/templates.md b/docs/en/docs/advanced/templates.md index 43731ec36..416540ba4 100644 --- a/docs/en/docs/advanced/templates.md +++ b/docs/en/docs/advanced/templates.md @@ -8,7 +8,7 @@ There are utilities to configure it easily that you can use directly in your **F ## Install dependencies -Install `jinja2`: +Make sure you create a [virtual environment](../virtual-environments.md){.internal-link target=_blank}, activate it, and install `jinja2`:
diff --git a/docs/en/docs/advanced/websockets.md b/docs/en/docs/advanced/websockets.md index 9655714b0..44c6c7428 100644 --- a/docs/en/docs/advanced/websockets.md +++ b/docs/en/docs/advanced/websockets.md @@ -4,7 +4,7 @@ You can use diff --git a/docs/en/docs/contributing.md b/docs/en/docs/contributing.md index 63e1f359a..91d5724a8 100644 --- a/docs/en/docs/contributing.md +++ b/docs/en/docs/contributing.md @@ -6,117 +6,13 @@ First, you might want to see the basic ways to [help FastAPI and get help](help- If you already cloned the fastapi repository and you want to deep dive in the code, here are some guidelines to set up your environment. -### Virtual environment with `venv` +### Virtual environment -You can create an isolated virtual local environment in a directory using Python's `venv` module. Let's do this in the cloned repository (where the `requirements.txt` is): - -
- -```console -$ python -m venv env -``` - -
- -That will create a directory `./env/` with the Python binaries, and then you will be able to install packages for that local environment. - -### Activate the environment - -Activate the new environment with: - -//// tab | Linux, macOS - -
- -```console -$ source ./env/bin/activate -``` - -
- -//// - -//// tab | Windows PowerShell - -
- -```console -$ .\env\Scripts\Activate.ps1 -``` - -
- -//// - -//// tab | Windows Bash - -Or if you use Bash for Windows (e.g. Git Bash): - -
- -```console -$ source ./env/Scripts/activate -``` - -
- -//// - -To check it worked, use: - -//// tab | Linux, macOS, Windows Bash - -
- -```console -$ which pip - -some/directory/fastapi/env/bin/pip -``` - -
- -//// - -//// tab | Windows PowerShell - -
- -```console -$ Get-Command pip - -some/directory/fastapi/env/bin/pip -``` - -
- -//// - -If it shows the `pip` binary at `env/bin/pip` then it worked. 🎉 - -Make sure you have the latest pip version on your local environment to avoid errors on the next steps: - -
- -```console -$ python -m pip install --upgrade pip - ----> 100% -``` - -
- -/// tip - -Every time you install a new package with `pip` under that environment, activate the environment again. - -This makes sure that if you use a terminal program installed by that package, you use the one from your local environment and not any other that could be installed globally. - -/// +Follow the instructions to create and activate a [virtual environment](virtual-environments.md){.internal-link target=_blank} for the internal code of `fastapi`. ### Install requirements using pip -After activating the environment as described above: +After activating the environment, install the required packages:
@@ -160,7 +56,19 @@ $ bash scripts/format.sh It will also auto-sort all your imports. -For it to sort them correctly, you need to have FastAPI installed locally in your environment, with the command in the section above using `-e`. +## Tests + +There is a script that you can run locally to test all the code and generate coverage reports in HTML: + +
+ +```console +$ bash scripts/test-cov-html.sh +``` + +
+ +This command generates a directory `./htmlcov/`, if you open the file `./htmlcov/index.html` in your browser, you can explore interactively the regions of code that are covered by the tests, and notice if there is any region missing. ## Docs @@ -482,17 +390,3 @@ Serving at: http://127.0.0.1:8008 * Search for such links in the translated document using the regex `#[^# ]`. * Search in all documents already translated into your language for `your-translated-document.md`. For example VS Code has an option "Edit" -> "Find in Files". * When translating a document, do not "pre-translate" `#hash-parts` that link to headings in untranslated documents. - -## Tests - -There is a script that you can run locally to test all the code and generate coverage reports in HTML: - -
- -```console -$ bash scripts/test-cov-html.sh -``` - -
- -This command generates a directory `./htmlcov/`, if you open the file `./htmlcov/index.html` in your browser, you can explore interactively the regions of code that are covered by the tests, and notice if there is any region missing. diff --git a/docs/en/docs/deployment/manually.md b/docs/en/docs/deployment/manually.md index d70c5e48b..3324a7503 100644 --- a/docs/en/docs/deployment/manually.md +++ b/docs/en/docs/deployment/manually.md @@ -82,7 +82,9 @@ When referring to the remote machine, it's common to call it **server**, but als When you install FastAPI, it comes with a production server, Uvicorn, and you can start it with the `fastapi run` command. -But you can also install an ASGI server manually: +But you can also install an ASGI server manually. + +Make sure you create a [virtual environment](../virtual-environments.md){.internal-link target=_blank}, activate it, and then you can install the server: //// tab | Uvicorn diff --git a/docs/en/docs/deployment/server-workers.md b/docs/en/docs/deployment/server-workers.md index 433371b9d..efde5f3a1 100644 --- a/docs/en/docs/deployment/server-workers.md +++ b/docs/en/docs/deployment/server-workers.md @@ -39,6 +39,8 @@ And then the Gunicorn-compatible **Uvicorn worker** class would be in charge of ## Install Gunicorn and Uvicorn +Make sure you create a [virtual environment](../virtual-environments.md){.internal-link target=_blank}, activate it, and then install `gunicorn`: +
```console diff --git a/docs/en/docs/environment-variables.md b/docs/en/docs/environment-variables.md new file mode 100644 index 000000000..78e82d5af --- /dev/null +++ b/docs/en/docs/environment-variables.md @@ -0,0 +1,300 @@ +# Environment Variables + +/// tip + +If you already know what "environment variables" are and how to use them, feel free to skip this. + +/// + +An environment variable (also known as "**env var**") is a variable that lives **outside** of the Python code, in the **operating system**, and could be read by your Python code (or by other programs as well). + +Environment variables could be useful for handling application **settings**, as part of the **installation** of Python, etc. + +## Create and Use Env Vars + +You can **create** and use environment variables in the **shell (terminal)**, without needing Python: + +//// tab | Linux, macOS, Windows Bash + +
+ +```console +// You could create an env var MY_NAME with +$ export MY_NAME="Wade Wilson" + +// Then you could use it with other programs, like +$ echo "Hello $MY_NAME" + +Hello Wade Wilson +``` + +
+ +//// + +//// tab | Windows PowerShell + +
+ +```console +// Create an env var MY_NAME +$ $Env:MY_NAME = "Wade Wilson" + +// Use it with other programs, like +$ echo "Hello $Env:MY_NAME" + +Hello Wade Wilson +``` + +
+ +//// + +## Read env vars in Python + +You could also create environment variables **outside** of Python, in the terminal (or with any other method), and then **read them in Python**. + +For example you could have a file `main.py` with: + +```Python hl_lines="3" +import os + +name = os.getenv("MY_NAME", "World") +print(f"Hello {name} from Python") +``` + +/// tip + +The second argument to `os.getenv()` is the default value to return. + +If not provided, it's `None` by default, here we provide `"World"` as the default value to use. + +/// + +Then you could call that Python program: + +//// tab | Linux, macOS, Windows Bash + +
+ +```console +// Here we don't set the env var yet +$ python main.py + +// As we didn't set the env var, we get the default value + +Hello World from Python + +// But if we create an environment variable first +$ export MY_NAME="Wade Wilson" + +// And then call the program again +$ python main.py + +// Now it can read the environment variable + +Hello Wade Wilson from Python +``` + +
+ +//// + +//// tab | Windows PowerShell + +
+ +```console +// Here we don't set the env var yet +$ python main.py + +// As we didn't set the env var, we get the default value + +Hello World from Python + +// But if we create an environment variable first +$ $Env:MY_NAME = "Wade Wilson" + +// And then call the program again +$ python main.py + +// Now it can read the environment variable + +Hello Wade Wilson from Python +``` + +
+ +//// + +As environment variables can be set outside of the code, but can be read by the code, and don't have to be stored (committed to `git`) with the rest of the files, it's common to use them for configurations or **settings**. + +You can also create an environment variable only for a **specific program invocation**, that is only available to that program, and only for its duration. + +To do that, create it right before the program itself, on the same line: + +
+ +```console +// Create an env var MY_NAME in line for this program call +$ MY_NAME="Wade Wilson" python main.py + +// Now it can read the environment variable + +Hello Wade Wilson from Python + +// The env var no longer exists afterwards +$ python main.py + +Hello World from Python +``` + +
+ +/// tip + +You can read more about it at The Twelve-Factor App: Config. + +/// + +## Types and Validation + +These environment variables can only handle **text strings**, as they are external to Python and have to be compatible with other programs and the rest of the system (and even with different operating systems, as Linux, Windows, macOS). + +That means that **any value** read in Python from an environment variable **will be a `str`**, and any conversion to a different type or any validation has to be done in code. + +You will learn more about using environment variables for handling **application settings** in the [Advanced User Guide - Settings and Environment Variables](./advanced/settings.md){.internal-link target=_blank}. + +## `PATH` Environment Variable + +There is a **special** environment variable called **`PATH`** that is used by the operating systems (Linux, macOS, Windows) to find programs to run. + +The value of the variable `PATH` is a long string that is made of directories separated by a colon `:` on Linux and macOS, and by a semicolon `;` on Windows. + +For example, the `PATH` environment variable could look like this: + +//// tab | Linux, macOS + +```plaintext +/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin +``` + +This means that the system should look for programs in the directories: + +* `/usr/local/bin` +* `/usr/bin` +* `/bin` +* `/usr/sbin` +* `/sbin` + +//// + +//// tab | Windows + +```plaintext +C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32 +``` + +This means that the system should look for programs in the directories: + +* `C:\Program Files\Python312\Scripts` +* `C:\Program Files\Python312` +* `C:\Windows\System32` + +//// + +When you type a **command** in the terminal, the operating system **looks for** the program in **each of those directories** listed in the `PATH` environment variable. + +For example, when you type `python` in the terminal, the operating system looks for a program called `python` in the **first directory** in that list. + +If it finds it, then it will **use it**. Otherwise it keeps looking in the **other directories**. + +### Installing Python and Updating the `PATH` + +When you install Python, you might be asked if you want to update the `PATH` environment variable. + +//// tab | Linux, macOS + +Let's say you install Python and it ends up in a directory `/opt/custompython/bin`. + +If you say yes to update the `PATH` environment variable, then the installer will add `/opt/custompython/bin` to the `PATH` environment variable. + +It could look like this: + +```plaintext +/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin +``` + +This way, when you type `python` in the terminal, the system will find the Python program in `/opt/custompython/bin` (the last directory) and use that one. + +//// + +//// tab | Windows + +Let's say you install Python and it ends up in a directory `C:\opt\custompython\bin`. + +If you say yes to update the `PATH` environment variable, then the installer will add `C:\opt\custompython\bin` to the `PATH` environment variable. + +```plaintext +C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin +``` + +This way, when you type `python` in the terminal, the system will find the Python program in `C:\opt\custompython\bin` (the last directory) and use that one. + +//// + +This way, when you type `python` in the terminal, the system will find the Python program in `/opt/custompython/bin` (the last directory) and use that one. + +So, if you type: + +
+ +```console +$ python +``` + +
+ +//// tab | Linux, macOS + +The system will **find** the `python` program in `/opt/custompython/bin` and run it. + +It would be roughly equivalent to typing: + +
+ +```console +$ /opt/custompython/bin/python +``` + +
+ +//// + +//// tab | Windows + +The system will **find** the `python` program in `C:\opt\custompython\bin\python` and run it. + +It would be roughly equivalent to typing: + +
+ +```console +$ C:\opt\custompython\bin\python +``` + +
+ +//// + +This information will be useful when learning about [Virtual Environments](virtual-environments.md){.internal-link target=_blank}. + +## Conclusion + +With this you should have a basic understanding of what **environment variables** are and how to use them in Python. + +You can also read more about them in the Wikipedia for Environment Variable. + +In many cases it's not very obvious how environment variables would be useful and applicable right away. But they keep showing up in many different scenarios when you are developing, so it's good to know about them. + +For example, you will need this information in the next section, about [Virtual Environments](virtual-environments.md). diff --git a/docs/en/docs/index.md b/docs/en/docs/index.md index d76ef498b..ac4f4d00f 100644 --- a/docs/en/docs/index.md +++ b/docs/en/docs/index.md @@ -128,6 +128,8 @@ FastAPI stands on the shoulders of giants: ## Installation +Create and activate a virtual environment and then install FastAPI: +
```console diff --git a/docs/en/docs/tutorial/index.md b/docs/en/docs/tutorial/index.md index 5f8c51c4c..386fe5de9 100644 --- a/docs/en/docs/tutorial/index.md +++ b/docs/en/docs/tutorial/index.md @@ -4,9 +4,7 @@ This tutorial shows you how to use **FastAPI** with most of its features, step b Each section gradually builds on the previous ones, but it's structured to separate topics, so that you can go directly to any specific one to solve your specific API needs. -It is also built to work as a future reference. - -So you can come back and see exactly what you need. +It is also built to work as a future reference so you can come back and see exactly what you need. ## Run the code @@ -71,7 +69,9 @@ Using it in your editor is what really shows you the benefits of FastAPI, seeing ## Install FastAPI -The first step is to install FastAPI: +The first step is to install FastAPI. + +Make sure you create a [virtual environment](../virtual-environments.md){.internal-link target=_blank}, activate it, and then **install FastAPI**:
diff --git a/docs/en/docs/tutorial/request-files.md b/docs/en/docs/tutorial/request-files.md index 53d9eefde..9f19596a8 100644 --- a/docs/en/docs/tutorial/request-files.md +++ b/docs/en/docs/tutorial/request-files.md @@ -6,7 +6,11 @@ You can define files to be uploaded by the client using `File`. To receive uploaded files, first install `python-multipart`. -E.g. `pip install python-multipart`. +Make sure you create a [virtual environment](../virtual-environments.md){.internal-link target=_blank}, activate it, and then install it, for example: + +```console +$ pip install python-multipart +``` This is because uploaded files are sent as "form data". diff --git a/docs/en/docs/tutorial/request-forms-and-files.md b/docs/en/docs/tutorial/request-forms-and-files.md index 9b4342652..7830a2ba4 100644 --- a/docs/en/docs/tutorial/request-forms-and-files.md +++ b/docs/en/docs/tutorial/request-forms-and-files.md @@ -6,7 +6,11 @@ You can define files and form fields at the same time using `File` and `Form`. To receive uploaded files and/or form data, first install `python-multipart`. -E.g. `pip install python-multipart`. +Make sure you create a [virtual environment](../virtual-environments.md){.internal-link target=_blank}, activate it, and then install it, for example: + +```console +$ pip install python-multipart +``` /// diff --git a/docs/en/docs/tutorial/request-forms.md b/docs/en/docs/tutorial/request-forms.md index 88b5b86b6..87cfdefbc 100644 --- a/docs/en/docs/tutorial/request-forms.md +++ b/docs/en/docs/tutorial/request-forms.md @@ -6,7 +6,11 @@ When you need to receive form fields instead of JSON, you can use `Form`. To use forms, first install `python-multipart`. -E.g. `pip install python-multipart`. +Make sure you create a [virtual environment](../virtual-environments.md){.internal-link target=_blank}, activate it, and then install it, for example: + +```console +$ pip install python-multipart +``` /// diff --git a/docs/en/docs/tutorial/response-model.md b/docs/en/docs/tutorial/response-model.md index c17e32f90..6a2093e6d 100644 --- a/docs/en/docs/tutorial/response-model.md +++ b/docs/en/docs/tutorial/response-model.md @@ -133,8 +133,17 @@ Here we are declaring a `UserIn` model, it will contain a plaintext password: To use `EmailStr`, first install `email-validator`. -E.g. `pip install email-validator` -or `pip install pydantic[email]`. +Make sure you create a [virtual environment](../virtual-environments.md){.internal-link target=_blank}, activate it, and then install it, for example: + +```console +$ pip install email-validator +``` + +or with: + +```console +$ pip install "pydantic[email]" +``` /// diff --git a/docs/en/docs/tutorial/security/first-steps.md b/docs/en/docs/tutorial/security/first-steps.md index ed427a282..4bd026caf 100644 --- a/docs/en/docs/tutorial/security/first-steps.md +++ b/docs/en/docs/tutorial/security/first-steps.md @@ -56,9 +56,13 @@ Prefer to use the `Annotated` version if possible. The `python-multipart` package is automatically installed with **FastAPI** when you run the `pip install "fastapi[standard]"` command. -However, if you use the `pip install fastapi` command, the `python-multipart` package is not included by default. To install it manually, use the following command: +However, if you use the `pip install fastapi` command, the `python-multipart` package is not included by default. -`pip install python-multipart` +To install it manually, make sure you create a [virtual environment](../../virtual-environments.md){.internal-link target=_blank}, activate it, and then install it with: + +```console +$ pip install python-multipart +``` This is because **OAuth2** uses "form data" for sending the `username` and `password`. diff --git a/docs/en/docs/tutorial/security/oauth2-jwt.md b/docs/en/docs/tutorial/security/oauth2-jwt.md index 52877b916..ba2bfef29 100644 --- a/docs/en/docs/tutorial/security/oauth2-jwt.md +++ b/docs/en/docs/tutorial/security/oauth2-jwt.md @@ -28,7 +28,9 @@ If you want to play with JWT tokens and see how they work, check @@ -70,7 +72,7 @@ It supports many secure hashing algorithms and utilities to work with them. The recommended algorithm is "Bcrypt". -So, install PassLib with Bcrypt: +Make sure you create a [virtual environment](../virtual-environments.md){.internal-link target=_blank}, activate it, and then install PassLib with Bcrypt:
diff --git a/docs/en/docs/tutorial/sql-databases.md b/docs/en/docs/tutorial/sql-databases.md index 0645cc9f1..56971bf9d 100644 --- a/docs/en/docs/tutorial/sql-databases.md +++ b/docs/en/docs/tutorial/sql-databases.md @@ -101,7 +101,9 @@ Now let's see what each file/module does. ## Install `SQLAlchemy` -First you need to install `SQLAlchemy`: +First you need to install `SQLAlchemy`. + +Make sure you create a [virtual environment](../virtual-environments.md){.internal-link target=_blank}, activate it, and then install it, for example:
diff --git a/docs/en/docs/tutorial/testing.md b/docs/en/docs/tutorial/testing.md index 95c8c5bef..06a87e92e 100644 --- a/docs/en/docs/tutorial/testing.md +++ b/docs/en/docs/tutorial/testing.md @@ -12,7 +12,11 @@ With it, you can use `httpx`. -E.g. `pip install httpx`. +Make sure you create a [virtual environment](../virtual-environments.md){.internal-link target=_blank}, activate it, and then install it, for example: + +```console +$ pip install httpx +``` /// @@ -206,7 +210,9 @@ If you have a Pydantic model in your test and you want to send its data to the a ## Run it -After that, you just need to install `pytest`: +After that, you just need to install `pytest`. + +Make sure you create a [virtual environment](../virtual-environments.md){.internal-link target=_blank}, activate it, and then install it, for example:
diff --git a/docs/en/docs/virtual-environments.md b/docs/en/docs/virtual-environments.md new file mode 100644 index 000000000..3c4aa49c1 --- /dev/null +++ b/docs/en/docs/virtual-environments.md @@ -0,0 +1,844 @@ +# Virtual Environments + +When you work in Python projects you probably should use a **virtual environment** (or a similar mechanism) to isolate the packages you install for each project. + +/// info + +If you already know about virtual environments, how to create them and use them, you might want to skip this section. 🤓 + +/// + +/// tip + +A **virtual environment** is different than an **environment variable**. + +An **environment variable** is a variable in the system that can be used by programs. + +A **virtual environment** is a directory with some files in it. + +/// + +/// info + +This page will teach you how to use **virtual environments** and how they work. + +If you are ready to adopt a **tool that manages everything** for you (including installing Python), try uv. + +/// + +## Create a Project + +First, create a directory for your project. + +What I normally do is that I create a directory named `code` inside my home/user directory. + +And inside of that I create one directory per project. + +
+ +```console +// Go to the home directory +$ cd +// Create a directory for all your code projects +$ mkdir code +// Enter into that code directory +$ cd code +// Create a directory for this project +$ mkdir awesome-project +// Enter into that project directory +$ cd awesome-project +``` + +
+ +## Create a Virtual Environment + +When you start working on a Python project **for the first time**, create a virtual environment **inside your project**. + +/// tip + +You only need to do this **once per project**, not every time you work. + +/// + +//// tab | `venv` + +To create a virtual environment, you can use the `venv` module that comes with Python. + +
+ +```console +$ python -m venv .venv +``` + +
+ +/// details | What that command means + +* `python`: use the program called `python` +* `-m`: call a module as a script, we'll tell it which module next +* `venv`: use the module called `venv` that normally comes installed with Python +* `.venv`: create the virtual environment in the new directory `.venv` + +/// + +//// + +//// tab | `uv` + +If you have `uv` installed, you can use it to create a virtual environment. + +
+ +```console +$ uv venv +``` + +
+ +/// tip + +By default, `uv` will create a virtual environment in a directory called `.venv`. + +But you could customize it passing an additional argument with the directory name. + +/// + +//// + +That command creates a new virtual environment in a directory called `.venv`. + +/// details | `.venv` or other name + +You could create the virtual environment in a different directory, but there's a convention of calling it `.venv`. + +/// + +## Activate the Virtual Environment + +Activate the new virtual environment so that any Python command you run or package you install uses it. + +/// tip + +Do this **every time** you start a **new terminal session** to work on the project. + +/// + +//// tab | Linux, macOS + +
+ +```console +$ source .venv/bin/activate +``` + +
+ +//// + +//// tab | Windows PowerShell + +
+ +```console +$ .venv\Scripts\Activate.ps1 +``` + +
+ +//// + +//// tab | Windows Bash + +Or if you use Bash for Windows (e.g. Git Bash): + +
+ +```console +$ source .venv/Scripts/activate +``` + +
+ +//// + +/// tip + +Every time you install a **new package** in that environment, **activate** the environment again. + +This makes sure that if you use a **terminal (CLI) program** installed by that package, you use the one from your virtual environment and not any other that could be installed globally, probably with a different version than what you need. + +/// + +## Check the Virtual Environment is Active + +Check that the virtual environment is active (the previous command worked). + +/// tip + +This is **optional**, but it's a good way to **check** that everything is working as expected and you are using the virtual environment you intended. + +/// + +//// tab | Linux, macOS, Windows Bash + +
+ +```console +$ which python + +/home/user/code/awesome-project/.venv/bin/python +``` + +
+ +If it shows the `python` binary at `.venv/bin/python`, inside of your project (in this case `awesome-project`), then it worked. 🎉 + +//// + +//// tab | Windows PowerShell + +
+ +```console +$ Get-Command python + +C:\Users\user\code\awesome-project\.venv\Scripts\python +``` + +
+ +If it shows the `python` binary at `.venv\Scripts\python`, inside of your project (in this case `awesome-project`), then it worked. 🎉 + +//// + +## Upgrade `pip` + +/// tip + +If you use `uv` you would use it to install things instead of `pip`, so you don't need to upgrade `pip`. 😎 + +/// + +If you are using `pip` to install packages (it comes by default with Python), you should **upgrade** it to the latest version. + +Many exotic errors while installing a package are solved by just upgrading `pip` first. + +/// tip + +You would normally do this **once**, right after you create the virtual environment. + +/// + +Make sure the virtual environment is active (with the command above) and then run: + +
+ +```console +$ python -m pip install --upgrade pip + +---> 100% +``` + +
+ +## Add `.gitignore` + +If you are using **Git** (you should), add a `.gitignore` file to exclude everything in your `.venv` from Git. + +/// tip + +If you used `uv` to create the virtual environment, it already did this for you, you can skip this step. 😎 + +/// + +/// tip + +Do this **once**, right after you create the virtual environment. + +/// + +
+ +```console +$ echo "*" > .venv/.gitignore +``` + +
+ +/// details | What that command means + +* `echo "*"`: will "print" the text `*` in the terminal (the next part changes that a bit) +* `>`: anything printed to the terminal by the command to the left of `>` should not be printed but instead written to the file that goes to the right of `>` +* `.gitignore`: the name of the file where the text should be written + +And `*` for Git means "everything". So, it will ignore everything in the `.venv` directory. + +That command will create a file `.gitignore` with the content: + +```gitignore +* +``` + +/// + +## Install Packages + +After activating the environment, you can install packages in it. + +/// tip + +Do this **once** when installing or upgrading the packages your project needs. + +If you need to upgrade a version or add a new package you would **do this again**. + +/// + +### Install Packages Directly + +If you're in a hurry and don't want to use a file to declare your project's package requirements, you can install them directly. + +/// tip + +It's a (very) good idea to put the packages and versions your program needs in a file (for example `requirements.txt` or `pyproject.toml`). + +/// + +//// tab | `pip` + +
+ +```console +$ pip install "fastapi[standard]" + +---> 100% +``` + +
+ +//// + +//// tab | `uv` + +If you have `uv`: + +
+ +```console +$ uv pip install "fastapi[standard]" +---> 100% +``` + +
+ +//// + +### Install from `requirements.txt` + +If you have a `requirements.txt`, you can now use it to install its packages. + +//// tab | `pip` + +
+ +```console +$ pip install -r requirements.txt +---> 100% +``` + +
+ +//// + +//// tab | `uv` + +If you have `uv`: + +
+ +```console +$ uv pip install -r requirements.txt +---> 100% +``` + +
+ +//// + +/// details | `requirements.txt` + +A `requirements.txt` with some packages could look like: + +```requirements.txt +fastapi[standard]==0.113.0 +pydantic==2.8.0 +``` + +/// + +## Run Your Program + +After you activated the virtual environment, you can run your program, and it will use the Python inside of your virtual environment with the packages you installed there. + +
+ +```console +$ python main.py + +Hello World +``` + +
+ +## Configure Your Editor + +You would probably use an editor, make sure you configure it to use the same virtual environment you created (it will probably autodetect it) so that you can get autocompletion and inline errors. + +For example: + +* VS Code +* PyCharm + +/// tip + +You normally have to do this only **once**, when you create the virtual environment. + +/// + +## Deactivate the Virtual Environment + +Once you are done working on your project you can **deactivate** the virtual environment. + +
+ +```console +$ deactivate +``` + +
+ +This way, when you run `python` it won't try to run it from that virtual environment with the packages installed there. + +## Ready to Work + +Now you're ready to start working on your project. + + + +/// tip + +Do you want to understand what's all that above? + +Continue reading. 👇🤓 + +/// + +## Why Virtual Environments + +To work with FastAPI you need to install Python. + +After that, you would need to **install** FastAPI and any other **packages** you want to use. + +To install packages you would normally use the `pip` command that comes with Python (or similar alternatives). + +Nevertheless, if you just use `pip` directly, the packages would be installed in your **global Python environment** (the global installation of Python). + +### The Problem + +So, what's the problem with installing packages in the global Python environment? + +At some point, you will probably end up writing many different programs that depend on **different packages**. And some of these projects you work on will depend on **different versions** of the same package. 😱 + +For example, you could create a project called `philosophers-stone`, this program depends on another package called **`harry`, using the version `1`**. So, you need to install `harry`. + +```mermaid +flowchart LR + stone(philosophers-stone) -->|requires| harry-1[harry v1] +``` + +Then, at some point later, you create another project called `prisoner-of-azkaban`, and this project also depends on `harry`, but this project needs **`harry` version `3`**. + +```mermaid +flowchart LR + azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3] +``` + +But now the problem is, if you install the packages globally (in the global environment) instead of in a local **virtual environment**, you will have to choose which version of `harry` to install. + +If you want to run `philosophers-stone` you will need to first install `harry` version `1`, for example with: + +
+ +```console +$ pip install "harry==1" +``` + +
+ +And then you would end up with `harry` version `1` installed in your global Python environment. + +```mermaid +flowchart LR + subgraph global[global env] + harry-1[harry v1] + end + subgraph stone-project[philosophers-stone project] + stone(philosophers-stone) -->|requires| harry-1 + end +``` + +But then if you want to run `prisoner-of-azkaban`, you will need to uninstall `harry` version `1` and install `harry` version `3` (or just installing version `3` would automatically uninstall version `1`). + +
+ +```console +$ pip install "harry==3" +``` + +
+ +And then you would end up with `harry` version `3` installed in your global Python environment. + +And if you try to run `philosophers-stone` again, there's a chance it would **not work** because it needs `harry` version `1`. + +```mermaid +flowchart LR + subgraph global[global env] + harry-1[harry v1] + style harry-1 fill:#ccc,stroke-dasharray: 5 5 + harry-3[harry v3] + end + subgraph stone-project[philosophers-stone project] + stone(philosophers-stone) -.-x|⛔️| harry-1 + end + subgraph azkaban-project[prisoner-of-azkaban project] + azkaban(prisoner-of-azkaban) --> |requires| harry-3 + end +``` + +/// tip + +It's very common in Python packages to try the best to **avoid breaking changes** in **new versions**, but it's better to be safe, and install newer versions intentionally and when you can run the tests to check everything is working correctly. + +/// + +Now, imagine that with **many** other **packages** that all your **projects depend on**. That's very difficult to manage. And you would probably end up running some projects with some **incompatible versions** of the packages, and not knowing why something isn't working. + +Also, depending on your operating system (e.g. Linux, Windows, macOS), it could have come with Python already installed. And in that case it probably had some packages pre-installed with some specific versions **needed by your system**. If you install packages in the global Python environment, you could end up **breaking** some of the programs that came with your operating system. + +## Where are Packages Installed + +When you install Python, it creates some directories with some files in your computer. + +Some of these directories are the ones in charge of having all the packages you install. + +When you run: + +
+ +```console +// Don't run this now, it's just an example 🤓 +$ pip install "fastapi[standard]" +---> 100% +``` + +
+ +That will download a compressed file with the FastAPI code, normally from PyPI. + +It will also **download** files for other packages that FastAPI depends on. + +Then it will **extract** all those files and put them in a directory in your computer. + +By default, it will put those files downloaded and extracted in the directory that comes with your Python installation, that's the **global environment**. + +## What are Virtual Environments + +The solution to the problems of having all the packages in the global environment is to use a **virtual environment for each project** you work on. + +A virtual environment is a **directory**, very similar to the global one, where you can install the packages for a project. + +This way, each project will have it's own virtual environment (`.venv` directory) with its own packages. + +```mermaid +flowchart TB + subgraph stone-project[philosophers-stone project] + stone(philosophers-stone) --->|requires| harry-1 + subgraph venv1[.venv] + harry-1[harry v1] + end + end + subgraph azkaban-project[prisoner-of-azkaban project] + azkaban(prisoner-of-azkaban) --->|requires| harry-3 + subgraph venv2[.venv] + harry-3[harry v3] + end + end + stone-project ~~~ azkaban-project +``` + +## What Does Activating a Virtual Environment Mean + +When you activate a virtual environment, for example with: + +//// tab | Linux, macOS + +
+ +```console +$ source .venv/bin/activate +``` + +
+ +//// + +//// tab | Windows PowerShell + +
+ +```console +$ .venv\Scripts\Activate.ps1 +``` + +
+ +//// + +//// tab | Windows Bash + +Or if you use Bash for Windows (e.g. Git Bash): + +
+ +```console +$ source .venv/Scripts/activate +``` + +
+ +//// + +That command will create or modify some [environment variables](environment-variables.md){.internal-link target=_blank} that will be available for the next commands. + +One of those variables is the `PATH` variable. + +/// tip + +You can learn more about the `PATH` environment variable in the [Environment Variables](environment-variables.md#path-environment-variable){.internal-link target=_blank} section. + +/// + +Activating a virtual environment adds its path `.venv/bin` (on Linux and macOS) or `.venv\Scripts` (on Windows) to the `PATH` environment variable. + +Let's say that before activating the environment, the `PATH` variable looked like this: + +//// tab | Linux, macOS + +```plaintext +/usr/bin:/bin:/usr/sbin:/sbin +``` + +That means that the system would look for programs in: + +* `/usr/bin` +* `/bin` +* `/usr/sbin` +* `/sbin` + +//// + +//// tab | Windows + +```plaintext +C:\Windows\System32 +``` + +That means that the system would look for programs in: + +* `C:\Windows\System32` + +//// + +After activating the virtual environment, the `PATH` variable would look something like this: + +//// tab | Linux, macOS + +```plaintext +/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin +``` + +That means that the system will now start looking first look for programs in: + +```plaintext +/home/user/code/awesome-project/.venv/bin +``` + +before looking in the other directories. + +So, when you type `python` in the terminal, the system will find the Python program in + +```plaintext +/home/user/code/awesome-project/.venv/bin/python +``` + +and use that one. + +//// + +//// tab | Windows + +```plaintext +C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32 +``` + +That means that the system will now start looking first look for programs in: + +```plaintext +C:\Users\user\code\awesome-project\.venv\Scripts +``` + +before looking in the other directories. + +So, when you type `python` in the terminal, the system will find the Python program in + +```plaintext +C:\Users\user\code\awesome-project\.venv\Scripts\python +``` + +and use that one. + +//// + +An important detail is that it will put the virtual environment path at the **beginning** of the `PATH` variable. The system will find it **before** finding any other Python available. This way, when you run `python`, it will use the Python **from the virtual environment** instead of any other `python` (for example, a `python` from a global environment). + +Activating a virtual environment also changes a couple of other things, but this is one of the most important things it does. + +## Checking a Virtual Environment + +When you check if a virtual environment is active, for example with: + +//// tab | Linux, macOS, Windows Bash + +
+ +```console +$ which python + +/home/user/code/awesome-project/.venv/bin/python +``` + +
+ +//// + +//// tab | Windows PowerShell + +
+ +```console +$ Get-Command python + +C:\Users\user\code\awesome-project\.venv\Scripts\python +``` + +
+ +//// + +That means that the `python` program that will be used is the one **in the virtual environment**. + +you use `which` in Linux and macOS and `Get-Command` in Windows PowerShell. + +The way that command works is that it will go and check in the `PATH` environment variable, going through **each path in order**, looking for the program called `python`. Once it finds it, it will **show you the path** to that program. + +The most important part is that when you call `python`, that is the exact "`python`" that will be executed. + +So, you can confirm if you are in the correct virtual environment. + +/// tip + +It's easy to activate one virtual environment, get one Python, and then **go to another project**. + +And the second project **wouldn't work** because you are using the **incorrect Python**, from a virtual environment for another project. + +It's useful being able to check what `python` is being used. 🤓 + +/// + +## Why Deactivate a Virtual Environment + +For example, you could be working on a project `philosophers-stone`, **activate that virtual environment**, install packages and work with that environment. + +And then you want to work on **another project** `prisoner-of-azkaban`. + +You go to that project: + +
+ +```console +$ cd ~/code/prisoner-of-azkaban +``` + +
+ +If you don't deactivate the virtual environment for `philosophers-stone`, when you run `python` in the terminal, it will try to use the Python from `philosophers-stone`. + +
+ +```console +$ cd ~/code/prisoner-of-azkaban + +$ python main.py + +// Error importing sirius, it's not installed 😱 +Traceback (most recent call last): + File "main.py", line 1, in + import sirius +``` + +
+ +But if you deactivate the virtual environment and activate the new one for `prisoner-of-askaban` then when you run `python` it will use the Python from the virtual environment in `prisoner-of-azkaban`. + +
+ +```console +$ cd ~/code/prisoner-of-azkaban + +// You don't need to be in the old directory to deactivate, you can do it wherever you are, even after going to the other project 😎 +$ deactivate + +// Activate the virtual environment in prisoner-of-azkaban/.venv 🚀 +$ source .venv/bin/activate + +// Now when you run python, it will find the package sirius installed in this virtual environment ✨ +$ python main.py + +I solemnly swear 🐺 +``` + +
+ +## Alternatives + +This is a simple guide to get you started and teach you how everything works **underneath**. + +There are many **alternatives** to managing virtual environments, package dependencies (requirements), projects. + +Once you are ready and want to use a tool to **manage the entire project**, packages dependencies, virtual environments, etc. I would suggest you try uv. + +`uv` can do a lot of things, it can: + +* **Install Python** for you, including different versions +* Manage the **virtual environment** for your projects +* Install **packages** +* Manage package **dependencies and versions** for your project +* Make sure you have an **exact** set of packages and versions to install, including their dependencies, so that you can be sure that you can run your project in production exactly the same as in your computer while developing, this is called **locking** +* And many other things + +## Conclusion + +If you read and understood all this, now **you know much more** about virtual environments than many developers out there. 🤓 + +Knowing these details will most probably be useful in a future time when you are debugging something that seems complex, but you will know **how it all works underneath**. 😎 diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index d0527ca3c..6f1e12511 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -108,6 +108,8 @@ nav: - learn/index.md - python-types.md - async.md + - environment-variables.md + - virtual-environments.md - Tutorial - User Guide: - tutorial/index.md - tutorial/first-steps.md