venv, pipx atau uv: Mana satu untuk pelayan Python?
Pelayan Ubuntu baharu menyekat pip install dengan ralat externally-managed-environment. Ketahui cara memilih venv, pipx atau uv serta konfigurasi systemd yang betul.
Mengapa pip install gagal pada pelayan Ubuntu baharu
Memilih antara Python venv, pipx dan uv pada pelayan bergantung kepada satu soalan: apakah yang anda pasang? Dependensi aplikasi perlu berada dalam persekitaran maya di dalam direktori aplikasi itu sendiri. Alat baris perintah yang anda ingin taip mengikut nama perlu diletakkan dalam pipx. uv melakukan kedua-dua tugas tersebut dan menambah fail kunci (lockfile), yang mula menjadi penting sebaik sahaja mesin kedua perlu membina persekitaran yang sama. Apa yang tidak dilakukan oleh mana-mana alat ini adalah memasang ke dalam Python sistem, kerana pelayan Ubuntu semasa menolak tindakan tersebut secara terus.
Jalankan sudo pip install requests pada Ubuntu 24.04 dan pip akan berhenti sebelum ia memuat turun satu fail pun.
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.
If you wish to install a non-Debian-packaged Python package,
create a virtual environment using python3 -m venv path/to/venv.
Then use path/to/venv/bin/python and path/to/venv/bin/pip.
If you wish to install a non-Debian packaged Python application,
it may be easiest to use pipx install xyz, which will manage a
virtual environment for you.
note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this behaviour by passing --break-system-packages.Ini adalah PEP 668 (cadangan penambahbaikan Python 668, "persekitaran yang diurus secara luaran") yang menjalankan tugasnya. Debian dan Ubuntu meletakkan fail penanda di sebelah interpreter pada /usr/lib/python3.12/EXTERNALLY-MANAGED, dan pip enggan menulis ke dalam mana-mana interpreter yang membawa fail tersebut.
Peraturan ini wujud disebabkan oleh susunan sys.path. apt memasang pustaka ke dalam /usr/lib/python3/dist-packages. pip, yang dijalankan sebagai root terhadap interpreter sistem, menulis ke dalam /usr/local/lib/python3.12/dist-packages, dan pembungkusan Debian meletakkan direktori tersebut lebih awal dalam laluan carian. Cetak sendiri dengan python3 -c 'import sys; print(sys.path)' dan baca susunannya. Jadi, salinan yang ditulis oleh pip membayangi salinan yang dipasang oleh apt, bagi setiap program pada mesin yang berjalan di bawah /usr/bin/python3, termasuk alat pengedaran itu sendiri. cloud-init mengimport requests, jinja2 dan PyYAML daripada interpreter tersebut. Naik taraf salah satu daripadanya dengan pip, dapatkan keluaran yang tidak serasi, dan sesuatu yang tidak pernah anda sentuh akan gagal pada but seterusnya dengan traceback yang menamakan pakej yang anda tidak tahu berada dalam rantaian tersebut. apt masih merekodkan versinya sendiri sebagai dipasang, jadi tiada apa yang memberi amaran kepada anda, dan pembaikannya adalah sudo apt reinstall python3-requests.
Peraturan yang menyusul adalah ringkas. Python sistem adalah milik pengedaran. Jangan pasang ke dalamnya, jangan naik taraf pustakanya dengan pip, dan jangan padam fail EXTERNALLY-MANAGED untuk menghilangkan mesej tersebut. Satu-satunya tugas untuk /usr/bin/python3 adalah membina persekitaran maya.
venv lwn pipx lwn uv: peraturan pemilihan
Pilih berdasarkan perkara yang anda pasang, bukan berdasarkan alat yang paling baru anda baca.
- Aplikasi yang anda gunakan dan jalankan sebagai servis, seperti projek Django atau Flask: satu virtual environment (venv) di dalam direktori aplikasi tersebut.
- Alat baris perintah (command-line tool) yang anda mahukan pada
PATHanda, sepertiansibleatauhttpie: pipx, yang memberikan setiap alat persekitaran peribadi dan satu pautan padaPATH. - Projek yang memerlukan lockfile, pemasangan lebih pantas, atau versi Python yang tidak dibekalkan oleh distribusi: uv, yang menghasilkan venv biasa berserta fail
uv.lock. - Pustaka yang diperlukan oleh alat distribusi dan bukannya kod anda:
sudo apt install python3-<name>, satu-satunya cara yang disokong untuk menambah apa-apa pada interpreter sistem.
pipx dan uv tool install melakukan tugas yang sama, jadi pelayan yang sudah mempunyai uv tidak memerlukan pipx. Rangka kerja web yang anda pilih tidak mengubah apa-apa di sini: Django dan Flask pada VPS berbeza dari segi apa yang terkandung dalam requirements.txt, bukan cara persekitaran di sekelilingnya dibina. Semua arahan di bawah menggunakan Ubuntu 24.04 dan Python 3.12 miliknya, jadi sesuaikan versi di dalam path jika versi anda berbeza.
Bina venv bagi setiap aplikasi
Ubuntu mengasingkan modul venv daripada pakej asas Python, jadi pada imej minimum, percubaan pertama akan gagal dengan mesej yang menyatakan dengan tepat perkara yang hilang.
The virtual environment was not created successfully because ensurepip is not
available. On Debian/Ubuntu systems, you need to install the python3-venv
package using the following command.
apt install python3.12-venvPasang modul tersebut, kemudian cipta persekitaran sebagai pengguna yang akan memiliki kod tersebut.
sudo apt update
sudo apt install -y python3-venv
sudo install -d -o deploy -g deploy -m 755 /srv/myapp
sudo -u deploy python3 -m venv /srv/myapp/.venv
sudo -u deploy /srv/myapp/.venv/bin/pip install -r /srv/myapp/requirements.txtPerhatikan perkara yang tiada: tiada source, tiada activate. /srv/myapp/.venv/bin/pip dipasang ke dalam persekitaran tersebut kerana lokasi binari itu sendiri, bukan disebabkan oleh apa-apa yang anda eksport ke dalam shell. Sahkan perkara ini sebelum anda meneruskan.
/srv/myapp/.venv/bin/python -c 'import sys; print(sys.prefix)'Perintah itu akan memaparkan /srv/myapp/.venv. Jika ia memaparkan /usr, anda sedang menjalankan interpreter sistem dan pakej anda telah pergi ke lokasi yang tidak sepatutnya.
Dua sifat venv menentukan perkara yang boleh anda lakukan dengannya selepas itu. Venv tidak boleh dialihkan (relocatable), kerana setiap skrip dalam bin/ membawa baris shebang mutlak: head -1 /srv/myapp/.venv/bin/pip membaca #!/srv/myapp/.venv/bin/python. Namakan semula direktori induk dan skrip tersebut akan gagal dengan bad interpreter: No such file or directory. Venv juga mengunci interpreter yang menciptanya, yang direkodkan sebagai baris home dalam /srv/myapp/.venv/pyvenv.cfg, dan bin/python3 merupakan symlink kepada binari tersebut. Naik taraf keluaran sehingga python3.12 tiada lagi, symlink tersebut tidak mempunyai sasaran, dan servis akan mati semasa permulaan dengan No such file or directory. Kedua-dua kes mempunyai penyelesaian yang sama: padam venv tersebut dan bina yang baharu daripada requirements.txt. Proses membina semula hanya mengambil masa beberapa saat. Jangan sesekali menyalin venv antara mesin.
Lokasi venv dan pemilikan
Letakkan ia bersebelahan dengan kod di /srv/myapp/.venv, dan kekalkan satu venv bagi setiap aplikasi. Dengan cara ini, deployment menjadi satu direktori tunggal, unit systemd mendapat laluan yang tidak pernah berubah, dan dua aplikasi tidak akan saling merosakkan antara satu sama lain akibat naik taraf dependency yang dikongsi. Jangan letakkan venv di mana-mana lokasi yang diterbitkan terus oleh pelayan web anda, kerana ia mengandungi dependency dan sering kali mengandungi konfigurasi anda.
Pemilikan memerlukan perhatian khusus. Biarkan pengguna deploy memiliki kod dan persekitaran tersebut, dan berikan akaun servis akses baca dan laksana sahaja.
sudo adduser --system --group --no-create-home myapp
sudo chown -R deploy:myapp /srv/myapp
sudo chmod -R o-rwx /srv/myappServis kini boleh mengimport dependency-nya tetapi tidak boleh menulis semula fail tersebut. Ini bermakna pepijat pelaksanaan kod dalam aplikasi web tidak boleh menggantikan pustaka pada cakera secara senyap dan bertahan selepas but semula. Penaakulan yang sama untuk bahagian lain mesin diliputi dalam menjalankan servis sebagai pengguna dengan keistimewaan minimum.
pipx untuk alatan baris perintah
pipx memasang aplikasi, bukan pustaka. Setiap alat mendapat persekitarannya sendiri di bawah ~/.local/share/pipx/venvs/<name>, dan fail boleh laksana alat tersebut dipautkan ke dalam ~/.local/bin, supaya dua alat yang memerlukan versi pustaka yang berbeza tidak akan bercanggah.
sudo apt update
sudo apt install -y pipx
pipx ensurepath
pipx install httpiepipx ensurepath menambah ~/.local/bin ke dalam PATH dengan menyunting fail permulaan shell anda. Ia tidak boleh mengubah shell yang sedang anda gunakan, jadi http: command not found sejurus selepas pemasangan biasanya bermakna anda belum log keluar dan log masuk semula. ~/.profile lalai Ubuntu hanya menambah ~/.local/bin apabila direktori tersebut sudah wujud semasa log masuk, itulah sebabnya masalah ini berlaku sekali pada akaun baharu dan tidak berulang lagi.
Jika anda menghalakan pipx kepada pustaka, ia akan menolak dengan mesej yang bermula dengan:
No apps associated with package requests or its dependencies.Itu adalah alat tersebut memberitahu anda bahawa ia adalah instrumen yang salah. Pustaka sepatutnya berada dalam venv aplikasi.
Perincian yang penting pada pelayan ialah lokasi. pipx install biasa meletakkan segala-galanya di bawah direktori home satu pengguna. Unit systemd yang berjalan sebagai myapp tidak dapat melihatnya, cron job root tidak dapat melihatnya, dan sudo juga tidak akan menemuinya, kerana secure_path dalam /etc/sudoers menggantikan PATH dengan senarai tetap. Untuk alat yang perlu digunakan oleh seluruh mesin, pasanglah secara global.
sudo pipx install --global ansible
sudo pipx ensurepath --globalFlag --global meletakkan persekitaran dalam /opt/pipx dan memautkan fail boleh laksana ke dalam /usr/local/bin, yang berada dalam PATH lalai dan di dalam secure_path. Semak versi anda dahulu dengan pipx --version, kerana Ubuntu 24.04 membungkus pipx 1.4.3, yang lebih lama daripada --global, dan pipx yang lebih lama akan menjawab dengan unrecognized arguments: --global. Pada versi tersebut, tetapkan dua direktori yang didokumenkan itu sendiri:
sudo env PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx install ansible
command -v ansiblecommand -v ansible sepatutnya mencetak /usr/local/bin/ansible. Jika ia mencetak laluan di bawah /home, alat tersebut telah masuk ke dalam akaun pengguna tunggal dan tiada servis akan menemuinya.
uv apabila anda memerlukan lockfile
uv ialah binari tunggal daripada Astral yang merangkumi fungsi pip, venv dan pip-tools, malah ia boleh memuat turun penterjemah (interpreter) sendiri. Kelajuannya cukup ketara walaupun pada VPS yang kecil, dan ia menghasilkan lockfile yang sebenar.
Pemasang rasmi meletakkan uv dan uvx di dalam ~/.local/bin:
curl -LsSf https://astral.sh/uv/install.sh | sh
uv --versionMenyalurkan skrip terus ke dalam shell pada pelayan memerlukan sedikit perhatian. Tetapkan versi dalam URL dan baca fail tersebut sebelum anda menjalankannya:
curl -LsSf https://astral.sh/uv/0.12.3/install.sh -o uv-install.sh
less uv-install.sh
sh uv-install.shpipx install uv juga boleh digunakan jika pipx sudah tersedia. uv ialah satu binari lengkap tanpa sebarang dependency Python, jadi menyalinnya ke dalam /usr/local/bin merupakan cara yang sah untuk menyediakannya kepada semua pengguna pada pelayan tersebut.
Bagi projek dengan pyproject.toml, aliran kerja melibatkan empat arahan, dan hanya arahan terakhir yang dijalankan pada pelayan.
uv init myapp
uv add flask gunicorn
uv lock
uv sync --frozen --no-devuv lock menulis uv.lock, iaitu lockfile rentas platform yang menyimpan versi tepat yang telah diselesaikan, dan anda perlu melakukan commit fail ini bersama kod anda. uv sync membina .venv di dalam root projek untuk memadankannya. Pada pelayan, --frozen ialah flag yang penting: dokumentasi mentakrifkannya sebagai penggunaan versi dalam lockfile sebagai sumber kebenaran, bukannya menyemak sama ada lockfile tersebut terkini, iaitu gelagat yang diperlukan untuk deployment. --no-dev mengecualikan kumpulan dependency pembangunan.
Projek requirements.txt sedia ada tidak memerlukan penukaran kerana uv menggunakan bahasa yang sama dengan pip:
uv venv /srv/myapp/.venv
uv pip install --python /srv/myapp/.venv/bin/python -r /srv/myapp/requirements.txtHasilnya ialah virtual environment biasa. .venv/bin/python berfungsi tepat seperti yang dilakukan oleh python3 -m venv, jadi tiada apa-apa dalam panduan ini yang akan berubah.
Satu tetapan lalai uv perlu diketahui sebelum anda menggunakannya pada pelayan. Tetapan python-preference secara lalainya ialah managed, yang didokumentasikan sebagai memilih "penterjemah yang dimuat turun dan dipasang oleh uv" berbanding penterjemah yang sudah sedia ada pada sistem. Jadi, uv venv --python 3.13 pada pelayan yang hanya mempunyai versi 3.12 akan mengambil versi 3.13 ke dalam ~/.local/share/uv/python secara senyap dan bukannya gagal. Ini memudahkan kerja pada komputer riba tetapi mungkin mengejutkan pada pelayan, kerana servis anda kini bergantung pada penterjemah yang berada dalam direktori home dan tidak akan dikemaskini oleh apt upgrade. Tetapkan python-preference kepada only-system dalam uv.toml jika anda mahukan penterjemah daripada pengedaran (distribution) sistem. Jika anda mahukan environment di lokasi selain root projek, UV_PROJECT_ENVIRONMENT menentukan direktori yang akan digunakan untuk virtual environment projek tersebut.
Halakan systemd kepada interpreter venv, bukan kepada activate
Di sinilah kebanyakan penggunaan Python gagal, dan puncanya adalah salah faham tentang fungsi activate.
bin/activate ialah skrip shell. Ia meletakkan direktori bin milik venv di hadapan PATH, menetapkan VIRTUAL_ENV, menyimpan nilai lama supaya deactivate boleh memulihkannya, dan menukar prompt anda. Ia tidak mengandungi apa-apa yang dibaca oleh interpreter itu sendiri. Pengaktifan hanyalah kemudahan untuk manusia yang menaip python pada prompt.
Perkara yang sebenarnya memilih persekitaran ialah fail interpreter yang anda jalankan. Apabila /srv/myapp/.venv/bin/python bermula, modul site Python mencari fail pyvenv.cfg dalam direktori yang menyimpan executable tersebut dan satu tahap di atasnya. Penemuan /srv/myapp/.venv/pyvenv.cfg menetapkan sys.prefix kepada venv, yang meletakkan site-packages venv tersebut pada sys.path. Itulah keseluruhan mekanismenya. Ia tidak memerlukan pemboleh ubah persekitaran dan tidak memerlukan shell.
Jadi unit ini tidak akan bermula:
[Service]
ExecStart=source /srv/myapp/.venv/bin/activate && gunicorn app:appmyapp.service: Failed to locate executable source: No such file or directory
myapp.service: Failed at step EXEC spawning source: No such file or directory
myapp.service: Main process exited, code=exited, status=203/EXECExecStart bukan baris arahan shell. systemd melaksanakan program secara terus, jadi tiada fungsi terbina dalam source, && diserahkan sebagai argumen literal, dan tiada apa-apa yang dikembangkan.
Dan unit ini bermula, kemudian mati:
[Service]
ExecStart=/usr/bin/python3 /srv/myapp/app.pyModuleNotFoundError: No module named 'flask'/usr/bin/python3 ialah interpreter sistem, dan sys.path miliknya tidak pernah mengandungi venv anda. Arahan yang sama berfungsi dalam sesi SSH anda hanya kerana anda telah mengaktifkan venv di sana, jadi shell menyelesaikan python3 melalui PATH kepada .venv/bin/python3 sebaliknya.
Membungkus arahan dalam /bin/bash -c 'source ... && gunicorn ...' memang berfungsi. Ia juga meletakkan shell antara systemd dan proses anda tanpa sebarang faedah, sedangkan satu laluan mutlak (absolute path) sudah memadai:
[Unit]
Description=myapp web service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/srv/myapp
Environment=PYTHONUNBUFFERED=1
Environment=PATH=/srv/myapp/.venv/bin:/usr/local/bin:/usr/bin:/bin
ExecStart=/srv/myapp/.venv/bin/gunicorn --workers 3 --bind 127.0.0.1:8000 app:app
Restart=on-failure
RestartSec=5
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=full
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now myapp
systemctl status myapp
journalctl -u myapp -n 50 --no-pagersystemctl status myapp sepatutnya melaporkan active (running) dengan Main PID yang merupakan proses gunicorn anda. Jika sebaliknya, baca jurnal.
Baris Environment=PATH= tidak wujud untuk ExecStart, yang sudah membawa laluan penuh. Ia wujud untuk proses yang dimulakan oleh aplikasi anda. Sesuatu servis mewarisi PATH lalai yang pendek daripada systemd, jadi kod Python yang memanggil subprocess.run(["ffmpeg", ...]), atau arahan pengurusan yang menggunakan skrip konsol daripada venv, tidak akan menemui apa yang diperlukan. Meletakkan direktori bin venv di hadapan adalah satu-satunya bahagian activate yang benar-benar digunakan oleh servis. Semak apa yang unit tersebut benar-benar terima dengan systemctl show -p Environment myapp.
Peraturan yang sama meliputi kerja berjadual. cron menjalankan tugas dengan PATH bernilai /usr/bin:/bin, jadi baris crontab yang membaca python3 /srv/myapp/cleanup.py akan menjalankan interpreter sistem dan gagal dengan ModuleNotFoundError pada pukul tiga pagi, dan ralat tersebut pergi ke spool mel tempatan yang tidak dibaca oleh sesiapa. Tulis laluan mutlak venv di sana juga. Untuk mendapatkan output tersebut dalam jurnal dan rekod larian terakhir, pasangan servis dan pemasa systemd menggunakan baris ExecStart yang sama.
Adakah Docker menggantikan keputusan ini?
Bekas (container) mempunyai sistem failnya sendiri, jadi persoalan ini berubah bentuk dan bukannya hilang. Dalam imej rasmi seperti python:3.12-slim, Python dibina ke dalam /usr/local dan tidak membawa penanda EXTERNALLY-MANAGED, jadi pip install sebagai root adalah cara yang dihasratkan untuk menambah pakej dan venv tidak memberikan banyak manfaat. Bina FROM ubuntu:24.04 sebaliknya dan anda akan bertemu externally-managed-environment semula di dalam imej tersebut, atas sebab yang sama seperti pada hos: ia adalah penterjemah (interpreter) pengedaran yang membawa fail penanda pengedaran tersebut.
Banyak imej masih menggunakan venv, kerana ia memudahkan pembinaan berbilang peringkat (multi-stage build). Peringkat pembina memasang ke dalam /opt/venv, dan peringkat masa jalan (runtime) menyalin direktori tersebut serta meninggalkan pengkompil. Masalah pengaktifan turut terbawa bersama. Baris RUN source /opt/venv/bin/activate hanya memberi kesan kepada shell lapisan binaan tersebut, jadi pada masa jalan, bekas bermula pada penterjemah sistem dan menimbulkan ModuleNotFoundError. Tetapkan ENV PATH="/opt/venv/bin:$PATH", atau berikan CMD laluan mutlak /opt/venv/bin/gunicorn. Ia adalah pepijat yang sama seperti pepijat systemd, cuma dalam fail yang berbeza.
Jadi, bekas menggantikan persoalan penterjemah, kerana imej menetapkan penterjemah dan segala-galanya di bawahnya. Ia tidak menggantikan persoalan penetapan versi (pinning). Imej yang dibina daripada requirements.txt yang tidak ditetapkan versinya akan menyelesaikan versi yang berbeza pada bulan hadapan, yang bermaksud tag imej boleh dihasilkan semula manakala binaan yang menghasilkannya tidak. Fail kunci (lockfile) seperti uv.lock, atau fail keperluan yang ditetapkan sepenuhnya, adalah perkara yang menutup jurang tersebut, sama ada menggunakan bekas atau tidak. Dan apabila satu aplikasi berjalan pada satu VPS di bawah systemd, bekas kebanyakannya memindahkan keputusan yang sama ini ke dalam Dockerfile, memandangkan systemd sudah memulakan semula proses yang gagal dan menangkap outputnya dalam jurnal. Menjalankan Docker pada VPS berbaloi apabila anda mahu imej yang dibina itu sendiri menjadi perkara yang anda gunakan untuk atur cara (deploy).
FAQ
Bolehkah saya hanya menggunakan pip install dengan --break-system-packages?
Jangan lakukan ini pada pelayan yang perlu terus beroperasi. Flag tersebut melakukan apa yang dinyatakan: ia membuang pelindung, dan pip menulis ke dalam /usr/local/lib/python3.12/dist-packages, yang berada sebelum direktori apt pada sys.path. Versi anda kemudian akan mengatasi versi pengedaran untuk setiap skrip sistem yang berjalan di bawah /usr/bin/python3, dan apt masih menganggap versinya sendiri telah dipasang, jadi tiada apa yang mengesan konflik tersebut sehingga sesuatu rosak. Di dalam imej kontena yang anda bina semula dari awal setiap kali, kerosakan hanya terhad pada imej tersebut, jadi ia boleh diterima di sana. Pada mesin yang anda selenggara, cipta venv. Itu hanya satu arahan.
Di manakah persekitaran maya (virtual environment) harus diletakkan pada pelayan?
Di dalam direktori aplikasi itu sendiri, sebagai /srv/myapp/.venv, dimiliki oleh pengguna deploy, dengan akaun servis hanya memegang akses baca dan laksana. Kekalkan satu venv bagi setiap aplikasi, kerana venv yang dikongsi bermakna naik taraf untuk aplikasi pertama boleh merosakkan aplikasi kedua. Jangan alihkan atau salin venv selepas menciptanya: setiap skrip dalam direktori bin/ miliknya mempunyai laluan mutlak tersebut yang ditulis ke dalam baris shebangnya, jadi venv yang dialihkan akan gagal dengan bad interpreter: No such file or directory. Padam dan bina semula daripada requirements.txt sebaliknya.
Mengapa servis systemd saya gagal dengan ModuleNotFoundError?
Kerana unit tersebut melaksanakan penterjemah yang bukan milik venv. Jalankan systemctl cat myapp dan baca ExecStart. Ia mesti menamakan /srv/myapp/.venv/bin/python, atau skrip konsol daripada direktori bin/ yang sama, melalui laluan mutlak. Melakukan sourcing activate dalam fail unit tidak akan berfungsi, kerana ExecStart bukan shell, dan systemd melaporkan Failed to locate executable source dengan status=203/EXEC. Tambahkan Environment=PATH=/srv/myapp/.venv/bin:/usr/local/bin:/usr/bin:/bin supaya mana-mana subproses yang dimulakan oleh kod anda turut menemui alatan venv tersebut.
Patutkah saya menggunakan uv sebagai ganti venv dan pip?
Gunakan uv apabila anda mahukan lockfile, apabila masa pemasangan cukup perlahan sehingga mengganggu anda, atau apabila anda memerlukan versi Python yang tidak disediakan oleh pengedaran anda. Ia mencipta venv biasa, jadi unit systemd dan susun atur fail tidak berubah, dan uv sync --frozen memasang apa yang direkodkan oleh lockfile dengan tepat. Jika satu aplikasi dipasang daripada git dengan requirements.txt yang ditetapkan dan pemasangan selesai dalam beberapa saat, python3 -m venv sudah memadai, dan ia adalah satu lagi binari yang kurang perlu dikemas kini pada pelayan.