😎

uvの使い方の例、めっちゃ簡単な例。すぐ読める記事

に公開

はじめに

https://zenn.dev/tazzae999jp/articles/bc617555e98fdc

の続編として書いた

uv のめちゃくちゃ、簡単な例

動作確認環境 : WSL2( Ubuntu-24.04 )

uvそのもののインストールは

https://docs.astral.sh/uv/getting-started/installation/#standalone-installer


にプラットフォームごとにやり方、書いてます。

上記の方法でuvをインストールした場合は、

uv self update
で、uv本体のバージョンを更新していけます
「インストール可能なPython一覧」が追加されていきます。古いのは消されないようです。
ただし、
uv が公式にサポート・テストしている一番古いのは Python 3.8 系とのことで、
それより、古いバージョンのPythonは、uvは使えないと考えたほうがよい

uvの細かい話まで知りません

★ uvについて、右も左もわかりませんという人が、とりあえず、使い始める
★ ために必要な最低限のことを当記事で書いてます。
★ この記事に書いたことして、最低限の基本的な使い方を実際にできてます。

pyproject.toml を作って uv sync したら、.venvの仮想環境を作成、更新されます。
具体的には「.venv」フォルダ、「uv.lock」ファイルが作成、更新されます。
uvは、「 uv venv --python "3.13.7" 」を打ち込むことで、
.venvにpython本体も、uv管理のものを入れ込めます
通常の.venvは周辺ライブラリのみでpython本体は別でしたが、
uvの場合は、python本体と周辺ライブラリをセットで
ワークスペースフォルダごとに独立管理できます。
uvは、Rustで作成されているツールなので高速らしいです。
他にも細かい事柄ありますが、現時点では詳しく知りません
ただし、当記事記載のことをやれば、初心者でも、とりあえず、使えるようにはなるでしょう
細かい話は、その後、都度調べればよろしいかと思います。

uvについて、右も左もわかりませんという人が、とりあえず、使い始める
ために必要な最低限のことを当記事で書いてます。

★ 今までは、
★ miseでpython本体をワークスペースフォルダごとに切り分けてましたが
★ miseと.venvの組み合わせはメンドイし、
★ pythonに関しては、uv一本にしとけばよろしいかと、最近、思いました。

補足
これから、新しくする分は、上記の
「 「python本体 + 周辺ライブラリ」をuv一本化 」
ですればよいと思いました。

ただし、既に、今までの分で、
「miseでpython本体 + 周辺ライブラリは.venvと「pip install -r requirements.txt」」
で、ワークスペースフォルダごとに管理しているものがある。
.venvの仮想環境を別で作成し、requirements.txtを準備して、
pip install -r requirements.txt
をしているものです。
それを、
「 「python本体 + 周辺ライブラリ」をuv一本化 」にしようとすると、
requirements.txt → pyproject.toml への書き換え作業が必要になると思うです。

requirements.txt と pyproject.toml の間で自動変換するようなやり方が
後々に見つかったら、当記事に追記していこうかと思います

uvがuv管理のpython本体を使うために必要なこと

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
★ ここの項目の記述は、後続の項目の記述を先に読まなければ意味がわからないかもしれません
★ 意味が分からない場合は、後で読んでください
★ source .venv/bin/activate
★ で仮想環境に入って
★ which python3
★ which python
★ で出てきたパスを「ls -l」で調べたら、シンボリックリンクになってるはずです。
★ そのシンボリックリンクの参照先が
★ 「 uvが管理してるユーザごとのホームディレクトリ配下で保持しているPyhotn本体 」
★ 「 例:/home/myuser/.local/share/uv/python/cpython-3.13.7-linux-x86_64-gnu/bin/python3.13 」
★ ならば、
★ 「 uvがuv管理のpython本体を使う 」状態になってます
★ そうでなければ、(PC本体のpythonや、mise管理のpythonなどだったら)
★ それは、ここに書かれた注意事項ができてないのが原因だったりします。
★ その場合は、ここの記述を、確認してください。
★ ですが、
★ ここに書かれたことは、後続の項目を先に読まなければ、意味がわからない話だと思います
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

