Quản lý dependency cho Python

Quản lý dependency cho Python

Việc quản lý package hay còn gọi là dependency có vẻ khó khăn với Python, vì công cụ được cài mặc định là pip không có nhiều tính năng như các ngôn ngữ khác. Ví dụ NodeJS hay Rails đều có những công cụ chuyên biệt được cài mặc định để quản lý dependency, giúp cho làm việc nhóm hay chuyển đổi từ dự án này sang dự án khác với các version khác nhau rất dễ dàng.

Rất may là vẫn tồn tại rất nhiều công cụ khác nhau cho phép chúng ta làm điều đó. Trong bài viết này, tôi sẽ trình bày một số công cụ mà cá nhân tôi đang dùng và cảm thấy rất ổn.

Quản lý version Python

Việc cài đặt Python nghe có vẻ rất đơn giản, nhưng thực tế lại nảy sinh rất nhiều vấn đề. Ngay cả khi làm việc một mình, bạn có thể sẽ gặp vấn đề khi mà nhiều thư mực khác nhau sử dụng những version khác nhau. Đó là còn chưa kể đến khi làm việc nhóm mà mỗi người lại dùng một máy khác nhau, phần cứng khác nhau, OS khác nhau.

Để giải quyết tình trạng này, thì một công cụ như pyenv là vô cùng cần thiết. Đây là một công cụ giúp đơn giản hóa quá trình cài đặt và chuyển đổi các version Python khác nhau. Một điểm rất hay là pyenv cài đặt Python ở một thư mục riêng mà không thay đổi cài đặt Python có sẵn trong hệ thống. Điều này sẽ giúp máy tính ít gặp lỗi hơn khi chạy các tác vụ cần đến Python.

Việc sử dụng pyenv rất đơn giản:

$ pyenv install 3.8.6
$ pyenv install 3.9.0
$ pyenv install 3.10.2
$ pyenv versions
* system
  3.8.6
  3.9.0
  3.10.2

Chúng ta có thể thiết lập version Python nào mà chúng ta sử dụng thường xuyên làm global, khi đó lệnh python sẽ dùng đúng version đó:

$ pyenv global 3.8.6
$ pyenv versions
  system
* 3.8.6 (set by /Users/naa/.pyenv/version)
  3.9.0
  3.10.2
$ python --version
Python 3.8.6

Trong trường hợp chúng ta muốn thiết lập riêng cho từng thư mục thì thiết lập đó gọi là local:

$ pyenv local 3.10.2
$ pyenv versions
  system
  3.8.6
  3.9.0
* 3.10.2 (set by /Users/naa/sample/python-environments/.python-version)
$ python --version
Python 3.10.2

Quản lý dependency

Trong phần này, chúng ta sẽ tìm hiểu một số công cụ giúp quản lý việc cài đặt các package.

venv + pip

Hai công cụ venv và pip (package installer for python), được cài sẵn kèm với Python, là những công cụ phổ biến nhất để quản lý môi trường ảo (virtual environment) và các package được cài đặt trong môi trường đó.

Môi trường ảo Python có thể hiểu đơn giản là một môi trường đóng kín, trong đó sẽ có Python và các package được cài đặt riêng nhằm tránh xung đột với các môi trường khác. Để tạo một môi trường ảo, lệnh sau sẽ giúp chúng ta:

$ python -m venv my_venv
$ source my_venv/bin/activate
(my_venv)$

Dòng lệnh phía trên dùng để tạo một môi trường mới, dòng dưới để kích hoạt môi trường đó. Để bỏ kích hoạt, chúng ta dùng lệnh deactivate. Trong một thư mục, chúng ta có thể tạo nhiều môi trường khác nhau và chuyển đổi giữa chúng bằng cách kích hoạt môi trường tương ứng.

Môi trường ảo này sẽ đóng gói mọi thứ, kể cả Python để có thể chạy một cách độc lập với nhau:

(my_venv)$ which python
/Users/naa/sample/my_venv/bin/python

Trong môi trường đó, chúng ta dùng pip (cũng được đóng gói trong môi trường ảo) để cài đặt các package như bình thường:

(my_venv)$ pip install requests

Điểm khác biệt là pip sẽ tải và cài đặt các package vào thư mục của môi trường ảo, thay vì thư mục mặc định của hệ thống (và đương nhiên là không kích hoạt môi trường ảo này sẽ không thể dùng các package đó được).

Giờ đây, để có thể làm việc nhóm dễ dàng hơn, hoặc bạn muốn quản lý các package để có cài đặt lại sau này, cách làm thông thường là chúng ta sẽ tạo một file requirements.txt. Nội dung của file này sẽ là các package cần cài đặt và phiên bản của chúng. Với môi trường đã có sẵn package, lệnh pip freeze sẽ giúp chúng ta liệt kê một cách tự động:

(my_venv)$ pip freeze > requirements.txt
(my_venv)$ cat requirements.txt
idna==3.3
requests==2.27.1
urllib3==1.26.8

Hai công cụ này rất đơn giản và dễ sử dụng, nhưng nếu so về tính năng thì chúng mới chỉ ở mức cơ bản. Một khuyết điểm là chúng chỉ quản lý package chứ hoàn toàn không có thông tin gì về version Python được sử dụng. Ngoài ra, việc quản lý package ở các môi trường phát triển khác nhau (local, stg, prod) rất khó khăn. Tôi thường phải tạo ra mỗi file requirements cho một môi trường riêng, ví dụ như thế này:

requirements-dev.txt:

-r requirements.txt

# dev
coverage==6.3.2
flake8==4.0.1
ipython==8.0.1
isort==5.10.1

requirements.txt:

Django==4.0.2
gunicorn==20.1.0
redis==4.1.4

Nhưng giờ đây, khi biết đến Poetry và Pipenv, thì mọi thứ đơn giản hơn rất nhiều. Hai công cụ này có đầy đủ tính năng của venv và pip, chúng còn thêm nhiều tính năng nâng cao nữa, như phân chia môi trường phát triển, có lock file để quản lý việc cài đặt.

Khi tôi làm việc với npm hay RubyGems thì lock file luôn được tích hợp sẵn, và tôi rất bất ngờ khi Python lại không có những tính năng như thế. Bây giờ thì tôi hiểu ra là tôi chưa dùng đúng công cụ mà thôi.

Poetry

Poetry được đánh giá là công cụ quản lý dependency nhiều tính năng nhất cho Python. Nó còn có thể dùng để khởi tạo một project hoàn toàn mới bằng lệnh sau:

$ poetry new sample-project
$ cd sample-project

Lệnh này sẽ tạo cho chúng ta một project Python mới với cấu trúc rất hoàn chỉnh:

sample-project
├── pyproject.toml
├── README.md
├── poetry_demo
│   └── __init__.py
└── tests
    └── __init__.py

Dependency được quản lý trong file pyproject.toml:

[tool.poetry]
name = "sample-project"
version = "0.1.0"
description = ""
authors = ["naa"]

[tool.poetry.dependencies]
python = "^3.10"

[tool.poetry.dev-dependencies]
pytest = "^5.2"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

Để thêm một dependency (cài thêm package) mới, chúng ta đơn giản dùng lệnh sau:

$ poetry add [--dev] <package name>

Trong đó tùy chọn --dev nghĩa là package chỉ được cài đặt cho môi trường phải triển mà thôi. Ví dụ:

$ poetry add flask

Lệnh này sẽ cài đặt Flask và cài đặt vào môi trường ảo được quản lý bởi Poetry, đồng thời file poetry.lockpyproject.toml sẽ được cập nhật. Nội dung của file lock sẽ là toàn bộ các package được cài và các dependency của chúng, rất giống với cách hoạt động của npm.

[tool.poetry.dependencies]
python = "^3.10"
Flask = "^2.0.3"

Để chạy lệnh từ trong môi trường ảo, chúng ta cần thêm tiền tố poetry run trước các lệnh thông thường:

$ poetry run python -m pytest

Lệnh poetry run <command> sẽ thực thi lệnh trong môi trường ảo, mặc dù chúng ta không cần kích hoạt môi trường này, mọi thứ đã được poetry tự động hóa. Chúng ta vẫn có thể kích hoạt môi trường ảo (nếu muốn) bằng lệnh

$ poetry run shell

Tuy nhiên, sử dụng poetry run <command> là cách làm được đề xuất.

Pipenv

Pipenv là một công cụ với những tính năng quản lý dependency tương tự như Poetry. Chúng ta có thể khởi tạo pipenv cho một project bằng lệnh sau:

$ mkdir sample-project
$ cd sample-project
$ pipenv --python 3.10.2

Pipenv không có tính năng tạo một project hoàn toàn mới như Poetry, mà chỉ tập trung vào việc quản lý dependency mà thôi. Sau khi khởi tạo, chúng ta có thêm file Pipfile (và một file Pipfile.lock đi kèm):

[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]

[requires]
python_version = "3.10"

Để cài thêm package mới, chúng ta dùng lệnh sau:

$ pipenv install [--dev] <package name>

Tương tự như trên, tùy chọn --dev chỉ ra rằng package đó chỉ dùng cho môi trường phát triển mà thôi.

$ pipenv install flask

Cũng tương tự như Poetry, Pipenv cũng quản lý một môi trường ảo, và việc cài đặt package sẽ được thực hiện trong môi trường ảo đó. Sau khi cài đặt thì PipfilePipfile.lock sẽ được tự động cập nhật.

Để chạy lệnh trong môi trường ảo quản lý bởi Pipenv, chúng ta cần dùng tiền tố pipenv run. Ví dụ:

$ pipenv run python -m pytest

Tương tự như Poetry, pipenv run <command> sẽ chạy lệnh bên trong môi trường ảo. Chúng ta cũng có thể kích hoạt môi trường này bằng lệnh pipenv shell.

Pipenv hoạt động tốt khi kết hợp với pyenv. Ví dụ, khi bạn muốn khởi tạo một project mới, dùng version Python không có sẵn, thì Pipenv sẽ có thông báo hỏi rằng liệu bạn có muốn cài đặt Python hay không:

$ pipenv --python 3.7.5
Warning: Python 3.7.5 was not found on your system…
Would you like us to install CPython 3.7.5 with Pyenv? [Y/n]: Y

Nên dùng công cụ nào?

Nên bắt đầu với mặc định

Câu hỏi đặt ra là, với những công cụ như trên, thì công cụ nào là thích hợp. Như kinh nghiệm cá nhân của tôi, thì bắt đầu với venv và pip là một lựa chọn tốt. Đây là những công cụ có sẵn, đơn giản và hiệu quả dù tính năng không nhiều.

Với những project nhỏ và đơn giản, những công cụ này hoàn toàn đáp ứng được yêu cầu. Dần dần, khi project phát triển hơn bạn sẽ nhận ra những ưu và nhược điểm của hai công cụ này. Và khi nào cảm thấy cần một công cụ mạnh hơn, khi đó hãy nghĩ đến Poetry hoặc Pipenv.

Poetry hay Pipenv?

Hai công cụ này có tính năng rất giống nhau (Poetry có thêm tính năng khởi tạo project mới nhưng không dùng thường xuyên lắm, và nó cũng không hẳn là cần thiết). Việc chọn công cụ nào hoàn toàn phụ thuộc vào sở thích cá nhân. Tuy nhiên, chúng có một số điểm khác biệt, mà bạn có thể suy xét, nếu cả hai công cụ đều là mới với bạn:

  • Đưa package lên PyPI dùng Poetry đơn giản hơn. Vì vậy nếu bạn có nhu cầu này thì Poetry là lựa chọn tốt hơn.
  • Việc cài đặt các package khi cài đặt môi trường mới (trên máy mới, trên server) đều rất mất thời gian, không có sự khác biệt nhiều giữa hai công cụ này.
  • Cả hai công cụ đều là mã nguồn mở, và Poetry được phát triển mạnh hơn và có vẻ lắng nghe người dùng hơn.

Một số công cụ khác

Ngoài các công cụ trên, chúng ta còn rất nhiều công cụ khác, để quản lý dependency và cài đặt môi trường.

  • Docker là công cụ để build, deploy và quản lý các ứng dụng dưới dạng container. Nó là một công cụ thay thế tốt cho tất cả các công cụ ở trên (và có thể áp dụng cho mọi ngôn ngữ, framework).
  • Conda cũng là một công cụ quản lý dependency khác cho Python. Tôi không biết nhiều về công cụ này, nhưng nó rất quen thuộc với những người làm data science hay machine learning.
  • Một số công cụ khác có thể xem xét: virtualenvwrapper, pyenv-virtualenv và pip-tools.

Kết luận

Trong bài viết này, tôi đã trình bày một số công cụ trong hiểu biết của mình để quản lý dependency trong Python. Về cơ bản, thì các vấn đề mà những công cụ này giải quyết là:

  • Cài đặt và quản lý version Python
  • Quản lý môi trường ảo và dependency
  • Cài đặt môi trường trên máy khác

Những công cụ này giúp mọi thứ trở nên đơn giản hơn, nâng suất cao hơn và làm việc hiệu quả hơn. Tôi không đánh giá công cụ nào tốt hơn công cụ nào. Nếu có điều kiện thì bạn cứ thử hết tất cả để biết mình hợp với cái nào hơn.

#Python #dependency #management #pip #venv #pipenv #poetry

Tôi xin lỗi nếu bài viết có bất kỳ typo nào. Nếu bạn nhận thấy điều gì bất thường, xin hãy cho tôi biết.

Nếu có bất điều gì muốn nói, bạn có thể liên hệ với tôi qua các mạng xã hội, tạo discussion hoặc report issue trên Github.

Welcome

manhhomienbienthuy

Xin chào. Tôi là manhhomienbienthuy, nickname khác là naa. Đây là thế giới của tôi, chào mừng đến với thế giới của tôi…

Bài viết liên quan

Bài viết mới

Chuyên mục

Lưu trữ theo năm

Câu nói yêu thích

There's a big difference between knowing the name of something and knowing something.

– Richard P. Feynman –

Thông tin liên hệ

Cảm ơn bạn đã quan tâm blog của tôi. Nếu có bất điều gì muốn nói, bạn có thể liên hệ với tôi qua các mạng xã hội, tạo discussion hoặc report issue trên Github.