Pythonパッケージ開発チュートリアル

個人的なパッケージ開発チュートリアルです。ここに書いてあるのは一例なので、ググったりChatGPTに聞くなりして、より良い方法を見つけるなどして各自レベルアップしてください。

最近作成したAlphaFold3のインプット支援・アウトプット解析ツールである[alphafold3_tools](https://github.com/cddlab/alphafold3_tools)もこの流れで作っています。

## 使うツール

ソフトウェア・パッケージ群

- **[uv](https://docs.astral.sh/uv/)**: Pythonパッケージ開発ツール。2024年8月頃に[Rye](https://rye.astral.sh/)でできる操作を統合し始めた。
- **Visual Studio Code (VSCode)**: Integrated Development Environment／統合開発環境とそのプラグイン
  - [Pythonプラグイン](https://marketplace.visualstudio.com/items?itemName=ms-python.python)
  - [Ruff](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff) (Rustで書かれた自動フォーマット)
  - [mypy](https://marketplace.visualstudio.com/items?itemName=matangover.mypy) (型チェッカ）
  - [GitHub Copilot](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot) (GitHubが開発したAIによるコード補完, 要GitHub EducationまたはGitHub Pro)
  - デバッグ機能

## VSCodeとの連携

Windows, macOS, Linux、いずれのOSでも動作するように用意されているVisual Code Studio (VSCode)というIDE（統合開発環境）と連携するのがわかりやすいので、これを使っていきます。特にGitHubとVSCodeはともにMicrosoftによって開発が行われていることもあり、両者の連携が図られています。

VSCodeは様々なソフトウェア開発に向いていますが、Pythonの開発環境においてはまず

- [Pythonプラグイン](https://marketplace.visualstudio.com/items?itemName=ms-python.python)
- [Ruff](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff) (linter)
  - [RuffのVSCode拡張機能設定](https://zenn.dev/zaspa/articles/95580ba7c0c867)
  - isort, black, flake8などのツールを統合したもの。
- [mypy](https://marketplace.visualstudio.com/items?itemName=matangover.mypy) (型チェッカ）
  - 設定方法：[Python の型チェックを VSCode 上で行いたい](https://zenn.dev/k0kishima/articles/5466aaeb57be7a)
- [GitHub Copilot](https://docs.github.com/ja/copilot/getting-started-with-github-copilot) （AIが先読みして入力したいコードを先に提示してくれる。要[GitHub Global Campus](https://docs.github.com/ja/education/explore-the-benefits-of-teaching-and-learning-with-github-education/github-global-campus-for-students/apply-to-github-global-campus-as-a-student)への登録）
- デバッグ機能

を使えるようになりましょう。一括でこれらをインストールしたい場合は、VSCodeのターミナルで以下のコマンドを入力してください。参考：<https://zenn.dev/karaage0703/books/80b6999d429abc8051bb/viewer/349524>

ターミナルは以下のメニューの"新しいターミナル"から開けます（ショートカットキーを覚えると楽）。
![2025-04-03 11.05.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/1ccbc28f-30e4-4584-8011-febf674beab9.png)

下にターミナルが開きました。

![2025-04-03 11.06.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/181f1801-d5c4-4a0a-930e-b06fc17dd7cc.png)

このターミナルに以下のコマンドをまとめて打ちます。

```bash
code --install-extension charliermarsh.ruff
code --install-extension davidanson.vscode-markdownlint
code --install-extension ms-ceintl.vscode-language-pack-ja
code --install-extension ms-vscode-remote.remote-containers
code --install-extension ms-vscode-remote.remote-ssh
code --install-extension ms-vscode-remote.remote-ssh-edit
code --install-extension ms-vscode-remote.remote-wsl
code --install-extension ms-vscode-remote.vscode-remote-extensionpack
code --install-extension ms-vscode.remote-explorer
code --install-extension ms-vscode.remote-server
code --install-extension ms-vscode.test-adapter-converter
code --install-extension ms-python.debugpy
code --install-extension ms-python.python
code --install-extension ms-python.vscode-pylance
code --install-extension github.copilot
code --install-extension github.copilot-chat
code --install-extension github.github-vscode-theme
code --install-extension github.vscode-github-actions
code --install-extension github.vscode-pull-request-github
code --install-extension ms-toolsai.jupyter
code --install-extension ms-toolsai.jupyter-keymap
code --install-extension ms-toolsai.vscode-jupyter-slideshow
code --install-extension shd101wyy.markdown-preview-enhanced
code --install-extension tamasfe.even-better-toml
code --install-extension vscode-icons-team.vscode-icons
code --install-extension yzhang.markdown-all-in-one
```

これによって便利プラグインがまとめてインストールされます。

また、日本語環境の方が良い場合は、いま導入した`ms-ceintl.vscode-language-pack-ja`によって日本語環境に変更することができます。

`Shift+Ctrl+P`または`Shft+Command+P`でConfigure Display Languageから言語を選択します。

![2025-04-03 10.59.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/c0bfc5e6-dfdc-4753-8bd0-e203f25e062c.png)

![2025-04-03 10.59.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/fbca3382-27f5-4820-94a6-0740765daacb.png)

これで日本語を選び、再起動すると、表示が日本語に変化します。

## パッケージ開発チュートリアル：newcomer-practice

ここからはuvを使って実際に`newcomer-practice`ディレクトリを作成して公開するところまでやってみます。

### uvのインストール

まずは[uvの公式ドキュメント](https://docs.astral.sh/uv/#getting-started)を参照のこと。macOSまたはLinuxの場合は、以下でインストールします。

```bash
$ curl -LsSf https://astral.sh/uv/install.sh | sh
downloading uv 0.6.12 x86_64-apple-darwin
no checksums to verify
installing to /Users/bilab/.local/bin
  uv
  uvx
everything's installed!

To add $HOME/.local/bin to your PATH, either restart your shell or run:

    source $HOME/.local/bin/env (sh, bash, zsh)
    source $HOME/.local/bin/env.fish (fish)
WARNING: The following commands are shadowed by other commands in your PATH: uv uvx
```

インストール後にターミナルを再起動すると`uv`コマンドが使えるようになっているはずです。

```bash
$ uv --version
uv 0.6.12 (e4e03833f 2025-04-02)
```

::::note
`uv`は現在も精力的に機能が更新され続けていますので、定期的に更新しましょう。`uv self update`で更新できます。
::::

### pythonのインストール

今回はpython3.12を使います。macOSであればHomebrewからインストールすることができます。Ubuntu 22.04だとデフォルトは3.10です。

```bash
brew install python@3.12
```

なお、デモの範囲ではPython 3.6〜3.13であれば問題なく動きますので、その範囲のPythonが入っていれば適宜読み替えて進めて結構です。

### 作業ディレクトリの作成

uvをインストールし終わったら、まずは、作業ディレクトリを作成しましょう。以下のコマンドを実行してください。

```bash
mkdir -p ~/Desktop/work/newcomer-practice
cd ~/Desktop/work/newcomer-practice
```

`newcomer-practice`ディレクトリで、uvを使ってパッケージ開発を行います。

```bash
$ uv init
Initialized project `newcomer-practice`
```

`newcomer-practice`ディレクトリには、隠しを含めて5つのファイルと1つの隠しディレクトリが作成されます。

```bash
$ ls -a
.               .git            .python-version main.py
..              .gitignore      README.md       pyproject.toml
```

`.python-version`はuvでのPythonのバージョンを指定するファイルです。中には3.13と書かれていますが、これを3.12や3.11とすることで、開発のためのPythonバージョンを下げることができます。まずはこのファイルをVSCodeなどで開いて`3.12`にしておいてください。

```bash
echo "3.12" > .python-version
```

また、後ほどパッケージをビルドするためのディレクトリ`pack_test`をこの中に作成しておきます。

```bash
# ~/Desktop/work/newcomer-practiceディレクトリで実行する。
mkdir -p pack_test
```

`pyproject.toml`はuvの設定ファイルです。Pythonのパッケージ開発に必要な情報が書かれています。

```toml
[project]
name = "newcomer-practice"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []
```

ここに書ける設定は非常に幅広く、また他の開発ツールとの連携を行うために必要な設定を書く必要があるため、詳細は[uv - Projects](https://docs.astral.sh/uv/concepts/projects/)を読んでください。ここでは以下のようなtomlファイル設定に書き換えてください。

::::note info
2025/4/3 `tool.ruff`周りについてアップデート
::::

```toml
[project]
name = "newcomer-practice"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []

[tool.uv]
dev-dependencies = ["mypy", "notebook", "pandas", "pytest", "ruff", "pandas"]

[tool.ruff]
indent-width = 4
line-length = 88 # Same as Black.
exclude = [".ruff_cache", ".ruff.toml", ".ruff.lock"]
target-version = "py312"

[tool.ruff.lint]
select = [
    "F", # Flake8
    "B", # Black
    "I", # isort
    "E", # error
    "W", # warning
]
ignore = ["F401", "E501"]
fixable = ["ALL"]
unfixable = []

[tool.ruff.isort]
combine-as-imports = true
section-order = ["future", "standard-library", "third-party", "first-party", "local-folder"]
split-on-trailing-comma = true

[tool.ruff.format]
quote-style = "double"

[tool.ruff.lint.isort]
known-third-party = ["fastapi", "pydantic", "starlette"]

[tool.pytest.ini_options]
filterwarnings = [
    "ignore:.*Jupyter is migrating.*:DeprecationWarning",
]
addopts = "-vv --color=yes"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.metadata]
dynamic = ["name", "version"]

[tool.hatch.build.targets.wheel]
packages = ["pack_test"]
```

![2025-04-03 12.06.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/49af1c51-96fc-4a03-90f2-665090199058.png)

これに書き換えた後、`uv sync`を実行すると、開発環境が整います。

```bash
$ uv sync
Resolved 107 packages in 6ms
      Built newcomer-practice @ file:///Users/YoshitakaM/Desktop/work/newcomer-practice
Prepared 16 packages in 1.77s
Installed 104 packages in 383ms
 + anyio==4.8.0
 + appnope==0.1.4
 + attrs==25.1.0
...
...
 + webcolors==24.11.1
 + webencodings==0.5.1
 + websocket-client==1.8.0
```

これによって`.venv`ディレクトリに仮想環境が構築され、同時にその仮想環境に必要なパッケージがインストールされます。

::::note
uvで構築された`pyproject.toml`は複数人で同じ開発環境を共有できるというメリットもあります。後ほどGitHubでパッケージが公開されるとき、このファイルがあれば、他の人がこのパッケージを`git clone`でダウンロードしてきたあと、`uv sync`で開発者と同じ環境をすぐに構築することができます。そして変更を加えてGitHubにpull requestを送ることができ、開発者はその変更をレビューしてマージすることができます。この仕組みによって、ユーザーがすぐに開発者になることができ、安定したパッケージ開発が可能になります。
::::

仮想環境は`newcomer-practice`ディレクトリにて`. .venv/bin/activate`を実行することで有効になります。また、`deactivate`を実行することで無効になります。

```bash
# 仮想環境の有効化
. .venv/bin/activate
# 仮想環境の無効化
deactivate
```

::::note
VSCodeを使っている場合、VSCodeのターミナルから`uv sync`を実行した時点で仮想環境の作成が検知され、「これをワークスペースフォルダに選択しますか？」と表示されるのでそれを許可してください。
![2025-04-03 11.11.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/1562ada4-7480-41d6-8685-1976a7a543af.png)

ここで許可しなかった場合で後に切り替えたい場合は、新たに作業ディレクトリ内でPythonファイルを開いた時に、右下のPythonのバージョンをクリックして、仮想環境へのPATH`/path/to/newcomer-practice/.venv/bin/python3.12`を選択してください。
![2025-04-03 11.11.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/8f56c79d-e7d1-4c66-bf93-d991279dd5b0.png)

![2025-04-03 11.11.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/31033f13-7d8b-4bb9-9205-560bee7010de.png)
::::

### コードの作成

コードは`pack_test`ディレクトリに配置します。ここでは、`pack_test`ディレクトリに`hello.py`というファイルを作成し、以下のような内容を書いてください。

![2025-04-03 11.10.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/489b4d92-0104-4b6c-ad03-a4344b64aa34.png)

```python:pack_test/hello.py
def hello_test1(input1: str, input2: str, switch1: bool, switch2: bool) -> None:
    """uvパッケージングのデモ用挨拶関数。

    指定されたスイッチの状態に応じて、入力された名前で挨拶メッセージを表示します。

    Args:
        input1: 最初の挨拶で使用する名前
        input2: 2番目の挨拶で使用する名前
        switch1: Trueの場合、input1を使った挨拶を表示
        switch2: Trueの場合、input2を使った挨拶を表示

    Returns:
        None

    Example:
        >>> hello_test1("太郎", "花子", True, False)
        Hello uv packaging!. I'm 太郎.
        >>> hello_test1("太郎", "花子", False, True)
        I'm 花子. Nice to meet you.
    """
    if switch1:
        print(f"Hello uv packaging!. I'm {input1}.")
    if switch2:
        print(f"I'm {input2}. Nice to meet you.")
```

次に、これを呼び出す`test1.py`を同`pack_test`ディレクトリに作成します。

```python:pack_test/test1.py
#!/usr/bin/env python3
from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser

from pack_test.hello import hello_test1


def main():
    parser = ArgumentParser(
        formatter_class=ArgumentDefaultsHelpFormatter,
        description="Test script for uv packaging.",
    )
    group = parser.add_mutually_exclusive_group()
    parser.add_argument(
        "-i",
        "--input1",
        help="argument for input1",
        type=str,
        required=True,
    )
    parser.add_argument(
        "-j",
        "--input2",
        help="argument for input2",
        type=str,
    )
    group.add_argument(
        "-s",
        "--switch1",
        help="Turn on switch1. Switch1 and Switch2 are mutually exclusive.",
        action="store_true",
    )
    group.add_argument(
        "-t",
        "--switch2",
        help="Turn on switch2. Switch1 and Switch2 are mutually exclusive.",
        action="store_true",
    )
    args = parser.parse_args()
    hello_test1(args.input1, args.input2, args.switch1, args.switch2)


if __name__ == "__main__":
    main()

```

簡単な解説ですが、この`test1.py`では、`pack_test/hello.py`に書き込んだ`hello_test1`関数を呼び出しています。`hello_test1`関数は、`input1`と`input2`という2つの引数を取り、`switch1`と`switch2`という2つのスイッチを取ります。`switch1`が`True`の場合、`input1`を表示します。`switch2`が`True`の場合、`input2`を表示します。`test1.py`は、コマンドライン引数として`-i`と`-j`と`-s`と`-t`を取り、それぞれ`input1`と`input2`と`switch1`と`switch2`に対応します。`-i`は必須の引数です。`-j`は任意の引数です。`-s`と`-t`はスイッチです。`-s`がある場合、`switch1`が`True`になります。`-t`がある場合、`switch2`が`True`になります。

ここまでの操作で、`newcomer-practice`内のディレクトリ構成は以下のようになります。

```bash
newcomer-practice
├── LICENSE
├── README.md
├── main.py
├── pack_test
│   ├── hello.py
│   └── test1.py
├── pyproject.toml
└── uv.lock
```

### VSCodeとRuffを使ってPythonコードの自動フォーマットを導入する

Pythonファイルを作ってみましたが、なんか`hello.py`の方では表示が赤くなっています。

![2025-04-03 12.21.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/7fde91fa-5423-45aa-bbb0-92bb4572badf.png)
![2025-04-03 11.15.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/b81062d9-7866-44f3-94e2-f3eee7066cbb.png)

画像の上の方に赤い下波線が、一番下の行に黄色の下波線が現れています。近くにマウスをホバーさせるとその理由が表示されます。

これはPython文法チェッカーのflake8が、正しい文法になるように自動チェックを働かせてくれている状態です。その指示に従うことでErrorやWarningを解決できます。が、これって面倒ですよね。自動で修正してほしいですよね。
これをVSCodeである程度自動で行ってくれるようにするために、以下の設定を追加します。
`Ctrl+,`または`Command+,`で、設定画面を開きます。画像の赤枠の部分を押すと`settings.json`が開きます。

![2025-04-03 11.19.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/28bcfa61-3515-46f1-bd53-4bc5415891cf.png)


`settings.json`を開いて、以下の内容を入力します。すでに他の設定値がある場合は、`,`で間を区切ることを忘れないようにしながら設定値を追記します。

```json:settings.json
{
    "files.autoSave": "onWindowChange",
    "[python]": {
        "editor.formatOnSave": true,
        "editor.defaultFormatter": "charliermarsh.ruff",
        "editor.codeActionsOnSave": {
            "source.organizeImports": "explicit",
            "source.fixAll": "explicit"
        },
    },
    "[markdown]": {
        "editor.formatOnSave": true,
        "editor.formatOnPaste": true,
        "editor.defaultFormatter": "DavidAnson.vscode-markdownlint",
    },
    "flake8.enabled": false,
}
```

この設定追記によって、ウィンドウが変わると自動でファイル保存が実行されるようになり、かつpythonのファイルを編集しているときはRuffによる自動フォーマットが実行されるようになります（ついでにmarkdownも）。また、`"flake8.enabled": false`を用いて、flake8による文法チェッカーを無効化しています。このへんの設定は好みによるので好きな値に設定してください。

::::note warn
`settings.json`の編集時に、下波線が現れている場合、またはハイライトが消えている場合は、その設定が有効でないことを表しています。画像では、`editor.defaultFormatter`に下波線が、`ruff.lineLength: 88`のハイライトが消えています。
![2025-04-03 11.30.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/8baeaf51-f773-4235-b9a7-854cdce6ccd3.png)
`,`を忘れてしまっているために設定が有効化されていないこともありますが、Ruffについては、拡張機能：マーケットプレースから手動でインストールする必要があるかもしれません。この場合、画像左の赤枠から拡張機能を選び、ruffと入力して現れるRuffを手動でインストールしてください。その後、`settings.json`の表示に異常がなくなればOKです。
![2025-04-03 11.23.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/7a19d143-ffb5-4720-a369-2233536f1fc9.png)
::::

これを用いて`hello.py`や`test1.py`に変更を加え、ウィンドウを変えたり保存したりすると、自動である程度フォーマッターが働いて整形してくれるようになるはずです。

### パッケージの動作

実際にこの自作の関数が期待通りに動作するかを試してみましょう。ターミナルから以下のコマンドを入力し、仮のディレクトリを作成してその中でpython3.12の仮想環境を有効化します。

```bash
# mktemp -dで一時的なディレクトリを作成し、その中で仮想環境を有効化する。
cd "$(mktemp -d)"
python3.12 -m venv .venv
. .venv/bin/activate
```

次に、この中でpipを用いて`newcomer-practice`パッケージをインストールします。このとき`-e`をつけることでeditableモードでインストールします。これにより、`~/Desktop/work/newcomer-practice`パッケージの中身を変更しても、再度インストールしなくても変更が反映されます。

```bash
$ python3.12 -m pip install -e ~/Desktop/work/newcomer-practice
...
...
Successfully built newcomer-practice
Installing collected packages: newcomer-practice
Successfully installed newcomer-practice-0.1.0

[notice] A new release of pip is available: 25.0 -> 25.0.1
[notice] To update, run: pip install --upgrade pip
```

これを実行して、python3.12をインタラクティブに起動し、以下のような動作が確認できれば成功です。

```bash
$ python3.12
Python 3.12.9 (main, Feb  4 2025, 14:38:38) [Clang 16.0.0 (clang-1600.0.26.6)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from pack_test import hello

>>> hello.hello_test1("AAA", "BBB", True, False)
Hello uv packaging!. I'm AAA.
>>> hello.hello_test1("AAA", "BBB", False, True)
I'm BBB. Nice to meet you.
>>> #(Ctrl-Dを押すとPythonインタラクティブモードを抜けられる)
```

さらに、このコマンドをターミナルのコマンドラインから実行するために、以下の設定を`pyproject.toml`に追記します。

```toml:pyproject.toml

[project.scripts]
kadai_test1 = "pack_test.test1:main"
```

これを実行した状態で再度`pip install`を実行すると、今度は`kadai_test1`というコマンドが使えるようになります。

```bash
$ python3.12 -m pip install -e ~/Desktop/work/newcomer-practice
Obtaining file:///Users/YoshitakaM/Desktop/work/newcomer-practice
  Installing build dependencies ... done
  Checking if build backend supports build_editable ... done
...
...
  Attempting uninstall: newcomer-practice
    Found existing installation: newcomer-practice 0.1.0
    Uninstalling newcomer-practice-0.1.0:
      Successfully uninstalled newcomer-practice-0.1.0
Successfully installed newcomer-practice-0.1.0

[notice] A new release of pip is available: 25.0 -> 25.0.1
[notice] To update, run: pip install --upgrade pip

$ kadai_test1 -h
usage: kadai_test1 [-h] -i INPUT1 [-j INPUT2] [-s | -t]

Test script for uv packaging.

options:
  -h, --help            show this help message and exit
  -i INPUT1, --input1 INPUT1
                        argument for input1 (default: None)
  -j INPUT2, --input2 INPUT2
                        argument for input2 (default: None)
  -s, --switch1         Turn on switch1. Switch1 and Switch2 are mutually exclusive. (default: False)
  -t, --switch2         Turn on switch2. Switch1 and Switch2 are mutually exclusive. (default: False)
```

これで、`kadai_test1`というコマンドが使えるようになりました。引数を指定して実行してみましょう。

```bash
$ kadai_test1 -i AAA -j BBB -s
Hello uv packaging!. I'm AAA.
$ kadai_test1 -i AAA -j BBB -t
I'm BBB. Nice to meet you.
$ kadai_test1 -i AAA -j BBB -s -t
usage: kadai_test1 [-h] -i INPUT1 [-j INPUT2] [-s | -t]
kadai_test1: error: argument -t/--switch2: not allowed with argument -s/--switch1
```

最後のコマンド`kadai_test1 -i AAA -j BBB -s -t`は、`-s`と`-t`が同時に指定されているためエラーが出ます。これは`group = parser.add_mutually_exclusive_group()`と指定してあるためです。これで、自作のパッケージが正常に動作することが確認できました。

### 依存パッケージの追加

プロジェクト内でnumpy, matplotlibなどのパッケージを使いたい場合、ターミナルから`uv add`コマンドで追加することができます。

```bash
uv add numpy matplotlib
```

`uv add`を行うと、`pyproject.toml`ファイルの`[project.dependencies]`に追加されます。

```toml:pyproject.toml
[project]
name = "newcomer-practice"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["numpy", "matplotlib"]
```

バージョン指定や、githubからのgitでのインストールも可能です。

```bash
# バージョン指定
uv add "requests==2.31.0"
# git dependency
uv add git+https://github.com/psf/requests
```

`uv remove`でパッケージを取り除くことも可能です。

```bash
uv remove numpy matplotlib
```

パッケージを追加した後は、`uv sync`を実行して依存パッケージをインストールします。

```bash
uv sync
```

`uv lock --upgrade-package`でパッケージをアップグレードすることもできます。

```bash
uv lock --upgrade-package numpy matplotlib requests
```

`--upgrade-package`フラグは、指定されたパッケージを最新の互換バージョンに更新しようとしますが、lockファイルの他の部分はそのままにします。

また、`--dev`で開発用の依存パッケージとしてインストールすることも可能です。開発用依存パッケージは、実際のパッケージには含まれず、開発時のみに必要なパッケージです。主にjupyter notebook, mypy, ruffなどの開発支援ツールを入れておくとよいでしょう。

```bash
uv add notebook mypy ruff --dev
```

### GitHub連携

Gitとはプログラムのソースコードなどの変更履歴を記録・追跡するための分散型バージョン管理システムです。Linuxカーネルのソースコード管理に用いるためLinuxの生みの親であるLinus Torvaldsによって開発され、それ以降ほかの多くのプロジェクトで採用されています。

GitHubはソフトウェア開発のプラットフォームであり、ソースコードをホスティングすることで複数人のソフトウエア開発者と協働してコードをレビューしたり、プロジェクトを管理しつつ開発を行うことができます。コードのバージョン管理システムにはGitを使用しています。2008年4月にサービス開始され、2010年にGitHub社が設立されました。2018年にはMicrosoftに買収されています。

現在では研究者もGitHubなどのプラットフォームを使って研究に使ったコードを公開することが推奨されています。これによって他のユーザーもその人の実験を再現することができるようになります。

#### GitHubのアカウント作成

アカウント作成など基本的なところは省略します。また、学生や大学の学生証・職員証を持っている人は[GitHub Education](https://education.github.com/)に登録することで**GitHub Pro**アカウントになることができ、**GitHub Copilotが使えるようになる**ので、この手続きをしておくことをおすすめします。

- [Github Education の申請方法](https://zenn.dev/iizuka0000/articles/how-to-apply-for-github-education)

登録には学生証・職員証が必要です。申請から承認までには2週間ほどかかります（と言われますが多くの場合は割とすぐに承認されます）。承認されたら、GitHubのアカウントの設定から「Education」の項目に「GitHub Education」が表示されていることを確認してください。

#### GitHub Copilotを使う

<https://github.com/settings/copilot> にアクセスして、**GitHub Copilotを有効**にしてください。

![8IhyCuV.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/9c049fe8-bcd6-4ca5-9489-02a113f4a933.png)

さらに、VSCode上でGitHub Copilotを使うには、**VSCodeでアカウントを連携する**必要があります。VSCodeの左下のアイコンをクリックして、GitHubアカウントを連携してください。また、**拡張機能からGitHub Copilotを検索し、これをインストールしてください**。

使えるようになると、VSCodeの右下に「Copilot」というアイコンが表示されます。

#### GitHubでリポジトリを作成する

GitHubと連携して自身の**リポジトリ**を作成する方法を説明します。本来gitはローカル（自身のパソコン）で管理するものですが、GitHubを使うことで、リモート（インターネット上）にも保存することができます。また、GitHubを使うことで、他の人との共同作業も可能になります。

gitはもともとコマンドラインベースなので、すべての操作はターミナルのコマンドから行うことができます。それらのコマンドをしっかりと覚えたい方は慶應義塾大学の渡辺先生の[GitHub演習](https://kaityo256.github.io/github/)のウェブサイトを参考にするとよいでしょう。しかし、これらのコマンドを完全に覚えるのは大変ですし、今ではVScodeまたはGitHubのウェブサイト上からのGUI操作でおおよそ最低限必要な操作は行うことができます。この章では、GUI操作でリポジトリを作成する方法を説明します。

GitHubのトップ画面に新しくリポジトリを作成するためのボタンがあります。このボタンをクリックすると、リポジトリの作成画面に移動します。

![adfadf.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/79bd8185-fee6-44d2-a2d5-bcba01ed4b7c.png)

Create a new repositoryの画面で、プロジェクトファイルを保存するためのリポジトリを作成します。リポジトリ名は、プロジェクト名と同じにしておくとよいでしょう。

![jXOOhxS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/76e97d48-dcae-412d-af7e-f9f30966eb7b.png)

この画面では、リポジトリの説明を書くことができます。また、リポジトリの公開範囲を設定することができます。ここでは、Publicにしておきます。Publicにすると、他の人がこのリポジトリを見ることができます。Privateにすると、自分以外は見ることができません。PrivateはGitHub Educationに加入していれば選択できますが、基本的には有料サービスです。

**Add a README file**にはチェックを入れておきましょう。

`.gitignore`は、作成したいプロジェクトで主に使われることになる言語を設定する事が多いです。ここでは、Pythonを選択します。
Choose a licenseのところではそのプロジェクトのライセンスを設定します。この効力は大きく、ユーザーおよび営利目的とする企業はGitHub上のソフトウェアのライセンスの仕様に必ず従わなければなりません。最も制限がゆるいライセンスはMIT Licenseと言われます。ここでは例としてMIT Licenseを選択します。

リポジトリを作成するとこのような画面になります。

![リポジトリメイン1](https://i.imgur.com/rkVYH9e.png)

ここに向けて、先ほど作成した`newcomer-practice`パッケージを、GitHubのリポジトリnewcomer-practiceに紐づけます。以下にその手順を示します。

まず、ローカルPCにおいてgitを使う準備として、`git config`でコードの変更をgitにコミットするときのメールアドレスを設定する必要があります。詳細は[Git のコミットメールアドレスを設定する](https://docs.github.com/ja/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/setting-your-commit-email-address#setting-your-commit-email-address-in-git)に詳しいので、こちらの手順を参考にしてください。ここでは[コンピュータにあるすべてのリポジトリ用にメールアドレスを設定する](https://docs.github.com/ja/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/setting-your-commit-email-address#setting-your-email-address-for-every-repository-on-your-computer)の手順に従い、グローバルなメールアドレス設定を行います。GitHubアカウントを作成したときのユーザー名とメールアドレスを使って、ターミナルから

```bash
git config --global user.name "Taro Yamada"
git config --global user.email "fooooo@gmail.com"
```

と入力しておきます。

ターミナルを開き、すでに作成済みのローカルのnewcomer-practiceディレクトリへ移動します。

```bash
cd ~/Desktop/work/newcomer-practice
```

まだGitを初期化していない場合は、`git init`を実行してリポジトリを作成します。（`uv init`を使ってローカルにパッケージを先に作成した場合は、このコマンドは不要です。）

次に、このローカルリポジトリをGitHubのリポジトリ（<https://github.com/YoshitakaMo/newcomer-practice.git>)と紐づけます。

```bash
git remote add origin https://github.com/YoshitakaMo/newcomer-practice.git
```

リモートリポジトリの設定を確認するには、以下を実行します。

```bash
$ git remote -v
origin  https://github.com/YoshitakaMo/newcomer-practice.git (fetch)
origin  https://github.com/YoshitakaMo/newcomer-practice.git (push)
```

`git branch -M main`でブランチをmainに変更します。GitHubのデフォルトブランチ名がmainの場合は、以下を実行します。

```bash
git branch -M main
```

リモート(<https://github.com/YoshitakaMo/newcomer-practice.git>)のmainブランチの内容をまずローカルにコピーします。

```bash
$ git pull origin main
From https://github.com/YoshitakaMo/newcomer-practice
 * branch            main       -> FETCH_HEAD
error: The following untracked working tree files would be overwritten by merge:
        .gitignore
        README.md
Please move or remove them before you merge.
Aborting
```

ここでエラーが出ました。この原因は、すでにリモートのmainブランチに`.gitignore`と`README.md`が存在しているためです。今回はまだこれらのファイルに手を付けていませんので、ローカルの`newcomer-practice`にあるこれらのファイルを削除してから、再度`git pull origin main`を実行します。

```bash
$ rm .gitignore README.md
$ git pull origin main
From https://github.com/YoshitakaMo/newcomer-practice
 * branch            main       -> FETCH_HEAD
```

これでリモートのmainブランチの内容がローカルにコピーされました。次に、ローカルの変更をステージングしてコミットします。

```bash
$ git add .
$ git commit -m "initial commit"
[main (root-commit) 29b1d0e] initial commit
 ６ files changed, 1671 insertions(+)
 create mode 100644 .python-version
 create mode 100644 main.py
 create mode 100644 pack_test/hello.py
 create mode 100644 pack_test/test1.py
 create mode 100644 pyproject.toml
 create mode 100644 uv.lock
```

最後に、ローカルのmainブランチの内容をリモートのmainブランチにプッシュします。

```bash
$ git push origin main
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Delta compression using up to 20 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (9/9), 50.25 KiB | 3.59 MiB/s, done.
Total 9 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To https://github.com/YoshitakaMo/newcomer-practice.git
   674d97d..d246ec1  main -> main
```

::::note
なお、このgitコマンドを使った一連の手順は、VSCodeのGitHub拡張機能を使うことでGUIで行うこともできます。VSCodeの左側にあるGitアイコンをクリックすると、リポジトリの変更をステージングしたり、コミットしたり、プッシュしたりすることができます。詳しくは[VSCodeの公式ドキュメント](https://code.visualstudio.com/docs/editor/versioncontrol)を参照してください。
::::

GitHubのリポジトリページ（<https://github.com/YoshitakaMo/newcomer-practice>）を開き、ファイルが正しくアップロードされているか確認します。これでローカルのnewcomer-practiceとGitHubのリポジトリが紐づきました！ 🚀

::::note
今回はローカルにパッケージを開発してからGitHubに同名のリポジトリを作るという流れで行いましたが、先にGitHubリポジトリを作成してそれをローカルPCに`git clone`しておき、その中で`uv init`してからパッケージ開発を進めるという順番でも可能です。
::::

ちなみに、**このリポジトリの画面で`.`キーを押すと、GitHubのウェブサイト上でVSCodeのGUIを開いているかのようにファイルを編集すること**もできます。github.devというアドレスにアクセスすることができ、VSCodeライクなGUIが現れます。

![Webブラウザ上でのVSCode](https://i.imgur.com/6k9iNxI.png)

このように、GitHubとVSCodeを連携させることで、ローカルでの作業とリモートでの作業をシームレスに行うことができます。

#### GitHubに置いたPythonパッケージをpipでインストールできることを確認する

作成したPythonパッケージをGitHubにアップロードしておくと、`pip install`で取り込むことが可能になります。具体的には

| コマンドライン | 説明 |
| :---: | :---: |
| `pip install pkg_name@git+https://github.com/username/repo_name.git` | リポジトリ名とパッケージ名が異なる場合は「パッケージ名@」を「git+https://…….git」の前に付加 |
| `pip install git+https://github.com/username/pkg_name.git` | リポジトリ名とパッケージ名が同じならこう書ける |
| `pip install git+https://github.com/username/pkg_name.git@v1.0` | 「@v1.0」のように末尾にバージョンやタグを付加できる |

という形でインストールできます。これを試してみましょう。適当なディレクトリを作り、その中で仮想環境を起動してから`pip`を行います。

```bash
$ cd"(mktemp -d)"
$ python3.12 -m venv .venv
$ source .venv/bin/activate
$ which python3.12
# /private/var/folders/xxxxxxxxxxxx/.venv/bin/python3.12 # なんか適当なtempディレクトリの中のpython3.12になっていることを確認
$ python3.12 -m pip install git+https://github.com/YoshitakaMo/newcomer-practice.git
Collecting git+https://github.com/YoshitakaMo/newcomer-practice.git
  Cloning https://github.com/YoshitakaMo/newcomer-practice.git to /private/var/folders/2x/
  ......
Successfully built newcomer-practice
Installing collected packages: newcomer-practice
Successfully installed newcomer-practice-0.1.0

[notice] A new release of pip is available: 25.0 -> 25.0.1
[notice] To update, run: pip install --upgrade pip

$ kadai_test1 -h
usage: kadai_test1 [-h] -i INPUT1 [-j INPUT2] [-s | -t]
```

ということで、GitHubに置いた自作Pythonパッケージをpipでインストールでき、自作の`kadai_test1`が使えるようになっていることを確認できました。

あとはこのリポジトリをどんどん改良していくだけです。また、他の人にも`git clone`してもらうことで、他の人との共同作業も可能になります。


## Pythonパッケージ開発ツール"uv"の使い方

### uvのインストール

まずは[uvの公式ドキュメント](https://docs.astral.sh/uv/#getting-started)を参照のこと。macOSまたはLinuxの場合は、以下でインストールします。

```bash
$ curl -LsSf https://astral.sh/uv/install.sh | sh
downloading uv 0.6.5 aarch64-apple-darwin
installing to /Users/YoshitakaM/.cargo/bin
  uv
  uvx
everything's installed!
```

インストール後に`exec $SHELL -l`などでshellを再読み込みを行うとuvを起動できます。今回用いるuvのバージョンは以下です。

```bash
$ uv --version
uv 0.6.5 (bcbcd0a1e 2025-03-06)
```

::::note
`uv`は現在も精力的に機能が更新され続けていますので、定期的に更新しましょう。`uv self update`で更新できます。
::::

### 新規プロジェクトの初期化

`init`で新規プロジェクトを作成することができます。`my-project`は任意のプロジェクト名です。既に作成したいプロジェクト下にいる場合は`uv init`だけで作成できます。

```bash
$ uv init my-project
Initialized project `my-project` at `/Users/YoshitakaM/Desktop/my-project`
$ cd my-project
```

すると以下のディレクトリ構造が作成されて、`pyproject.toml`も自動で生成されます。

```shell
.
├── README.md
├── main.py
└── pyproject.toml
```

`pyproject.toml`の中身は以下のようになっています。

```toml:pyproject.toml
[project]
name = "my-project"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []
```

#### パッケージの同期

`pyproject.toml`をもとにパッケージをインストールします。以下のコマンドを実行できます。

```bash
uv sync
```

Rye同様に仮想環境として`.venv`が作成されて、また、`uv.lock`というlockファイルが生成されます。また、全てのパッケージを再インストールする場合は`uv sync --reinstall`で可能です。

### 仮想環境のアクティベート

以下のコマンドで仮想環境を有効化できます。

```bash
. .venv/bin/activate
```

Python3のパスとバージョンが仮想環境のものになっていることを確認します。

```bash
$ which python3
/Users/YoshitakaM/Desktop/my-project/.venv/bin/python3
$ python3 --version
Python 3.12.6
```

無効化する場合は以下を実行します。

```bash
deactivate
```

### Pythonのバージョン変更

`pin`コマンドでPythonのバージョンを変更することが可能です。`.python-version`ファイルも生成されます。

```bash
# 目的に応じて3.12の代わりに3.10, 3.11を指定する
uv python pin 3.12
```

また、プロジェクトを初期化する際に`uv init`の引数に`--python`または`-p`にバージョンを指定することでも可能です。

```bash
uv init my-project-3.10 -p 3.10
```

または、直接`pyproject.toml`の`requires-python = ">=3.10,<3.11"`のように書き換えて`uv sync`で更新することも可能です。

詳細な情報は公式の[uv - Python versions](https://docs.astral.sh/uv/concepts/python-versions/)を参照してください。

### helpコマンド

`--help`を使うとコマンドのヘルプメニューを表示できます。

```bash
uv --help
```

特定のコマンドのヘルプメニューを表示するには、次のようにします（例：`uv init`）。

```bash
uv init --help
```

`--help`フラグを使った場合、簡略化されたヘルプメニューを表示します。コマンドのより長いヘルプ メニューを表示するには、`uv help`を使用します。

```bash
uv help
```

特定のコマンドの長いヘルプメニューを表示するには、次のようにしますuv init。

```bash
uv help init
```

長いヘルプメニューを使用する場合、`uv`は`less`またはを使用して`more`出力を「ページング」しようとするため、一度にすべてが表示されることはありません。ページャーを終了するには、`q`を押します。

### バージョンの表示

uvは現在も精力的に開発を続けているため、ヘルプを見たい場合は使用している`uv`のバージョンを知ることが重要です。新しいバージョンでは問題がすでに解決されている場合もあります。

インストールされているバージョンを確認するには:

```bash
uv version
```

以下も有効です:

```bash
uv --version      # Same output as `uv version`
uv -V             # Will not include the build commit and date
uv pip --version  # Can be used with a subcommand
```

### 依存するパッケージ（開発時を含む）の追加と削除

`uv add`をつけることで、依存パッケージの追加が可能です。

```bash
uv add numpy biopython matplotlib pandas
```

バージョンを指定することも可能です。

```bash
uv add "numpy==1.26.4"
```

既にPythonファイルの`requirements.txt`が存在する場合は`uv add -r`からインストールすることも可能です。

```bash
uv add -r requirements.txt
```

削除するときは`uv remove`です。

```bash
uv remove numpy biopython matplotlib pandas
```

`--dev`オプションをつけることで、開発用パッケージとして追加することも可能です。こちらはGitHubを使って仲間内で開発環境を統一するときに使います。こちらに追加したパッケージは、パッケージリリース時に一般ユーザーに対してはインストールされません。

```bash
uv add --dev pytest notebook ruff mypy
```

実行したら、**`uv sync`を実行して設定を反映させる必要があります**。これを忘れずに。

```bash
uv sync
```

依存パッケージを追加・削除すると、以下で紹介する`pyproject.toml`ファイルの`project.dependencies, tool.uv.dev-dependencies`の値が随時変化します。

```toml:pyproject.toml
[project]
name = "newcomer-practice"
version = "0.1.0"
...
...
dependencies = []

[tool.uv]
dev-dependencies = ["mypy", "notebook", "pandas", "pytest", "ruff", "pandas"]
```

### スクリプトの実行

uvを使用してスクリプトを実行すると、環境を手動で管理しなくてもスクリプトの依存関係が管理されます。

#### 依存関係のないスクリプトの実行

スクリプトにdependenciesがない場合（または標準ライブラリモジュールのみに依存している場合）は、`uv run`で実行できます。

```python:example.py
import os
print(os.path.expanduser("~"))
```

```bash
$ uv run example.py
/Users/YoshitakaM
```

スクリプトには引数を指定できます:

```python:example.py
import sys
print(" ".join(sys.argv[1:]))
```

```bash
$ uv run example.py test
test
$ uv run example.py hello world!
hello world!
```

さらに、スクリプトはstdinから直接読み取ることもできます。

```bash
$ echo 'print("hello world!")' | uv run -
hello world!
```

または、シェルがヒアドキュメントをサポートしている場合は、次のようにしても同じ結果が得られます。

```bash
uv run - <<EOF
print("hello world!")
EOF
```

`project.toml`を含むディレクトリで`uv run`を使用する場合、スクリプトを実行する前に現在のプロジェクトがインストールされることに注意してください。スクリプトがプロジェクトに依存しない場合、フラグ`--no-project`を使用してこれをスキップします。

```bash
# Note, it is important that the flag comes _before_ the script
uv run --no-project example.py
```

プロジェクトでの作業の詳細については、[uv project guide](https://docs.astral.sh/uv/guides/projects/)を参照してください。

#### 依存関係のあるスクリプトの実行

スクリプトが他のパッケージに依存する場合（※多くは依存します）、それらのパッケージがスクリプトが実行される環境にインストールされておく必要があります。uvは、手動で管理された依存関係を持つ長期の仮想環境を使用するのではなく、オンデマンドでこれらの環境を作成することを好みます。これには、スクリプトに必要な依存関係の明示的な宣言が必要です。通常、依存関係の宣言には[project](https://docs.astral.sh/uv/guides/projects/)または[inline metadata](https://docs.astral.sh/uv/guides/scripts/#declaring-script-dependencies)を使用することをお勧めしますが、uvは呼び出しごとに依存関係を要求することもサポートしています。

例として`rich`パッケージを使った以下のスクリプト

```python:example.py
import time
from rich.progress import track

for i in track(range(20), description="For example:"):
    time.sleep(0.05)
```

これは`--no-project`フラグを使って依存関係を指定しない場合は失敗します。

```bash
$ uv run --no-project example.py
# ModuleNotFoundError: No module named 'rich'
```

`--with`オプションを使うと、依存関係を要求できます。複数の依存がある場合は、`--with`を繰り返して指定します。

```bash
$ uv run --with rich example.py
# Success
```

特定のバージョンが必要な場合は、要求された依存関係に制約を追加することができます。

```bash
uv run --with "rich>=12.0.0,<13" example.py
```

`uv run`がプロジェクトで使用されている場合、これらの依存関係はプロジェクトの依存関係に加えて含まれることに注意してください。この動作を無効にするには、`--no-project`フラグを使用します。

### ツールを使う

多くのPythonパッケージはtoolとして使えるアプリケーションを提供しています。

#### ツールの実行

`uvx`コマンドを使ってインストールすることなくツールを呼び出すことができます。例えば`ruff`を実行する場合は以下のようにします。

```bash
uvx ruff
```

これは

```bash
uv tool run ruff
```

と同じです。`uvx`は`uv tool run`が便利に使えるようにしてあるエイリアスです。

引数はtoolの名前の後に続けて指定します。

```bash
$ uvx pycowsay hello from uv
  -------------
< hello from uv >
  -------------
   \   ^__^
    \  (oo)\_______
       (__)\       )\/\
           ||----w |
           ||     ||
```

`uvx`を使用する場合、toolは一時的に隔離された環境にインストールされます。

例えば、pytestやmypyを使用する場合など、プロジェクト内でツールを実行し、そのツールがプロジェクトをインストールする必要がある場合は、`uvx`の代わりに`uv run`を使用します。そうしないと、ツールはプロジェクトから隔離された仮想環境で実行されます。

プロジェクトがフラットな構造になっている場合、例えば、モジュール用に`src`ディレクトリを使う代わりとしての時などは、プロジェクト自体をインストールする必要はなく、`uvx`でも問題ありません。この場合、プロジェクトの依存関係にツールのバージョンを固定したい場合にのみ、`uv run`を使用するのが効果的です。

#### 異なるパッケージ名でのコマンド

`uvx ruff`を呼び出した時、uvは`ruff`コマンドを提供する`ruff`パッケージをインストールします。しかし、パッケージ名とコマンド名が異なる場合があります。例えば `httpie`が提供する`http`の場合などでは、`--from`オプションを使用すると、特定のパッケージからコマンドを呼び出すことができます。

```bash
uvx --from httpie http
```

`--from`はgitをソースにしている場合にも使えます。

```bash
uvx --from git+https://github.com/httpie/cli httpie
```

#### 特定のバージョンを指定する

特定のバージョンでツールを実行するには、`command@<version>`を使用します。

```bash
uvx ruff@0.3.0 check
```

ツールを最新バージョンで実行するには、`command@latest`を使います。

```bash
uvx ruff@latest check
```

上記のように、`--from`オプションを使用してパッケージのバージョンを指定することもできます：

```bash
uvx --from 'ruff==0.3.0' ruff check
```

または、バージョン範囲を制限する場合は

```bash
uvx --from 'ruff>0.2.0,<0.3.0' ruff check
```

`@`構文はあるバージョンを正確に指定する場合のみ使用可能で、それ以外には使えないことに注意。

#### ツールのアップグレード

ツールをアップグレードするには、`uv tool upgrade`を使います：

```bash
uv tool upgrade ruff
```

ツールのアップグレードは、ツールのインストール時に指定されたバージョン制約に従います。例えば、`uv tool install ruff >=0.3,<0.4`をしたあとで`uv tool upgrade ruff`を実行すると、ruff は`>=0.3,<0.4`の範囲の最新バージョンにアップグレードされます。

バージョン制約を置き換えるには、`uv tool install`でツールを再インストールします。

```bash
uv tool install ruff>=0.4
```

すべてのツールをアップグレードするには

```bash
uv tool upgrade --all
```

でOKです。

### uvの仮想環境に入る

uvはvenvでプロジェクト直下の`.venv`ディレクトリに仮想環境を作成しています。仮想環境に入るには通常通り`. <myproject>/.venv/bin/activate`を実行します。

```bash
. .venv/bin/activate
```

仮想環境に正しく入った場合、`which python3`の結果がそのmyprojectディレクトリ以下の`.venv/bin/python3`になります。

```bash
$ which python3
/path/to/myproject/.venv/bin/python3
```

仮想環境を終了したい場合は、`deactivate`を実行します。

```bash
deactivate
```