rcmdnk's blog

入門 Python 3 第2版

uvでPythonのプロジェクトを管理する際に、 パッケージの依存関係でextrasなパッケージをoptional-dependenciesで指定することができます。

それらのパッケージはuv syncではインストールされないので、 uvの環境でインストールしたい場合は uv sync --extra <EXTRA>でインストールするか、 dependency-groupsで設定してインストールできるようにしておく必要があります。

ただdependency-groupsで指定する場合、 そのまま同じパッケージを追加するとバージョンなどを複数の箇所に書くことになり 管理が面倒になります。

そのような重複を避けて書く方法について。

optional-dependenciesでのextraパッケージの指定

pyproject.toml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[project]
name = "my-example-package"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
    "numpy>=2.3.3",
]

[project.optional-dependencies]
data = [
    "pandas>=2.3.2",
]


[dependency-groups]
dev = [
  "pytest >= 8.3.0",
]

こんな感じのpyproject.tomlがあったとします。

何もない状態から

1
2
3
$ uv add "numpy>=2.3.3"
$ uv add --optional data "pandas>=2.3.2"
$ uv add --dev "pytest"

のようにパッケージを加えた状態です。

このパッケージはpipなどでインストールする際に、my-example-packageとだけ指定すると numpyだけインストールされ、pandasはインストールされません。

my-example-package[data]と指定することで、pandasもインストールされます。

これらの場合はpytestはインストールされません。

一方、uv syncではpytestはインストールされますがpandasはインストールされません。 uv sync --extra data、もしくはuv sync --all-extrasとすることで、pandasもインストールされます。

Extraなパッケージは重いライブラリだったりで、 不要な時はインストールしないで済むようにするための仕組みです。

uv syncでextraパッケージをインストールする方法

一方、このパッケージを開発する際にはpandasも必要になることが多いので それも含めた仮想環境を作っておきたいことが多いです。 その場合に上記のようにオプション追加でインストールするのは面倒なので、

pyproject.toml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[project]
name = "my-example-package"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
    "numpy>=2.3.3",
]

[project.optional-dependencies]
data = [
    "pandas>=2.3.2",
]


[dependency-groups]
dev = [
  "pytest>=8.3.0",
  "pandas>=2.3.2",
]

のような感じでdevグループにpandasを追加しておけばuv syncでもインストールされます。

1
$ uv add --dev "pytest"

で追加することも出来ます。

または、pandasがインストールされてない環境も簡単にチェックしたい場合、

pyproject.toml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[project]
name = "my-example-package"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
    "numpy>=2.3.3",
]

[project.optional-dependencies]
data = [
    "pandas>=2.3.2",
]


[dependency-groups]
dev = [
  "pytest>=8.3.0",
]
others = [
  "pandas>=2.3.2",
]

[tool.uv]
default-groups = ["dev", "others"]

のように、別途othersグループを作ってそこにpandasを追加し、 tool.uvdefault-groupsに追加指定しておく方法もあります1

コマンドで追加する場合は

1
$ uv add --group others "pandas>=2.3.2"

でパッケージ追加出来ます。

too.uvの設定は手動で追加する必要があります。

こちらでもuv syncpandasがインストールされるようになりますし、 uv sync --no-group othersとすることで、pandasがインストールされてない環境を作ることが出来ます。

分かりやすいように名前を変えましたがgroupの方もdataとしても大丈夫です。(optional-dependenciesのextra名とは独立しています。)

重複無く書く方法

ただこの場合、pandas>=2.3.2が重複していて、特にバージョンを変えたい場合などに 2箇所を変えないといけないので面倒です。

そこで、これを以下のように書き直すことが出来ます。

pyproject.toml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[project]
name = "my-example-package"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
    "numpy>=2.3.3",
]

[project.optional-dependencies]
data = [
    "pandas>=2.3.2",
]


[dependency-groups]
dev = [
  "pytest>=8.3.0",
]
others = [
  "my-example-package[data]"
]

[tool.uv]
default-groups = ["dev", "others"]

othersのグループに、自分自身のmy-example-packagedataのextra付きで指定しています。

1
$ uv add --group others my-example-package[data]

のようにコマンドで追加することも出来ます 2

これで、uv syncpandasがインストールされるようになり、 また、pandasのバージョン指定はoptional-dependenciesの方で一箇所だけ書けば良くなります。

循環参照になってしまう感じのする書き方ですが、意図したとおりに動作しますし、 uvの開発者の方が紹介している方法になります。

Question: What’s the difference between optional-dependencies and dependency-groups in pyproject.toml? · Issue #9011 · astral-sh/uv

もしかすると今後のアップデートでまた違った書き方が出来るようになったり推奨されたりするかもしれませんが、 現状ではこの方法が一番便利な方法かな、と思ってます。

Sponsored Links
  1. default-groupsはデフォルトではdevのみが指定されている状態です。

  2. この場合、

    1
    2
    
    [tool.uv.sources]
    my-example-package = { workspace = true }
    

    が追加で加えられます。

    ただ、この場合は自分自身への参照なのでworkwpace = trueを指定しなくても同じで この部分があっても無くても動作は同じです。

Sponsored Links

« vim_ahkの設定画面をタブ化

}