7rikazhexde’s tech log

技術的な興味関心、備忘録、アウトプットなどを書いています。

既存プロジェクトをPoetryで管理する方法

以前、以下の記事でMacでPoetryをインストールする方法を紹介しました。

7rikazhexde-techlog.hatenablog.com

今回はGitHubで管理するプロジェクトに対してPoetryを適用した内容について実例を基に紹介します。

Poetryについては公式ドキュメントも合わせて確認ください。
python-poetry.org

対象プロジェクトについて

以下リポジトリで管理するプロジェクトを対象として以下の2つの方法について確認しました。

  1. 既存のプロジェクトにpoetry環境を構築するpoetry initの例
  2. poetry newでひな形から新規作成する例

github.com

既存のプロジェクトにpoetry環境を構築するpoetry initの例

これまで上記リポジトリでは以下のパッケージをrequirements.txtで管理していましたが、

  • PySimpleGUI
  • pandas
  • requests

Poetryを使用してプロジェクトの依存関係を管理するpyproject.tomlファイルを作成していきます。

既存のプロジェクトをgit cloneしてpoetry initを実行する

新規のプロジェクトを作るのではなく、既存のプロジェクトにpyproject.tomlファイルを作成するためにpoetry initコマンドを実行して初期化処理を実行します。

<参考>

% git clone https://github.com/7rikazhexde/dlSubscanStakingRewardsHistory.git

dlSubscanStakingRewardsHistory % poetry init
Configuration file exists at $HOME/Library/Application Support/pypoetry, reusing this directory.

Consider moving configuration to $HOME/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.

This command will guide you through creating your pyproject.toml config.