「 準備 」の項目での記載の pyproject.toml の例示のところの
requires-python = ">=3.13"
と、
python-preference = "only-managed"
が必要です。

requires-pythonでバージョンを書いて
python-preference = "only-managed"
を書いておく必要があります

さもなくば、既にPC本体にあるpython本体や、miseのpython本体への
シンボリックリンクを.venv環境に作るだけとなってしまいます。

uvそのものが、ユーザごとのホームディレクトリ配下で、インストールし、
保持しているものを参照するための
シンボリックリンクで、.venv環境に作るようにするために、必要です。

そのうえで、後述の
uv venv --python "$(cat .python-version)"
で、venv環境への指定が必要です。

ここまでちゃんとやったら、
uvはuv管理のpython本体を使ってくれます。

準備

pyproject.toml

[project]
name = "workspace-app"
version = "0.1.0"
# Pythonは“最新安定版系”を許容(3.13以上)
requires-python = ">=3.13"
# ランタイム依存(テスト用以外)
dependencies = [
  "googletrans",
  "jupyterlab",
]

# 依存グループ(標準で dev は自動インストール対象)
[dependency-groups]
dev = [
  "pytest",
  "pytest-mock"
]

[tool.uv]
python-preference = "only-managed"
# 明示しておく(既定も "dev")
default-groups = ["dev"]

.python-version

3.13.7

使い方(前準備)

後述の「 使い方(本体) 」の項目に書かれた ★これ★ と書かれた部分が
常日頃、やるべきことですが、

最初に、当項目記載の「 使い方(前準備) 」を1度やっておかなければ
うまくいかないことがあります。

後述の「 使い方(本体) 」の項目に書かれたことをやってみて
エラーになるようでしたら、

最初に、当項目記載の「 使い方(前準備) 」を1度やってから、

再度、やれば、うまくいったりするでしょう。

基本的に、プロジェクトのワークスペースフォルダをカレントディレクトリにして
下記のコマンドは実行する。

注意、後続の★これ★
の前に、先に、1度はここに書いたことをやっておく必要があったりします。

uv self update

uv を最新化(uvは新しいPython版リストを持つため、古いuvだと新パッチを知らないことがある)

uv python install

カレントの .python-version を読み込んで該当版を入れる
あくまでユーザごとのuvの領域に入れる
uv python install は 配布在庫が無いパッチ版を指定すると失敗する(例: No download found ...)。在庫は uv python list 3.13 で確認するか、.python-version を 3.13 にして「在庫の最新」に寄せる。
.python-version は LFのみ(CRLF混入だと解決に失敗し得る)。

をやっておく必要があるときがある。

$ uv self update
info: Checking for updates...
success: Upgraded uv from v0.8.4 to v0.8.23! https://github.com/astral-sh/uv/releases/tag/0.8.23

$ uv python install
Installed Python 3.13.7 in 42.29s
 + cpython-3.13.7-linux-x86_64-gnu (python3.13)

使い方(本体)

上記の前提ができてる状況で、下記を行う。

★これ★

rm -rf .venv uv.lock
( 環境を作り直したい場合、前の分が邪魔な場合は、実行。初回は要らない。 )

uv venv --python "$(cat .python-version)"

uv sync

を打ち込む → .venv ができる
既に .venv があれば、その中身が更新される

補足
uv sync そのものは、仮想環境に入らずの状況で打ち込むものである。

以後、周辺ライブラリの更新だけなら、
pyproject.toml
を編集した後、uv sync をすればよい。

rm -rf .venv uv.lock
は、環境を作り直したい場合
そうでなく、差分更新したいなら、不要

uv venv --python "$(cat .python-version)"
は、今回は、.python-versionの中身が3.13.7の状況なので
uv venv --python "3.13.7"
になる。これは、venvに、uv管理のpython本体の3.13.7にするの意味である

