]> git.ipfire.org Git - thirdparty/fastapi/sqlmodel.git/commitdiff
📝 Recommend uv projects by default in docs uvdocs 2050/head
authorSebastián Ramírez <tiangolo@gmail.com>
Tue, 21 Jul 2026 21:57:21 +0000 (23:57 +0200)
committerSebastián Ramírez <tiangolo@gmail.com>
Tue, 21 Jul 2026 21:57:21 +0000 (23:57 +0200)
32 files changed:
README.md
docs/advanced/decimal.md
docs/advanced/uuid.md
docs/environment-variables.md
docs/index.md
docs/install.md
docs/tutorial/automatic-id-none-refresh.md
docs/tutorial/code-structure.md
docs/tutorial/connect/create-connected-rows.md
docs/tutorial/connect/create-connected-tables.md
docs/tutorial/connect/read-connected-data.md
docs/tutorial/connect/remove-data-connections.md
docs/tutorial/connect/update-data-connections.md
docs/tutorial/create-db-and-table-with-db-browser.md
docs/tutorial/create-db-and-table.md
docs/tutorial/delete.md
docs/tutorial/fastapi/simple-hero-api.md
docs/tutorial/fastapi/tests.md
docs/tutorial/indexes.md
docs/tutorial/insert.md
docs/tutorial/limit-and-offset.md
docs/tutorial/many-to-many/create-data.md
docs/tutorial/many-to-many/create-models-with-link.md
docs/tutorial/many-to-many/link-with-extra-fields.md
docs/tutorial/many-to-many/update-remove-relationships.md
docs/tutorial/one.md
docs/tutorial/relationship-attributes/cascade-delete-relationships.md
docs/tutorial/relationship-attributes/read-relationships.md
docs/tutorial/update.md
docs/tutorial/where.md
docs/virtual-environments.md
mkdocs.yml

index 16ab3f86ddd4e78ef112e48bb6483c58626b4e91..f5864de908771aec59e17eec69d7d2c48d980d4e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -62,18 +62,19 @@ As **SQLModel** is based on **Pydantic** and **SQLAlchemy**, it requires them. T
 
 ## Installation
 