Package name [dlsubscanstakingrewardshistory]:  
Version [0.1.0]:  
Description []:  GUI application to save Reward&Slash data as csv file using PySimpleGUI and Subscan API
Author [[[user.name(git config)] <[user.email(git config)>, n to skip]:  
License []:  MIT
Compatible Python versions [^3.10]:  

main dependencies向けのパッケージ追加

次にプロジェクトで使用するパッケージを追加します。
main dependenciesで入力した情報は[tool.poetry.dependencies]の項目に追加されます。
パッケージを入力すると候補となるパッケージを検索してくれるので、[数字]の記載の番号を入力すると追加されます。

Would you like to define your main dependencies interactively? (yes/no) [yes] yes
You can specify a package in the following forms:
  - A single name (requests): this will search for matches on PyPI
  - A name and a constraint (requests@^2.23.0)
  - A git url (git+https://github.com/python-poetry/poetry.git)
  - A git url with a revision (git+https://github.com/python-poetry/poetry.git#develop)
  - A file path (../my-package/my-package.whl)
  - A directory (../my-package/)
  - A url (https://example.com/packages/my-package-0.1.0.tar.gz)

Package to add or search for (leave blank to skip): pysimplegui
Found 20 packages matching pysimplegui
Showing the first 10 matches

Enter package # to add, or the complete package name if it is not listed []:
 [ 0] PySimpleGUI
 [ 1] PySimpleGUI27
 [ 2] PySimpleGUI-Events
 [ 3] pysimplegui-exemaker
 [ 4] PySimpleGUI-chess
 [ 5] pysimplegui-howdoi
 [ 6] PySimpleGuy
 [ 7] psgresizer
 [ 8] psgdemos
 [ 9] psgcompiler
 [10] 
 > 0
Enter the version constraint to require (or leave blank to use the latest version): 
Using version ^4.60.4 for PySimpleGUI

Add a package (leave blank to skip): pandas
Found 20 packages matching pandas
Showing the first 10 matches

Enter package # to add, or the complete package name if it is not listed []:
 [ 0] pandas
 [ 1] pandas2
 [ 2] Pandas3
 [ 3] Pint-Pandas
 [ 4] pandas-ui
 [ 5] clustergrammer-pandas2
 [ 6] pandas-jsonlines
 [ 7] pandas-or
 [ 8] h3pandas
 [ 9] pandas-utility
 [10] 
 > 0
Enter the version constraint to require (or leave blank to use the latest version): 
Using version ^1.5.1 for pandas

Add a package (leave blank to skip): requests
Found 20 packages matching requests
Showing the first 10 matches

Enter package # to add, or the complete package name if it is not listed []:
 [ 0] requests
 [ 1] requests5
 [ 2] requests3
 [ 3] requests2
 [ 4] requests_spider
 [ 5] requests-kerberos
 [ 6] fed-requests
 [ 7] requests_gpgauthlib
 [ 8] jupyter-requests
 [ 9] ks33requests
 [10] 
 > 0
Enter the version constraint to require (or leave blank to use the latest version): 
Using version ^2.28.1 for requests

Add a package (leave blank to skip): 

development dependencies向けのパッケージ登録

本番動作には必要ないが、開発する時に必要なパッケージは
development dependencies で[tool.poetry.group.dev.dependencies]の項目に追加されます。
以下では単体テストを書くためのフレームワークであるpytestを追加します。

Would you like to define your development dependencies interactively? (yes/no) [yes] yes
Package to add or search for (leave blank to skip): pytest
Found 20 packages matching pytest
Showing the first 10 matches

Enter package # to add, or the complete package name if it is not listed []:
 [ 0] pytest
 [ 1] pytest123
 [ 2] 131228_pytest_1
 [ 3] pytest-pingguo-pytest-plugin
 [ 4] pytest-parallel
 [ 5] pytest-circleci
 [ 6] exgrex-pytest
 [ 7] pytest-grpc
 [ 8] pytest-pythonpath
 [ 9] pytest-vnc
 [10] 
 > 0
Enter the version constraint to require (or leave blank to use the latest version): 
Using version ^7.2.0 for pytest

Add a package (leave blank to skip): 

Generated file

[tool.poetry]
name = "dlsubscanstakingrewardshistory"
version = "0.1.0"
description = "GUI application to save Reward&Slash data as csv file using PySimpleGUI and Subscan API"
authors = ["[[user.name(git config)] <[user.email(git config)>"]
license = "MIT"
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.10"
PySimpleGUI = "^4.60.4"
pandas = "^1.5.1"
requests = "^2.28.1"

[tool.poetry.group.dev.dependencies]
pytest = "^7.2.0" # 追加

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


Do you confirm generation? (yes/no) [yes] yes

依存関係の確認

作成されたpyproject.tomlを見ると実際にプロジェクトの情報とパッケージの情報が書き込まれていることが確認できます。

dlSubscanStakingRewardsHistory % cat pyproject.toml 
[tool.poetry]
name = "dlsubscanstakingrewardshistory"
version = "0.1.0"
description = "GUI application to save Reward&Slash data as csv file using PySimpleGUI and Subscan API"
authors = ["[[user.name(git config)] <[user.email(git config)>"]
license = "MIT"
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.10"
PySimpleGUI = "^4.60.4"
pandas = "^1.5.1"
requests = "^2.28.1"

[tool.poetry.group.dev.dependencies]
pytest = "^7.2.0"

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

仮想環境のセットアップ

ここまででプロジェクトの準備ができたので仮想環境をセットアップします。

dlSubscanStakingRewardsHistory % poetry install
Configuration file exists at $HOME/Library/Application Support/pypoetry, reusing this directory.

Consider moving configuration to $HOME/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.
Creating virtualenv dlsubscanstakingrewardshistory in $HOME/develop/python/local_test1/dlSubscanStakingRewardsHistory/.venv
Updating dependencies
Resolving dependencies... (4.0s)

Writing lock file

Package operations: 19 installs, 0 updates, 0 removals

  • Installing pyparsing (3.0.9)
  • Installing six (1.16.0)
  • Installing attrs (22.1.0)
  • Installing certifi (2022.9.24)
  • Installing charset-normalizer (2.1.1)
  • Installing exceptiongroup (1.0.0)
  • Installing idna (3.4)
  • Installing iniconfig (1.1.1)
  • Installing numpy (1.23.4)
  • Installing packaging (21.3)
  • Installing pluggy (1.0.0)
  • Installing python-dateutil (2.8.2)
  • Installing pytz (2022.5)
  • Installing tomli (2.0.1)
  • Installing urllib3 (1.26.12)
  • Installing pandas (1.5.1)
  • Installing pysimplegui (4.60.4)
  • Installing pytest (7.2.0)
  • Installing requests (2.28.1)

ファイルツリーの確認

poetry installを実行したことで、Poetryは pyproject.tomlに並べられた全ての依存関係を解決し、それらのファイルの最新バージョンをダウンロードされます。
Poetryがインストールを完了すると、ダウンロードしたパッケージとその正確なバージョンを poetry.lockへ書き込み、その特定のバージョンでプロジェクトを固定します。(参考:installing-dependencies)

dlSubscanStakingRewardsHistory % tree
.
├── LICENSE
├── README.md
├── csv_sample
│   ├── 1REAJ1k691g5Eqqg9gL7vvZCBG7FCCZ8zgQkZWd4va5ESih_CryptactCustom_300_20220605.csv
│   └── 1REAJ1k691g5Eqqg9gL7vvZCBG7FCCZ8zgQkZWd4va5ESih_Reward&Slash_300_20220605.csv
├── png
│   ├── dlSubscanStakingRewardsHistory_CryptactCustom.png
│   ├── dlSubscanStakingRewardsHistory_Reward&Slash.png
│   ├── dlSubscanStakingRewardsHistory_setting.png
│   └── dlSubscanStakingRewardsHistory_startup.png
├── poetry.lock # 追加
├── pyproject.toml  #追加
├── requirements.txt
├── src
│   ├── __pycache__
│   │   ├── cryptact.cpython-310.pyc
│   │   ├── gui.cpython-310.pyc
│   │   └── subscan.cpython-310.pyc
│   ├── config.ini
│   ├── cryptact.py
│   ├── gui.py
│   ├── main.py
│   └── subscan.py
└── uml
    ├── classes_dlSubscanStakingRewardsHistory
    │   ├── classes_dlSubscanStakingRewardsHistory.png
    │   └── classes_dlSubscanStakingRewardsHistory.puml
    └── packages_dlSubscanStakingRewardsHistory
        ├── packages_dlSubscanStakingRewardsHistory.png
        └── packages_dlSubscanStakingRewardsHistory.puml

poetry runコマンドによる仮想環境の有効化とプログラムの実行

仮想環境でプログラムを実行するためにはpoetry runコマンドを使用します。
コマンドを実行したところ問題なく起動確認できました。

src % python --version
Python 3.10.7
[ユーザー名]@[コンピューター名] src % poetry run python main.py
Configuration file exists at $HOME/Library/Application Support/pypoetry, reusing this directory.

Consider moving configuration to $HOME/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.
Mac OS Version is 12.6 and patch enabled so applying the patch
Applyting Mac OS 12.3+ Alpha Channel fix.  Your default Alpha Channel is now 0.99

poetry run python main.py 実行結果

poetry shellコマンドによる仮想環境の有効化とプログラムの実行

poetry shellコマンドを使用することで仮想環境を有効化できます。
有効化した状態でプログラムを実行した場合でも問題なく起動確認できました。

  • 仮想環境の有効化: poetry shell
  • 仮想環境の無効化: exit
[ユーザー名]@[コンピューター名] src % python --version
Python 3.10.7
[ユーザー名]@[コンピューター名] src % poetry shell    
Configuration file exists at $HOME/Library/Application Support/pypoetry, reusing this directory.

Consider moving configuration to $HOME/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.
Spawning shell within $HOME/develop/python/local_test1/dlSubscanStakingRewardsHistory_poetry/.venv
Restored session: 2022年 10月29日 土曜日 19時39分38秒 JST
[ユーザー名]@[コンピューター名] src % . $HOME/develop/python/local_test1/dlSubscanStakingRewardsHistory_poetry/.venv/bin/activate
(dlsubscanstakingrewardshistory-py3.10) [ユーザー名]@[コンピューター名] src % python --version
Python 3.10.4
(dlsubscanstakingrewardshistory-py3.10) [ユーザー名]@[コンピューター名] src % python main.py
Mac OS Version is 12.6 and patch enabled so applying the patch
Applyting Mac OS 12.3+ Alpha Channel fix.  Your default Alpha Channel is now 0.99
(dlsubscanstakingrewardshistory-py3.10) [ユーザー名]@[コンピューター名] src % exit

Saving session...completed.
[ユーザー名]@[コンピューター名] src % python --version
Python 3.10.7

poetry newでひな形から新規作成する例

プロジェクトを新規作成する場合poetry new コマンドを実行します。
(参考:newコマンド)

poetry newの指定

  • プロジェクト名: dlSubscanStakingRewardsHistory
  • パッケージ内のディレクトリ名: app --name オプションを指定することでproject以下のプロジェクトフォルダ名を指定できます。
% mkdir poetry_project
% cd poetry_project
poetry_project % poetry new dlSubscanStakingRewardsHistory --name app

Configuration file exists at $HOME/Library/Application Support/pypoetry, reusing this directory.

Consider moving configuration to $HOME/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.
Created package app in dlSubscanStakingRewardsHistory

ファイルツリーを確認

% cd dlSubscanStakingRewardsHistory 
dlSubscanStakingRewardsHistory % tree
.
├── README.md
├── app #appとなっています。
│   └── __init__.py
├── pyproject.toml
└── tests
    └── __init__.py

tomlファイルの確認

dlSubscanStakingRewardsHistory % cat pyproject.toml
[tool.poetry]
name = "app" #appとなっています。
version = "0.1.0"
description = ""
authors = ["[[user.name(git config)] <[user.email(git config)>"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.10" #Version指定がなければ3.10より大きいバージョン指定で追加される


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

<補足>明示的にPythonのバージョンを指定した場合

コマンド実行した2022/08/21時点では3.10.6は非サポートのため3.10.4で仮想環境が作成されました。
また、poetry newでpyproject.tomlを作成した場合、poetry initを実行するとA pyproject.toml file with a poetry section already exists.とエラーになります。
この場合、pyproject.tomlを削除してから再度poetry initを実行すればREADME.md,app(※指定により異なります),testsを作成した状態でpyproject.tomlを作成することができます。
1.のケースでもappフォルダを作成後にpoetry initを実行する方法でも同じ構成にはすることはできます。

[ユーザー名]@[コンピューター名] poetry_test3 % poetry init --python 3.10.6 #明示的にバージョンを指定

This command will guid[user.email(git config)e you through creating your pyproject.toml config.

Package name [poetry_test3]:  
Version [0.1.0]:  
Description []:  
Author [[[user.name(git config)] <[user.email(git config)>, n to skip]:  
License []:  

Would you like to define your main dependencies interactively? (yes/no) [yes] no
Would you like to define your development dependencies interactively? (yes/no) [yes] no
Generated file

[tool.poetry]
name = "poetry_test3"
version = "0.1.0"
description = ""
authors = ["[[user.name(git config)] <[user.email(git config)>"]

[tool.poetry.dependencies]
python = "3.10.6"

[tool.poetry.dev-dependencies]

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


Do you confirm generation? (yes/no) [yes] yes
[ユーザー名]@[コンピューター名] poetry_test3 % ls
pyproject.toml
[ユーザー名]@[コンピューター名] poetry_test3 % poetry shell
The currently activated Python version 3.10.4 is not supported by the project (3.10.6).
Trying to find and use a compatible version. 
Using python3 (3.10.6)
Creating virtualenv poetry-test3 in $HOME/develop/python/poetry_test3/.venv
Spawning shell within $HOME/develop/python/poetry_test3/.venv
Restored session: 2022年 8月21日 日曜日 19時12分37秒 JST
[ユーザー名]@[コンピューター名] poetry_test3 % . $HOME/develop/python/poetry_test3/.venv/bin/activate
(.venv) [ユーザー名]@[コンピューター名] poetry_test3 % python -V
Python 3.10.4

仮想環境のセットアップ

dlSubscanStakingRewardsHistory % poetry install    
Configuration file exists at $HOME/Library/Application Support/pypoetry, reusing this directory.

Consider moving configuration to $HOME/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.
Creating virtualenv app in $HOME/develop/python/poetry_project/dlSubscanStakingRewardsHistory/.venv
Updating dependencies
Resolving dependencies... (0.1s)

Writing lock file

Installing the current project: app (0.1.0)

ファイルツリーを再度確認

poetry installを実行したことで、Poetryは pyproject.tomlに並べられた全ての依存関係を解決し、それらのファイルの最新バージョンをダウンロードされます。
Poetryがインストールを完了すると、ダウンロードしたパッケージとその正確なバージョンを poetry.lockへ書き込み、その特定のバージョンでプロジェクトを固定します。

dlSubscanStakingRewardsHistory % tree
.
├── README.md
├── app
│   └── __init__.py
├── poetry.lock     #lockファイルが追加された
├── pyproject.toml
└── tests
    └── __init__.py

lockファイル確認

dlSubscanStakingRewardsHistory % cat poetry.lock           
package = []

[metadata]
lock-version = "1.1"
python-versions = "^3.10"
content-hash = "53f2eabc9c26446fbcc00d348c47878e118afc2054778c3c803a0a8028af27d9"

パッケージ追加

dlSubscanStakingRewardsHistory % poetry add pysimplegui
Configuration file exists at $HOME/Library/Application Support/pypoetry, reusing this directory.

Consider moving configuration to $HOME/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.
Using version ^4.60.4 for pysimplegui

Updating dependencies
Resolving dependencies... (0.5s)

Writing lock file

Package operations: 1 install, 0 updates, 0 removals

  • Installing pysimplegui (4.60.4)
[ユーザー名]@[コンピューター名] dlSubscanStakingRewardsHistory % poetry add pandas     
Configuration file exists at $HOME/Library/Application Support/pypoetry, reusing this directory.

Consider moving configuration to $HOME/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.
Using version ^1.5.1 for pandas

Updating dependencies
Resolving dependencies... Downloading https://files.pythonhosted.org/packages/b5/d7/91fd8911d22e7fac794803095dd192bf1ebd70c7603272085230d915e738/pytz-2022.5-py2Resolving dependencies... Downloading https://files.pythonhosted.org/packages/64/8e/9929b64e146d240507edaac2185cd5516f00b133be5b39250d253be25a64/numpy-1.23.4.taResolving dependencies... Downloading https://files.pythonhosted.org/packages/64/8e/9929b64e146d240507edaac2185cd5516f00b133be5b39250d253be25a64/numpy-1.23.4.taResolving dependencies... Downloading https://files.pythonhosted.org/packages/64/8e/9929b64e146d240507edaac2185cd5516f00b133be5b39250d253be25a64/numpy-1.23.4.taResolving dependencies... Downloading https://files.pythonhosted.org/packages/64/8e/9929b64e146d240507edaac2185cd5516f00b133be5b39250d253be25a64/numpy-1.23.4.taResolving dependencies... (21.5s)

Writing lock file

Package operations: 5 installs, 0 updates, 0 removals

  • Installing six (1.16.0)
  • Installing numpy (1.23.4)
  • Installing python-dateutil (2.8.2)
  • Installing pytz (2022.5)
  • Installing pandas (1.5.1)
[ユーザー名]@[コンピューター名] dlSubscanStakingRewardsHistory % poetry add requests
Configuration file exists at $HOME/Library/Application Support/pypoetry, reusing this directory.

Consider moving configuration to $HOME/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.
Using version ^2.28.1 for requests

Updating dependencies
Resolving dependencies... Downloading https://files.pythonhosted.org/packages/fc/34/3030de6f1370931b9dbb4dad48f6ab1015ab1d32447850b9fc94e60097be/idna-3.4-py3-noResolving dependencies... Downloading https://files.pythonhosted.org/packages/1d/38/fa96a426e0c0e68aabc68e896584b83ad1eec779265a028e156ce509630e/certifi-2022.9.Resolving dependencies... (0.6s)

Writing lock file

Package operations: 5 installs, 0 updates, 0 removals

  • Installing certifi (2022.9.24)
  • Installing charset-normalizer (2.1.1)
  • Installing idna (3.4)
  • Installing urllib3 (1.26.12)
  • Installing requests (2.28.1)

まとめ

実際のプロジェクトを使用してpoetry環境を構築する方法を紹介しました。

  1. 既存のプロジェクトにpoetry環境を構築するpoetry initの例
  2. poetry newでひな形から新規作成する例

紹介した内容は基本的な部分であり、使用していないオプション指定やパッケージの更新などはドキュメントを確認ください。

今後はdevelopment dependenciesやpoetry.lockファイルを活用して、
機能追加やテストコードなどを考慮したプロジェクト管理ができるようにしていきたいと考えています。

2023/03/05
静的解析ツールをpoetryコマンドに適用した記事について投稿しました。

7rikazhexde-techlog.hatenablog.com

参考記事

以下の記事を参考にさせていただきました。

Poetryをサクッと使い始めてみる - Qiita

Basic usage | Documentation | Poetry - Python dependency management and packaging made easy