これをしなければ、pythonの本体に関しては、PCの環境内のものを利用することになり、uvを通じたpython本体になりません

周辺ライブラリだけでなく、python本体も含めて、該当のプロジェクトフォルダ配下は、
独立的にuv管理されたものとしたい場合は、これが必要です。

.venvが作成された後は、

ターミナルでは、
source .venv/bin/activate
で、仮想環境に入って作業をする

VSコードや、Curosrエディタでは、Ctrl+Shit+P (または、F1)で
Python: Select Interpreter
で、.venvの中のpythonを選択して作業をする。

★ これ以後の記述は、uvの話と直接関係ありません ★

今回、たまたま、pyproject.toml に
dependencies = [
"googletrans",
"jupyterlab",
]
の記述だったので、jupyterlab と googletransの話題を、
これより下に、に書きました
★ これ以後の記述は、uvの話と直接関係ありません ★
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

活用 jupyter lab

jupyter lab
を打ち込んだら、「jupyter lab」が起動した

jupyter labなんかより「*.ipynb」のノートブックもCursorエディタで実装して動作させたほうがAIコーディングできるし使いやすいでしょう!!

たしかに、jupyterlab起動して、web画面で *.ipynb のノートブックファイルを
jupyterlabで編集しながら、動作確認できますが

*.ipynb の、ノートブックの開発作業をcursorエディタのAI機能を活用しながら
開発し動作させたいですよね。

その場合は、
pyproject.toml の
dependencies = [

ipykernel を追加しましょう!!
例)
下記のようにして、"ipykernel"が含まれた状態にする
dependencies = [
"googletrans",
"jupyterlab",
"pdfminer.six",
"ipykernel",
]

uv sync します。
ipykernelが.venvに入った状況にします。

その状況で、cursorエディタに拡張機能「Jupyter」がインストールされていれば、
*.ipynb の、ノートブックの開発作業をcursorエディタのAI機能を活用しながら
開発し動作させることが可能です

注意点として、*.ipynb のノートブックの右上で、.venvの該当のpythonを見ている状況にしておく必要があります。それを確認し、そうなってなければ、選択してそうしてください。

.venvのpythonが選択された状況にしておく必要があります

活用 googletrans

googletransの活用に関しては、下記のような実装が書ける

translator.py

# =============================================================================
# Google翻訳APIを使用した翻訳クラス
# =============================================================================
# このファイルは、Google翻訳APIを使ってテキストを翻訳する機能を提供します。
# 非同期処理(async/await)を使用して、ネットワーク通信を効率的に処理します。

# 必要なライブラリをインポート
import asyncio  # 非同期処理を行うためのライブラリ
import time     # 時間関連の処理(現在は未使用だが、将来の拡張用)
from googletrans import Translator  # Google翻訳APIを使用するためのライブラリ