-Make sure you create a [virtual environment](https://sqlmodel.tiangolo.com/virtual-environments/), activate it, and then install SQLModel, for example with:
+First, [install `uv`](https://docs.astral.sh/uv/getting-started/installation/), and then add SQLModel to your project:
 
 <div class="termy">
 
 ```console
-$ pip install sqlmodel
+$ uv add sqlmodel
 ---> 100%
-Successfully installed sqlmodel
 ```
 
 </div>
 
+If you prefer to use `pip`, install `sqlmodel` inside a virtual environment. See the [installation guide](install.md) for the alternative steps.
+
 ## Example
 
 For an introduction to databases, SQL, and everything else, see the [SQLModel documentation](https://sqlmodel.tiangolo.com/databases/).
index 465fe8bea8dfd65b8d68af1437c1854005de8695..02b84ab8be872fa0e32e95b4dda34c9470143a4f 100644 (file)
@@ -82,7 +82,7 @@ Now if you run this, instead of printing the unexpected number `3.30000000000000
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate and previous output omitted 😉
 
index ff90c0bf7b080b69a8aca6f46f1006210ef5a6c5..833ced4b7f5513a2a8886917d04595b2d3b64d12 100644 (file)
@@ -127,7 +127,7 @@ If you run the program, you will see the **UUID** generated in the Python code,
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate and previous output omitted 😉
 
index 4d5a6983e74a5e9adbb2fe567034c53cdd2ea562..d64f41a872be498ba1da54a45a22fe78986bc1aa 100644 (file)
@@ -1,300 +1,9 @@
 # Environment Variables
 
-Before we jump into code, let's cover a bit some of the **basics** that we'll need to understand how to work with Python (and programming) in general. Let's check a bit about **environment variables**.
+An **environment variable** (also known as an **env var**) is a value that lives outside of your Python code, in the operating system, and can be read by your application and other programs.
 
-/// tip
+Applications commonly use environment variables for configuration such as database URLs, credentials, and secret keys.
 
-If you already know what "environment variables" are and how to use them, feel free to skip this.
+## Learn More { #learn-more }
 
-///
-
-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
-
-<div class="termy">
-
-```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
-```
-
-</div>
-
-////
-
-//// tab | Windows PowerShell
-
-<div class="termy">
-
-```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
-```
-
-</div>
-
-////
-
-## 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()`](https://docs.python.org/3.8/library/os.html#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
-
-<div class="termy">
-
-```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
-```
-
-</div>
-
-////
-
-//// tab | Windows PowerShell
-
-<div class="termy">
-
-```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
-```
-
-</div>
-
-////
-
-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:
-
-<div class="termy">
-
-```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
-```
-
-</div>
-
-/// tip
-
-You can read more about it at [The Twelve-Factor App: Config](https://12factor.net/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.
-
-## `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:
-
-<div class="termy">
-
-```console
-$ python
-```
-
-</div>
-
-//// tab | Linux, macOS
-
-The system will **find** the `python` program in `/opt/custompython/bin` and run it.
-
-It would be roughly equivalent to typing:
-
-<div class="termy">
-
-```console
-$ /opt/custompython/bin/python
-```
-
-</div>
-
-////
-
-//// 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:
-
-<div class="termy">
-
-```console
-$ C:\opt\custompython\bin\python
-```
-
-</div>
-
-////
-
-This information will be useful when learning about [Virtual Environments](virtual-environments.md).
-
-## 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](https://en.wikipedia.org/wiki/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).
+Read the [Environment Variables guide](https://tiangolo.com/guides/environment-variables/) for a detailed, cross-platform explanation, including how to create and read environment variables and how the `PATH` environment variable works.
index 78009abef4de70c37448fa1e736f0788f2e9f5d7..3114f5bc2f6d0238fb3ed63efb1d6c0dac51a0ea 100644 (file)
@@ -82,18 +82,19 @@ As **SQLModel** is based on **Pydantic** and **SQLAlchemy**, it requires them. T
 
 ## Installation
 
-Make sure you create a [virtual environment](https://sqlmodel.tiangolo.com/virtual-environments/), activate it, and then install SQLModel, for example with:
+First, [install `uv`](https://docs.astral.sh/uv/getting-started/installation/), and then add SQLModel to your project:
 
 <div class="termy">
 
 ```console
-$ pip install sqlmodel
+$ uv add sqlmodel
 ---> 100%
-Successfully installed sqlmodel
 ```
 
 </div>
 
+If you prefer to use `pip`, install `sqlmodel` inside a virtual environment. See the [installation guide](install.md) for the alternative steps.
+
 ## Example
 
 For an introduction to databases, SQL, and everything else, see the [SQLModel documentation](https://sqlmodel.tiangolo.com/databases/).
index 048c3c6437177378f242041321d8aa7984a1f56f..0d1a128eabb91868206042663f895eb3e59b4749 100644 (file)
@@ -1,19 +1,48 @@
 # Install **SQLModel**
 
-Create a project directory, create a [virtual environment](virtual-environments.md), activate it, and then install **SQLModel**, for example with:
+The first step is to set up your project and add **SQLModel**.
+
+Install [`uv`](https://docs.astral.sh/uv/getting-started/installation/), then create a project and add SQLModel:
 
 <div class="termy">
 
 ```console
-$ pip install sqlmodel
+$ uv init awesome-project --bare
+$ cd awesome-project
+$ uv add sqlmodel
 ---> 100%
-Successfully installed sqlmodel pydantic sqlalchemy
 ```
 
 </div>
 
+`uv add` creates the project's virtual environment in `.venv`, adds SQLModel to `pyproject.toml`, and creates `uv.lock` so the same package versions can be installed later.
+
+/// details | What these commands do
+
+* `uv init`: create a new Python project.
+* `awesome-project`: create the project in a new directory with this name.
+* `--bare`: create only the minimal `pyproject.toml` file, without generating a sample `main.py`, `README.md`, or other files. You will create the application files yourself in the next steps of this tutorial.
+
+Then `cd awesome-project` enters the new project directory before adding SQLModel.
+
+`uv` will use a compatible Python version already installed on your system, or download one if needed.
+
+When you run `uv add`, it selects compatible versions of SQLModel and all the packages SQLModel depends on. It records the exact versions in `uv.lock`, making it possible to install the same package versions later on another computer or when deploying the application.
+
+Creating or updating this file is called [**locking** the project dependencies](https://docs.astral.sh/uv/concepts/projects/sync/). `uv` does this automatically when you add a package.
+
+///
+
 As **SQLModel** is built on top of [SQLAlchemy](https://www.sqlalchemy.org/) and [Pydantic](https://pydantic-docs.helpmanual.io/), when you install `sqlmodel` they will also be automatically installed.
 
+/// details | Using `pip` instead
+
+If you prefer to manage a virtual environment and packages manually, create and activate a virtual environment and then install SQLModel with `pip install sqlmodel`.
+
+Read the [Virtual Environments guide](https://tiangolo.com/guides/virtual-environments/) for the detailed steps.
+
+///
+
 ## Install DB Browser for SQLite
 
 Remember that [SQLite is a simple database in a single file](databases.md#a-single-file-database)?
index c55951f4e4d2e849755caa58927ce54c6e3fec3a..5687f2b42fde4eba0f55d517cd1ffa5e30ce0b03 100644 (file)
@@ -51,7 +51,7 @@ That will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Output above omitted 👆
 
@@ -82,7 +82,7 @@ This will, again, output the `id`s of the objects as `None`:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Output above omitted 👆
 
@@ -107,7 +107,7 @@ And now, something unexpected happens, look at the output, it seems as if the `H
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Output above omitted 👆
 
@@ -179,7 +179,7 @@ Let's see how it works:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Output above omitted 👆
 
@@ -254,7 +254,7 @@ Here's how the output would look like:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Output above omitted 👆
 
@@ -304,7 +304,7 @@ And the output shows again the same data:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Output above omitted 👆
 
@@ -347,7 +347,7 @@ And here's all the output generated by running this program, all together:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 INFO Engine BEGIN (implicit)
 INFO Engine PRAGMA main.table_info("hero")
index 4b879ed7e6573f3c306d03d3441d366e6562053a..e9ad77f9f127a0980245aa7df360d175b8b141e6 100644 (file)
@@ -102,13 +102,13 @@ We are doing that here, we import the models in `app.py` and **after** that we c
 Because now this is a larger project with a **Python package** and not a single Python file, we **cannot** call it just passing a single file name as we did before with:
 
 ```console
-$ python app.py
+$ uv run python app.py
 ```
 
 Now we have to tell Python that we want it to execute a *module* that is part of a package:
 
 ```console
-$ python -m project.app
+$ uv run python -m project.app
 ```
 
 The `-m` is to tell Python to call a *module*. And the next thing we pass is a string with `project.app`, that is the same format we would use in an **import**:
@@ -129,7 +129,7 @@ So, the output would be:
 <div class="termy">
 
 ```console
-$ python -m project.app
+$ uv run python -m project.app
 
 Created hero: id=1 secret_name='Dive Wilson' team_id=1 name='Deadpond' age=None
 Hero's team: name='Z-Force' headquarters='Sister Margaret's Bar' id=1
@@ -228,7 +228,7 @@ And running that achieves the same result as before:
 <div class="termy">
 
 ```console
-$ python -m project.app
+$ uv run python -m project.app
 
 Created hero: id=1 age=None name='Deadpond' secret_name='Dive Wilson' team_id=1
 Hero's team: id=1 name='Z-Force' headquarters='Sister Margaret's Bar'
index 230921054f9a49851460d4e0837c4539111ac6e4..ffcfd0a7846e588885d28722fd419871284cc5f4 100644 (file)
@@ -82,7 +82,7 @@ If we run that code we have up to now, it will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Previous output omitted 😉
 
@@ -168,7 +168,7 @@ If we execute that in the command line, it will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Previous output omitted 😉
 
index 14fc3c92550f48b50add6a0837a8f9beb372c4ff..d1703f32bf80c404c8a31b1493b17ebb01e14605 100644 (file)
@@ -129,7 +129,7 @@ If we run the code we have up to now, it will go and create the database file `d
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Automatically start a new transaction
 INFO Engine BEGIN (implicit)
index 7db237148ca87cff5ff552aff0e16d8fc08a2f44..7432b4702eca2924c09d42059777bbf8a665eea1 100644 (file)
@@ -154,7 +154,7 @@ Now we can run the program and see how it shows us each hero with their correspo
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Previous output omitted 😉
 
@@ -262,7 +262,7 @@ And if we run it in the command line, it will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Previous output omitted 😉
 
@@ -385,7 +385,7 @@ And if we run it, it will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Previous output omitted 😉
 
@@ -436,7 +436,7 @@ If we run that, it would output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Select only the hero data
 INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id
@@ -463,7 +463,7 @@ And if we run that, it will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Select the hero and the team data
 INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id, team.id AS id_1, team.name AS name_1, team.headquarters
index d0a0267b1f738a155173c0cafea0f49c57f9196a..d133b19cb492283420dc45c2fd2c2b3616c37188 100644 (file)
@@ -56,7 +56,7 @@ Running that in the command line will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Previous output omitted 😉
 
index 147c4e599de572d493103fb5e64a2d18067186df..cdce7720feab6d2e5bfa74c2d40534ed9b601a5d 100644 (file)
@@ -56,7 +56,7 @@ Running that in the command line will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Previous output omitted 😉
 
index 8b3bf93a1237f02bc06c3d9de4027c964eb4443b..508110bea5800265cc4ce3f3080d07fb942d42d6 100644 (file)
@@ -40,7 +40,7 @@ Click the button <kbd>New Database</kbd>.
 
 <img class="shadow" src="/img/create-db-and-table-with-db-browser/image001.png">
 
-A dialog should show up. Go to the [project directory you created](../virtual-environments.md#create-a-project) and save the file with a name of `database.db`.
+A dialog should show up. Go to your project directory and save the file with a name of `database.db`.
 
 /// tip
 
index a7cd9e3f6ccf65e6bdfa8b7106fc6b4630665e8c..40a9c4e1be7af7dd71599f5a1543cefa45c35857 100644 (file)
@@ -2,7 +2,7 @@
 
 Now let's get to the code. 👩‍💻
 
-Make sure you are inside of your project directory and with your virtual environment activated as explained in [Virtual Environments](../virtual-environments.md#create-a-project).
+Make sure you are inside of your project directory.
 
 We will:
 
@@ -327,7 +327,7 @@ Put the code in a file `app.py` if you haven't already.
 
 /// tip
 
-Remember to [activate the virtual environment](../virtual-environments.md#create-a-virtual-environment) before running it.
+Run it inside the project environment with `uv run`.
 
 ///
 
@@ -337,7 +337,7 @@ Now run the program with Python:
 
 ```console
 // We set echo=True, so this will show the SQL code
-$ python app.py
+$ uv run python app.py
 
 // First, some boilerplate SQL that we are not that interested in
 
@@ -467,7 +467,7 @@ The main purpose of the `__name__ == "__main__"` is to have some code that is ex
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Something happens here ✨
 ```
@@ -497,7 +497,7 @@ If you run it with:
 <div class="termy">
 
 ```console
-$ python myapp.py
+$ uv run python myapp.py
 
 // This will call create_db_and_tables()
 ```
index f6807fddab992005ecc30c70735383323689ea68..87f70e771279fce13a0f04de3c93258b84fafade 100644 (file)
@@ -67,7 +67,7 @@ That will print the same existing hero **Spider-Youngster**:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate and previous output omitted 😉
 
@@ -105,7 +105,7 @@ This commit after deleting the hero will generate this output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
@@ -138,7 +138,7 @@ This will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
@@ -167,7 +167,7 @@ This will execute some SQL in the database and output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
@@ -198,7 +198,7 @@ This will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
index fae34a346dd655d6a7750e18f56229f63df7b323..569f34643d4054155f46e4f599ecab92c71d1fd9 100644 (file)
@@ -8,12 +8,12 @@ The first step is to install FastAPI.
 
 FastAPI is the framework to create the **web API**.
 
-Make sure you create a [virtual environment](../../virtual-environments.md), activate it, and then install them, for example with:
+Add them to your project:
 
 <div class="termy">
 
 ```console
-$ pip install fastapi "uvicorn[standard]"
+$ uv add fastapi "uvicorn[standard]"
 
 ---> 100%
 ```
@@ -145,7 +145,7 @@ Then run it with the `fastapi` <abbr title="Command Line Interface">CLI</abbr>,
 <div class="termy">
 
 ```console
-$ fastapi dev main.py
+$ uv run fastapi dev main.py
 
 <span style="color: green;">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
 ```
@@ -169,7 +169,7 @@ For production, use `fastapi run` instead of `fastapi dev`:
 <div class="termy">
 
 ```console
-$ fastapi run main.py
+$ uv run fastapi run main.py
 
 <span style="color: green;">INFO</span>:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
 ```
index c7b2d7f3445b55a1a9bcec7f03c0d3284764b5bb..b43089c3685b09a99ab28bacfe2ef4d803cf8de1 100644 (file)
@@ -36,12 +36,12 @@ If you haven't done testing in FastAPI applications, first check the [FastAPI do
 
 Then, we can continue here, the first step is to install the dependencies, `requests` and `pytest`.
 
-Make sure you create a [virtual environment](../../virtual-environments.md), activate it, and then install them, for example with:
+Add them to your project:
 
 <div class="termy">
 
 ```console
-$ pip install requests pytest
+$ uv add requests pytest
 
 ---> 100%
 ```
@@ -353,7 +353,7 @@ Now we can run the tests with `pytest` and see the results:
 <div class="termy">
 
 ```console
-$ pytest
+$ uv run pytest
 
 ============= test session starts ==============
 platform linux -- Python 3.10.0, pytest-7.4.4, pluggy-1.5.0
index 8579384697e565678bc8f30c53f7b02c69386800..45a74a40c55152cb041f81f6f404f22c6cdc5dc2 100644 (file)
@@ -294,7 +294,7 @@ If you run the program now, you will see an output like this:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
index 82a22290286115bfdf67f115bc1b0af4cb578fb9..93028518f56fc0110f769d3c7e8f8136ba9c0daf 100644 (file)
@@ -251,7 +251,7 @@ Because we created the **engine** with `echo=True`, it will print out all the SQ
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 // Some boilerplate, checking that the hero table already exists
 INFO Engine BEGIN (implicit)
 INFO Engine PRAGMA main.table_info("hero")
index 90bb167f2671fb01c5bcccbf2878a07c2e5fcb08..97c9d1decfe4a5a4c8daa9eb0b08509a8ecb00a6 100644 (file)
@@ -43,7 +43,7 @@ If we run it on the command line, it will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Previous output omitted 🙈
 
@@ -147,7 +147,7 @@ And if we run it in the command line, it will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Previous output omitted 🙈
 
@@ -196,7 +196,7 @@ But we are starting to include after an offset of 1 (so we don't count the first
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Previous output omitted 🙈
 
index 3c8c0cfa6a6c271b3aabb7617bc92cef51dfd6cf..e434895bf6349b68543c7cf0b61f6e98c7be8cf4 100644 (file)
@@ -43,7 +43,7 @@ If we run the program from the command line, it would output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Previous output omitted 🙈
 
index af6563e1ab0b184ebd5660cc9eb506d2afebdc26..9822474205edf1f8a0448f95f6faea61247680f9 100644 (file)
@@ -71,7 +71,7 @@ If you run the code in the command line, it would output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Boilerplate omitted 😉
 
index 8e7d9de087e3d5c19faec13ec644fb4ce3d8392b..f6fb8f544f840cdea601b79eb10b68820941bd21 100644 (file)
@@ -80,7 +80,7 @@ Now, if we run the program, it will show almost the same output as before, becau
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Previous output omitted 🙈
 
@@ -176,7 +176,7 @@ If we run that program, we will see the output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Previous output omitted 🙈
 
@@ -257,7 +257,7 @@ And if we run the program now, it will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Previous output omitted 🙈
 
index ebc9ba3a85b1367733d6e640110eb9ec1f5897e1..116ba223a589248e4d8ae804088e100505c38f5b 100644 (file)
@@ -53,7 +53,7 @@ You can confirm it's all working by running the program in the command line:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Previous output omitted 🙈
 
@@ -130,7 +130,7 @@ To confirm that this last part worked, you can run the program again, it will ou
 <div style="font-size: 1rem;" class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Previous output omitted 🙈
 
index 63e6a9e448efd9c3ca66992ce9d8ac93cce65507..733d2a5e24b1ea7aaccfd1fe5357cf3bd07b157b 100644 (file)
@@ -47,7 +47,7 @@ If we run it in the command line it would output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
@@ -78,7 +78,7 @@ When we run it in the command line it will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
@@ -111,7 +111,7 @@ If we run it once, it will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
@@ -134,7 +134,7 @@ So, running it again, without first deleting the file `database.db` will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
@@ -175,7 +175,7 @@ This is what we would get if we run it in the command line:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
@@ -226,7 +226,7 @@ If you run it, it will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
@@ -253,7 +253,7 @@ Running that will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
index 1e31828c7b0acbee85ac65ccc79353bd58c15905..e3ff59bac127a8f7ac5f170a6acfe178e9e0604f 100644 (file)
@@ -236,7 +236,7 @@ We can confirm everything is working by running the program.
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate and previous output omitted 😉
 
@@ -378,7 +378,7 @@ Let's confirm it all works by running the program now:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate and previous output omitted 😉
 
@@ -461,7 +461,7 @@ Now, if we run the program, we will see that SQLModel (SQLAlchemy) is no longer
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate and previous output omitted 😉
 
@@ -539,7 +539,7 @@ Now, if we run the program and try to delete a team with heroes, we will see an
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate and previous output omitted 😉
 
@@ -602,7 +602,7 @@ Now, if we run the program and delete the heroes first, we will be able to delet
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate and previous output omitted 😉
 
index 528c0c983ad7ba7e3105abeb1dec87004ee424f9..aa783f45d24255d0f5c9a4a1fe543a8c8a5cefe8 100644 (file)
@@ -43,7 +43,7 @@ That would print a list with all the heroes in the Preventers team:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Automatically fetch the heroes
 INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age, hero.team_id AS hero_team_id
index 55af9c94dd19f55ba61c87f45911d5d60c36cd6e..af7a8ec13a8737b78b8241df08a9ffbc9f828e26 100644 (file)
@@ -98,7 +98,7 @@ Up to that point, running that in the command line will output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate and previous output omitted 😉
 
@@ -153,7 +153,7 @@ This commit will generate this output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
@@ -182,7 +182,7 @@ This refresh will trigger the same SQL query that would be automatically trigger
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
@@ -210,7 +210,7 @@ So, printing it will show the new `age`:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
index 674404bff9057c68779126ddd52e588ca89c1ea8..1e33244b3d4cb1b6d7015fde2f2480021b50470e 100644 (file)
@@ -444,7 +444,7 @@ And in this case the results will be just one:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
@@ -624,7 +624,7 @@ We can then run it to see the output from the program:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
@@ -676,7 +676,7 @@ When we run it, this generates the output:
 <div class="termy">
 
 ```console
-$ python app.py
+$ uv run python app.py
 
 // Some boilerplate output omitted 😉
 
index 0218120fbf40c71c513dbfa0306e21bfd90e35de..b12bf74387b02e555305d7369385237c71c0555e 100644 (file)
 # 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.
+When you work with Python projects, you should use a **virtual environment** to isolate the packages installed for each project.
 
-/// note
+For SQLModel projects, I recommend using [uv](https://docs.astral.sh/uv/) to manage the project, its dependencies, and its virtual environment.
 
-If you already know about virtual environments, how to create them and use them, you might want to skip this section. 🤓
+## Create a Project { #create-a-project }
 
-///
-
-/// 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.
-
-///
-
-/// note
-
-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](https://github.com/astral-sh/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.
+Install `uv` using the [official installation guide](https://docs.astral.sh/uv/getting-started/installation/), and then create a project:
 
 <div class="termy">
 
 ```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
+$ uv init awesome-project --bare
 $ cd awesome-project
+$ uv add sqlmodel
 ```
 
 </div>
 
-## Create a Virtual Environment
-
-When you start working on a Python project **for the first time**, create a virtual environment **<abbr title="there are other options, this is a simple guideline">inside your project</abbr>**.
-
-/// 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.
-
-<div class="termy">
-
-```console
-$ python -m venv .venv
-```
-
-</div>
-
-/// 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`](https://github.com/astral-sh/uv) installed, you can use it to create a virtual environment.
-
-<div class="termy">
-
-```console
-$ uv venv
-```
-
-</div>
-
-/// 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
-
-<div class="termy">
-
-```console
-$ source .venv/bin/activate
-```
-
-</div>
-
-////
-
-//// tab | Windows PowerShell
-
-<div class="termy">
-
-```console
-$ .venv\Scripts\Activate.ps1
-```
-
-</div>
-
-////
-
-//// tab | Windows Bash
-
-Or if you use Bash for Windows (e.g. [Git Bash](https://gitforwindows.org/)):
-
-<div class="termy">
-
-```console
-$ source .venv/Scripts/activate
-```
-
-</div>
-
-////
-
-/// tip
-
-Every time you install a **new package** in that environment, **activate** the environment again.
-
-This makes sure that if you use a **terminal (<abbr title="command line interface">CLI</abbr>) 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
-
-<div class="termy">
-
-```console
-$ which python
-
-/home/user/code/awesome-project/.venv/bin/python
-```
-
-</div>
-
-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
-
-<div class="termy">
-
-```console
-$ Get-Command python
-
-C:\Users\user\code\awesome-project\.venv\Scripts\python
-```
-
-</div>
-
-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`](https://github.com/astral-sh/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:
-
-<div class="termy">
-
-```console
-$ python -m pip install --upgrade pip
-
----> 100%
-```
-
-</div>
-
-## 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`](https://github.com/astral-sh/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.
-
-///
-
-<div class="termy">
-
-```console
-$ echo "*" > .venv/.gitignore
-```
-
-</div>
-
-/// 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`
-
-<div class="termy">
-
-```console
-$ pip install sqlmodel
-
----> 100%
-```
-
-</div>
-
-////
-
-//// tab | `uv`
-
-If you have [`uv`](https://github.com/astral-sh/uv):
-
-<div class="termy">
-
-```console
-$ uv pip install sqlmodel
----> 100%
-```
-
-</div>
-
-////
-
-### Install from `requirements.txt`
-
-If you have a `requirements.txt`, you can now use it to install its packages.
-
-//// tab | `pip`
-
-<div class="termy">
-
-```console
-$ pip install -r requirements.txt
----> 100%
-```
-
-</div>
-
-////
-
-//// tab | `uv`
-
-If you have [`uv`](https://github.com/astral-sh/uv):
-
-<div class="termy">
-
-```console
-$ uv pip install -r requirements.txt
----> 100%
-```
-
-</div>
-
-////
-
-/// details | `requirements.txt`
-
-A `requirements.txt` with some packages could look like:
-
-```requirements.txt
-sqlmodel==0.13.0
-rich==13.7.1
-```
-
-///
-
-## 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.
-
-<div class="termy">
-
-```console
-$ python main.py
-
-Hello World
-```
-
-</div>
-
-## 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](https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment)
-* [PyCharm](https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html)
-
-/// 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.
-
-<div class="termy">
-
-```console
-$ deactivate
-```
-
-</div>
-
-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 SQLModel you need to install [Python](https://www.python.org/).
-
-After that, you would need to **install** SQLModel 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:
-
-<div class="termy">
-
-```console
-$ pip install "harry==1"
-```
-
-</div>
-
-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`).
-
-<div class="termy">
-
-```console
-$ pip install "harry==3"
-```
-
-</div>
-
-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[<strike>harry v1</strike>]
-        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:
-
-<div class="termy">
-
-```console
-// Don't run this now, it's just an example 🤓
-$ pip install sqlmodel
----> 100%
-```
-
-</div>
-
-That will download a compressed file with the SQLModel code, normally from [PyPI](https://pypi.org/project/sqlmodel/).
-
-It will also **download** files for other packages that SQLModel 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 its 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
-
-<div class="termy">
-
-```console
-$ source .venv/bin/activate
-```
-
-</div>
-
-////
-
-//// tab | Windows PowerShell
-
-<div class="termy">
-
-```console
-$ .venv\Scripts\Activate.ps1
-```
-
-</div>
-
-////
-
-//// tab | Windows Bash
-
-Or if you use Bash for Windows (e.g. [Git Bash](https://gitforwindows.org/)):
-
-<div class="termy">
-
-```console
-$ source .venv/Scripts/activate
-```
-
-</div>
-
-////
-
-That command will create or modify some [environment variables](environment-variables.md) 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) 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 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
-
-<div class="termy">
-
-```console
-$ which python
-
-/home/user/code/awesome-project/.venv/bin/python
-```
-
-</div>
-
-////
-
-//// tab | Windows PowerShell
-
-<div class="termy">
-
-```console
-$ Get-Command python
-
-C:\Users\user\code\awesome-project\.venv\Scripts\python
-```
-
-</div>
-
-////
-
-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:
-
-<div class="termy">
-
-```console
-$ cd ~/code/prisoner-of-azkaban
-```
-
-</div>
-
-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`.
-
-<div class="termy">
-
-```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 <module>
-        import sirius
-```
-
-</div>
+`uv` creates a virtual environment for the project automatically. You don't need to create or activate one yourself.
 
-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`.
+Run commands inside the project environment with `uv run`, for example:
 
 <div class="termy">
 
 ```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 🐺
+$ uv run python app.py
 ```
 
 </div>
 
-## 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](https://github.com/astral-sh/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. 🤓
+## Learn More { #learn-more }
 
-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**. 😎
+Read the [Virtual Environments guide](https://tiangolo.com/guides/virtual-environments/) to learn how virtual environments work underneath, including activation and the alternative `python -m venv` and `pip` workflow.
index 3ad1b05c032c3d02ba07f13c8054c2865463ceb1..56dd943e8eec8f448401740f7db59460193ecc56 100644 (file)
@@ -63,8 +63,6 @@ nav:
     - learn/index.md
     - databases.md
     - db-to-code.md
-    - environment-variables.md
-    - virtual-environments.md
     - install.md
     - "":
       - tutorial/index.md