class GoogleTranslator():
    """
    Google翻訳APIを使用してテキストを翻訳するクラス
    
    このクラスは以下の機能を提供します:
    - 複数言語間でのテキスト翻訳
    - ネットワークエラー時の自動リトライ機能
    - 非同期処理による効率的な翻訳処理
    """
    
    def __init__(self):
        """
        コンストラクタ(初期化メソッド)
        
        このメソッドは、クラスのインスタンスが作成される時に自動的に呼び出されます。
        翻訳器の初期化と、リトライ設定を行います。
        """
        # Google翻訳APIの翻訳器インスタンスを作成
        self.translator = Translator()
        
        # リトライ設定(ネットワークエラー時の再試行回数)
        self.max_retries = 3  # 最大3回まで再試行
        
        # リトライ間隔(秒)
        self.retry_delay = 2  # 2秒間隔で再試行

    def get_language_id(self, language_name):
        """
        言語名をGoogle翻訳APIで使用する言語コードに変換するメソッド
        
        引数:
            language_name (str): 言語名(例:「日本語」「英語」)
            
        戻り値:
            str: 言語コード(例:「ja」「en」)
            
        例:
            get_language_id("日本語") → "ja"
            get_language_id("英語") → "en"
        """
        # 言語名とGoogle翻訳APIの言語コードの対応表
        # この辞書に新しい言語を追加することで、対応言語を増やすことができます
        languages = {
            '日本語': 'ja',      # Japanese
            '英語': 'en',        # English
            '中国語': 'zh-cn',   # Chinese (Simplified)
            'フランス語': 'fr',  # French
            'ドイツ語': 'de',    # German
            'ヒンディー語': 'hi', # Hindi
            'イタリア語': 'it',  # Italian
            '韓国語': 'ko',      # Korean
            'ロシア語': 'ru',    # Russian
            'スペイン語': 'es'   # Spanish
        }
        
        # 指定された言語名に対応する言語コードを返す
        # もし言語名が辞書に存在しない場合は、KeyErrorが発生します
        return languages[language_name]

    async def convert_async(self, text_original, language_original_name, language_translated_name):
        """
        非同期でテキストを翻訳するメソッド
        
        引数:
            text_original (str): 翻訳したい元のテキスト
            language_original_name (str): 元のテキストの言語名
            language_translated_name (str): 翻訳先の言語名
            
        戻り値:
            str: 翻訳されたテキスト
            
        注意:
            このメソッドは非同期(async)なので、呼び出す時はawaitが必要です
        """
        # 言語名を言語コードに変換
        language_original_id = self.get_language_id(language_original_name)
        language_translated_id = self.get_language_id(language_translated_name)
        
        # リトライループ:最大3回まで翻訳を試行
        for attempt in range(self.max_retries):
            try:
                # 現在の試行回数を表示(デバッグ用)
                print(f"翻訳試行 {attempt + 1}/{self.max_retries}: {text_original}")
                
                # Google翻訳APIを呼び出して翻訳を実行
                # awaitキーワードで非同期処理を待機
                text_translated = await self.translator.translate(
                    text_original,                    # 翻訳したいテキスト
                    src=language_original_id,         # 元の言語コード
                    dest=language_translated_id       # 翻訳先の言語コード
                )
                
                # 翻訳が成功した場合、翻訳結果のテキスト部分を返す
                return text_translated.text
                
            except Exception as e:
                # 翻訳中にエラーが発生した場合の処理
                print(f"翻訳エラー (試行 {attempt + 1}): {e}")
                
                # まだ再試行できる場合
                if attempt < self.max_retries - 1:
                    print(f"{self.retry_delay}秒後に再試行します...")
                    # 指定された秒数だけ待機(非同期で待機)
                    await asyncio.sleep(self.retry_delay)
                else:
                    # 最大試行回数に達した場合、エラーを再発生させる
                    raise e

    def convert(self, text_original, language_original_name, language_translated_name):
        """
        同期的にテキストを翻訳するメソッド(外部から呼び出すメインメソッド)
        
        引数:
            text_original (str): 翻訳したい元のテキスト
            language_original_name (str): 元のテキストの言語名
            language_translated_name (str): 翻訳先の言語名
            
        戻り値:
            str: 翻訳されたテキスト
            
        注意:
            このメソッドは非同期メソッドを同期的に実行するためのラッパーです。
            外部からはこのメソッドを呼び出すことで、簡単に翻訳機能を使用できます。
        """
        try:
            # 実行中のイベントループを取得(推奨される方法)
            loop = asyncio.get_running_loop()
            
            # 既存のイベントループで非同期メソッドを実行
            return loop.run_until_complete(self.convert_async(text_original, language_original_name, language_translated_name))
                
        except RuntimeError:
            # イベントループが実行中でない場合
            # 新しいイベントループを作成して非同期メソッドを実行
            return asyncio.run(self.convert_async(text_original, language_original_name, language_translated_name))

trans = GoogleTranslator()
text_translated = trans.convert("こんにちは", "日本語", "英語")
print(f"翻訳結果: {text_translated}")

で、
翻訳結果: Hello

以上

Discussion