0
0

Poetryを使ってPythonパッケージを作成してみた

Posted at

背景・目的

Poetryを最近触れる機会があったので、あらためて知識の整理と簡単な動作を確認してみます。

まとめ

下記に特徴をまとめます。

特徴 説明
Poetry Python で依存関係を管理およびパッケージ化するためのツール

プロジェクトが依存するライブラリを宣言でき、ライブラリが管理 (インストール/更新) される

Poetry は、繰り返しインストールを確実にするためのロックファイルを提供し、配布用にプロジェクトを構築できる
System requirements Python 3.8以上が必要
Project setup -
プロジェクトを作成する poetry new <プロジェクト名>により可能
Python Version 他のパッケージとは異なり、Poetry は Python インタープリターを自動的にインストールしない

パッケージ内の Python ファイルをスクリプトやアプリケーションのように実行したい場合は、それらを実行するための独自の Python インタープリターを使用する必要がある

pyproject.tomlに定義する
関連パッケージの依存関係の定義 下記の方法がある。
・tool.poetry.dependenciesに記載する
poetry add pendulumコマンドを実行する
poetry.lockファイル 依存関係が記録される

リポジトリで共有することでプロジェクト関係者で同一の環境を利用できる

概要

下記を基に整理します。

Introduction

Poetry is a tool for dependency management and packaging in Python. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you. Poetry offers a lockfile to ensure repeatable installs, and can build your project for distribution.

  • Poetry は、Python で依存関係を管理およびパッケージ化するためのツール
  • プロジェクトが依存するライブラリを宣言でき、ライブラリが管理 (インストール/更新) される
  • Poetry は、繰り返しインストールを確実にするためのロックファイルを提供し、配布用にプロジェクトを構築できる

System requirements

Poetry requires Python 3.8+. It is multi-platform and the goal is to make it work equally well on Linux, macOS and Windows.

  • Python 3.8以上が必要
  • Linux、macOS、Windows で動作

Basic usage

下記を基に整理します。

Project setup

poetry new により、プロジェクトを作成します。

  1. プロジェクトを作成します
    poetry new poetry-demo
    
  2. 実行すると下記の通りディレクトリが作成されます
    poetry-demo
    ├── pyproject.toml
    ├── README.md
    ├── poetry_demo
    │   └── __init__.py
    └── tests
        └── __init__.py
    

重要なのは、pyproject.tomlファイル。これを使用するとプロジェクトとその依存関係が調整されます。

[tool.poetry]
name = "poetry-demo"
version = "0.1.0"
description = ""
authors = ["Sébastien Eustace <sebastien@eustace.io>"]
readme = "README.md"
packages = [{include = "poetry_demo"}]

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


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

Poetry は、パッケージにプロジェクトのルートにある tool.poetry.name と同じ名前のパッケージが含まれていると想定します。そうでない場合は、tool.poetry.packages にパッケージとその場所を指定します。

Setting a Python Version

Unlike with other packages, Poetry will not automatically install a python interpreter for you. If you want to run Python files in your package like a script or application, you must bring your own python interpreter to run them.

  • 他のパッケージとは異なり、Poetry は Python インタープリターを自動的にインストールしない
  • パッケージ内の Python ファイルをスクリプトやアプリケーションのように実行したい場合は、それらを実行するための独自の Python インタープリターを使用する必要がある

Poetry will require you to explicitly specify what versions of Python you intend to support, and its universal locking will guarantee that your project is installable (and all dependencies claim support for) all supported Python versions. Again, it’s important to remember that – unlike other dependencies – setting a Python version is merely specifying which versions of Python you intend to support.

  • Poetry では、サポートする Python のバージョンを明示的に指定する必要がある
  • そのユニバーサル ロックにより、プロジェクトがインストール可能 (およびすべての依存関係がサポートを要求) であることが保証され、サポートされているすべての Python バージョンがサポートされる
  • 他の依存関係とは異なり、Python バージョンの設定は、サポートする Python のバージョンを指定するだけである
  • pyproject.tomlファイルの該当箇所を載せます
    [tool.poetry.dependencies]
    python = "^3.7.0"
    
    • 3.7.0 より新しいバージョンの Python 3 であれば、どれでも使用できる

When you run poetry install, you must have access to some version of a Python inrepreter that satisfies this constraint available on your system. Poetry will not install a Python interpreter for you. If you use a tool like pyenv, you can use the experimental configuration value virtualenvs.prefer-active-python.

  • poetry install を実行する場合、システムで使用できるこの制約を満たす Python インタプリタのバージョンにアクセスできる必要がある
  • Poetry は Python インタプリタをインストールしない
  • pyenv などのツールを使用する場合は、実験的な構成値 virtualenvs.prefer-active-python を使用できる

Initialising a pre-existing project

Instead of creating a new project, Poetry can be used to ‘initialise’ a pre-populated directory. To interactively create a pyproject.toml file in directory pre-existing-project:

  • 新しいプロジェクトを作成する代わりに、Poetry を使用して、事前に設定されたディレクトリを「初期化」できる

Operating modes

Poetry can be operated in two different modes. The default mode is the package mode, which is the right mode if you want to package your project into an sdist or a wheel and perhaps publish it to a package index. In this mode, some metadata such as name and version, which are required for packaging, are mandatory. Further, the project itself will be installed in editable mode when running poetry install.

If you want to use Poetry only for dependency management but not for packaging, you can use the non-package mode:

In this mode, metadata such as name and version are optional. Therefore, it is not possible to build a distribution or publish the project to a package index. Further, when running poetry install, Poetry does not try to install the project itself, but only its dependencies (same as poetry install --no-root).

  • 2 つの異なるモードで操作できる
    • デフォルトのモードはパッケージ モード
      • プロジェクトを sdist または Wheel にパッケージ化し、場合によってはパッケージ インデックスに公開する場合に使用する
      • パッケージ化に必要な名前やバージョンなどの一部のメタデータが必須
      • プロジェクト自体は、インストールを実行すると編集可能モードでインストールされる
    • 非パッケージモード
      • 名前やバージョンなどのメタデータはオプション
      • ディストリビューションをビルドしたり、プロジェクトをパッケージ インデックスに公開したりすることはできない
      • poetry install を実行すると、Poetry はプロジェクト自体をインストールせず、その依存関係のみをインストールする (poetry install --no-root と同じ)

Specifying dependencies

If you want to add dependencies to your project, you can specify them in the tool.poetry.dependencies section.

  • プロジェクトに依存関係を追加する場合は、tool.poetry.dependency セクションで依存関係を指定できる
[tool.poetry.dependencies]
pendulum = "^2.1"

As you can see, it takes a mapping of package names and version constraints.
Poetry uses this information to search for the right set of files in package “repositories” that you register in the tool.poetry.source section, or on PyPI by default.
Also, instead of modifying the pyproject.toml file by hand, you can use the add command.

  • パッケージ名とバージョン制約のマッピングが必要
  • この情報を使用して、tool.poetry.dependenciesセクション、デフォルトPyPIに登録したリポジトリ内の適切なファイルセットを検索する
  • pyproject.toml ファイルを手動で変更する代わりに、add コマンドを使用することも可能
poetry add pendulum

Using your virtual environment

By default, Poetry creates a virtual environment in {cache-dir}/virtualenvs. You can change the cache-dir value by editing the Poetry configuration. Additionally, you can use the virtualenvs.in-project configuration variable to create virtual environments within your project directory.
There are several ways to run commands within this virtual environment.

  • デフォルトでは、Poetry は {cache-dir}/virtualenvs に仮想環境を作成する

  • Poetry 構成を編集することで、cache-dir 値を変更できる

  • virtualenvs.in-project 構成変数を使用して、プロジェクト ディレクトリ内に仮想環境を作成することもできる

  • 仮想環境内でコマンドを実行する方法はいくつかある

Using poetry run

To run your script simply use poetry run python your_script.py. Likewise if you have command line tools such as pytest or black you can run them using poetry run pytest.

  • スクリプトを実行するには、poetry run python your_script.py を使用する
  • pytest や black などのコマンド ライン ツールをお持ちの場合は、poetry run pytest を使用して実行できる

Activating the virtual environment

The easiest way to activate the virtual environment is to create a nested shell with poetry shell.

To deactivate the virtual environment and exit this new shell type exit. To deactivate the virtual environment without leaving the shell use deactivate.

  • 仮想環境をアクティブにする最も簡単な方法は、poetry shellを使用してネストされたシェルを作成すること
  • 仮想環境を非アクティブにしてこの新しいシェルを終了するには、exitと入力する
  • シェルを終了せずに仮想環境を非アクティブ化するには、deactivate する

Version constraints

In our example, we are requesting the pendulum package with the version constraint ^2.1. This means any version greater or equal to 2.1.0 and less than 3.0.0 (>=2.1.0 <3.0.0).

  • 例) バージョン制約 ^2.1 を持つpendulumパッケージをリクエストする
    • 2.1.0 以上 3.0.0 未満 (>=2.1.0 <3.0.0) のバージョンを意味する

How does Poetry download the right files?

When you specify a dependency in pyproject.toml, Poetry first takes the name of the package that you have requested and searches for it in any repository you have registered using the repositories key. If you have not registered any extra repositories, or it does not find a package with that name in the repositories you have specified, it falls back to PyPI.

When Poetry finds the right package, it then attempts to find the best match for the version constraint you have specified.

  • Poertryが適切なファイルをダウンロードする方法
    1. pyproject.toml で依存関係を指定すると、Poetry はまず要求したパッケージの名前を取得する
    2. repositories キーを使用して登録したリポジトリ内でそのパッケージを検索する
      • 追加のリポジトリを登録していない場合、または指定したリポジトリ内にその名前のパッケージが見つからない場合は、PyPI にフォールバックする
      • Poetry は適切なパッケージを見つけると、指定したバージョン制約に最もよく一致するパッケージを見つけようとする

Installing dependencies

To install the defined dependencies for your project, just run the install command.

  • プロジェクトに定義された依存関係をインストールするには、install コマンドを実行するだけ
poetry install

このコマンドを実行すると、次の 2 つのいずれかが発生する可能性がある

Installing without poetry.lock

If you have never run the command before and there is also no poetry.lock file present, Poetry simply resolves all dependencies listed in your pyproject.toml file and downloads the latest version of their files.

When Poetry has finished installing, it writes all the packages and their exact versions that it downloaded to the poetry.lock file, locking the project to those specific versions. You should commit the poetry.lock file to your project repo so that all people working on the project are locked to the same versions of dependencies (more below).

  • これまでにコマンドを実行したことがなく、poetry.lock ファイルも存在しない場合、Poetry は単に pyproject.toml ファイルにリストされているすべての依存関係を解決し、そのファイルの最新バージョンをダウンロードする
  • Poetry のインストールが完了すると、ダウンロードしたすべてのパッケージとその正確なバージョンが Poetry.lock ファイルに書き込まれ、プロジェクトがそれらの特定のバージョンにロックされる
  • プロジェクトに取り組んでいるすべての人々が同じバージョンの依存関係にロックされるように、poetry.lock ファイルをプロジェクト リポジトリにコミットする必要がある

Installing with poetry.lock

This brings us to the second scenario. If there is already a poetry.lock file as well as a pyproject.toml file when you run poetry install, it means either you ran the install command before, or someone else on the project ran the install command and committed the poetry.lock file to the project (which is good).

  • poetryのインストールを実行するときに、pyproject.toml ファイルだけでなくpoetry.lock ファイルもすでに存在する場合、以前にインストール コマンドを実行したか、プロジェクトの他の誰かがインストール コマンドを実行して、poetry.lock ファイルをプロジェクトにコミットしたか を意味する

Either way, running install when a poetry.lock file is present resolves and installs all dependencies that you listed in pyproject.toml, but Poetry uses the exact versions listed in poetry.lock to ensure that the package versions are consistent for everyone working on your project. As a result you will have all dependencies requested by your pyproject.toml file, but they may not all be at the very latest available versions (some dependencies listed in the poetry.lock file may have released newer versions since the file was created). This is by design, it ensures that your project does not break because of unexpected changes in dependencies.

  • いずれの場合でも、poetry.lock ファイルが存在するときに install を実行すると、pyproject.toml にリストしたすべての依存関係が解決され、インストールされる
  • Poetry は、poetry.lock にリストされている正確なバージョンを使用して、プロジェクトに取り組むすべての利用者にとってパッケージのバージョンが一貫していることを保証する
  • その結果、pyproject.toml ファイルによって要求されたすべての依存関係が取得されるが、それらはすべて最新の利用可能なバージョンではない可能性がある (poetry.lock ファイルにリストされている一部の依存関係は、ファイルの作成後に新しいバージョンがリリースされている可能性がある)
  • 依存関係の予期せぬ変更によってプロジェクトが中断されないようにするための仕様

Committing your poetry.lock file to version control

As an application developer

Application developers commit poetry.lock to get more reproducible builds.

Committing this file to VC is important because it will cause anyone who sets up the project to use the exact same versions of the dependencies that you are using. Your CI server, production machines, other developers in your team, everything and everyone runs on the same dependencies, which mitigates the potential for bugs affecting only some parts of the deployments. Even if you develop alone, in six months when reinstalling the project you can feel confident the dependencies installed are still working even if your dependencies released many new versions since then. (See note below about using the update command.)

  • アプリケーション開発者は、より再現性の高いビルドを取得するために、poeter.lock をコミットする
  • このファイルを VC にコミットすると、プロジェクトをセットアップする人が、自分が使用しているのとまったく同じバージョンの依存関係を使用することになる。このファイルを VC にコミットすることは重要
  • これにより、CI サーバー、運用マシン、チーム内の他の開発者、すべてが同じ依存関係で実行されるため、デプロイメントの一部のみに影響を与えるバグの可能性が軽減される
  • 一人で開発している場合でも、6 か月後にプロジェクトを再インストールすると、依存関係がそれ以降に多くの新しいバージョンをリリースしたとしても、インストールされた依存関係がまだ動作していると確信できる
As a library developer

Library developers have more to consider. Your users are application developers, and your library will run in a Python environment you don’t control.

  • ライブラリ開発者はさらに考慮すべきことがある
  • ユーザーはアプリケーション開発者であり、ライブラリは制御できない Python 環境で実行される

The application ignores your library’s lock file. It can use whatever dependency version meets the constraints in your pyproject.toml. The application will probably use the latest compatible dependency version. If your library’s poetry.lock falls behind some new dependency version that breaks things for your users, you’re likely to be the last to find out about it.

  • アプリケーションはライブラリのロック ファイルを無視する
  • pyproject.toml の制約を満たす依存関係のバージョンであればどれでも使用できる
  • アプリケーションはおそらく、互換性のある最新の依存関係バージョンを使用することになる
  • あなたのライブラリのpoetry.lockが、ユーザーにとって問題となる新しい依存関係のバージョンよりも遅れている場合、それを知るのはおそらく最後になる

A simple way to avoid such a scenario is to omit the poetry.lock file. However, by doing so, you sacrifice reproducibility and performance to a certain extent. Without a lockfile, it can be difficult to find the reason for failing tests, because in addition to obvious code changes an unnoticed library update might be the culprit. Further, Poetry will have to lock before installing a dependency if poetry.lock has been omitted. Depending on the number of dependencies, locking may take a significant amount of time.

  • このようなシナリオを回避する簡単な方法は、poetry.lock ファイルを省略すること
  • ただし、これを行うと、再現性とパフォーマンスがある程度犠牲になる
  • ロックファイルがないと、明らかなコードの変更に加えて、気付かないライブラリの更新が原因である可能性があるため、テストが失敗する理由を見つけるのが困難になる可能性がある
  • さらに、poetry.lock が省略されている場合、依存関係をインストールする前に Poetry をロックする必要がある
  • 依存関係の数によっては、ロックにかなりの時間がかかる場合がある

If you do not want to give up the reproducibility and performance benefits, consider a regular refresh of poetry.lock to stay up-to-date and reduce the risk of sudden breakage for users.

  • 再現性とパフォーマンスの利点を放棄したくない場合は、poetry.lock を定期的に更新して最新の状態に保ち、ユーザーが突然破損するリスクを軽減することを検討する

Installing dependencies only

The current project is installed in editable mode by default.

If you want to install the dependencies only, run the install command with the --no-root flag:

  • 現在のプロジェクトは、デフォルトでは編集可能モードでインストールされる
  • 依存関係のみをインストールする場合は、 --no-root フラグを指定して install コマンドを実行する
poetry install --no-root

Updating dependencies to their latest versions

As mentioned above, the poetry.lock file prevents you from automatically getting the latest versions of your dependencies. To update to the latest versions, use the update command. This will fetch the latest matching versions (according to your pyproject.toml file) and update the lock file with the new versions. (This is equivalent to deleting the poetry.lock file and running install again.)

  • 上記にあげたとおり、poetry.lock ファイルにより、依存関係の最新バージョンを自動的に取得できなくなる
  • 最新バージョンに更新するには、update コマンドを使用する
  • これにより、一致する最新のバージョン (pyproject.toml ファイルに従って) がフェッチされ、ロック ファイルが新しいバージョンで更新される
    • これは、poetry.lock ファイルを削除して、インストールを再度実行することと同じ

実践

前提

今回、下記の環境で試しています。

  • MacOS
  • pyenv(任意)
  • VSCode(任意)

環境構築

事前準備

  1. Python 3.12をインストールします
    % pyenv install 3.12.5
    
  2. ダウンロードを確認します
    % pyenv versions
    
    * system (set by /Users/XXXX/.pyenv/version)
      3.11.5
      3.11.9
      3.11.9/envs/myenv
      3.12.5
      myenv --> /Users/XXXX/.pyenv/versions/3.11.9/envs/myenv
    %
    
  3. バージョンを切り替えます。切り替わりました
    % pyenv global 3.12.5
    % pyenv versions
      system
      3.11.5
      3.11.9
      3.11.9/envs/myenv
    * 3.12.5 (set by /Users/XXXX/.pyenv/version)
      myenv --> /Users/XXXX/.pyenv/versions/3.11.9/envs/myenv
    % 
    % python --version
    Python 3.12.5
    %
    
  4. 仮想環境を作成します
    % pyenv virtualenv 3.12.5 testenv
    
  5. 作成した仮想環境をアクティブ化します
     % pyenv activate testenv
    (testenv)  % 
    

Installation

下記を元に試します。

With the official installerを使用しています。この他のインストール方法を利用する場合は、ドキュメントをご確認ください。

Install Poetry

  1. インストーラーをダウンロードし、実行します

    % curl -sSL https://install.python-poetry.org | python3 -
    Retrieving Poetry metadata
    
    # Welcome to Poetry!
    
    This will download and install the latest version of Poetry,
    a dependency and package manager for Python.
    
    It will add the `poetry` command to Poetry's bin directory, located at:
    
    /Users/XXXX/.local/bin
    
    You can uninstall at any time by executing this script with the --uninstall option,
    and these changes will be reverted.
    
    Installing Poetry (1.8.3): Done
    
    Poetry (1.8.3) is installed now. Great!
    
    To get started you need Poetry's bin directory (/Users/XXXX/.local/bin) in your `PATH`
    environment variable.
    
    Add `export PATH="/Users/XXXX/.local/bin:$PATH"` to your shell configuration file.
    
    Alternatively, you can call Poetry explicitly with `/Users/XXXX/.local/bin/poetry`.
    
    You can test that everything is set up by executing:
    
    `poetry --version`
    
    % 
    

Add Poetry to your PATH

  1. パスを通すため、.zshrcに環境変数を設定します
    % tail -1 ~/.zshrc 
    export PATH="/Users/XXXX/.local/bin:$PATH"
    % 
    
  2. パスが通ったか確認します。(バージョンを確認します)
    % source ~/.zshrc 
    % poetry --version
    Poetry (version 1.8.3)
    %
    

1. Pythonパッケージの作成(Poetryを使用)

新しいプロジェクトの作成

  1. Poetryを使用して、新しいPythonプロジェクトを作成します
    % poetry new poetry_package     
    Created package poetry_package in poetry_package
    % 
    
  2. 下記のディレクトリ構成が自動的に作成されました
    % tree poetry_package      
    poetry_package
    ├── README.md
    ├── poetry_package
    │   └── __init__.py
    ├── pyproject.toml
    └── tests
        └── __init__.py
    
    3 directories, 4 files
    % 
    

コードの実装

  1. poetry_package/module.pyファイルを作成し、関数を追加します
    def greet(name):
        return f'Hello, {name}!'
    
  2. poetry_package/__init__.pyを修正し、モジュールをエクスポートします。これにより、モジュール名でインポートできます
    from .module import greet
    

依存関係の管理

  1. 依存関係を追加します(requestsライブラリを追加します)

    % poetry add requests
    Using version ^2.32.3 for requests
    
    Updating dependencies
    Resolving dependencies... (0.5s)
    
    Package operations: 5 installs, 0 updates, 0 removals
    
      - Installing certifi (2024.8.30)
      - Installing charset-normalizer (3.3.2)
      - Installing idna (3.10)
      - Installing urllib3 (2.2.3)
      - Installing requests (2.32.3)
    
    Writing lock file
    % 
    
  2. 上記により、requestsライブラリが追加されます。※ dependenciesに追加されています

    % cat pyproject.toml 
    [tool.poetry]
    name = "poetry-package"
    version = "0.1.0"
    description = ""
    authors = ["XXXXXXXX"]
    readme = "README.md"
    
    [tool.poetry.dependencies]
    python = "^3.12"
    requests = "^2.32.3"
    
    
    [build-system]
    requires = ["poetry-core"]
    build-backend = "poetry.core.masonry.api"
    % 
    
  3. また、poetry.loclファイルでバージョンが固定されます

    ・・・
    [[package]]
    name = "requests"
    version = "2.32.3"
    description = "Python HTTP for Humans."
    optional = false
    python-versions = ">=3.8"
    ・・・
    
  4. poetry buildを実行し、パッケージを生成します

    % poetry build
    Building poetry-package (0.1.0)
      - Building sdist
      - Built poetry_package-0.1.0.tar.gz
      - Building wheel
      - Built poetry_package-0.1.0-py3-none-any.whl
    %
    
  5. distディレクトリが作成され、その配下に、tar.gzと、.whlファイルが生成されました

    poetry_package % tree .
    .
    ├── README.md
    ├── __init__.py
    ├── dist
    │   ├── poetry_package-0.1.0-py3-none-any.whl
    │   └── poetry_package-0.1.0.tar.gz
    ├── module.py
    ├── poetry.lock
    ├── poetry_package
    │   └── __init__.py
    ├── pyproject.toml
    └── tests
        └── __init__.py
    
    4 directories, 9 files
    % 
    

2. GitHubリポジトリへの公開

  1. GitHubにサインインします
  2. リポジトリを作成します
  3. 作成したパッケージディレクトリをPushします
    git init
    git add .
    git commit -m "Initial commit"
    git remote add origin https://github.com/yourusername/my_package.git
    git push -u origin main
    

3. パッケージのインストール

  1. pipでGitHubリポジトリからインストールします
    % (testenv) pip install git+https://github.com/XXXXX/poetry_package.git
    ・・・・
    Successfully built poetry-package
    Installing collected packages: urllib3, idna, charset-normalizer, certifi, requests, poetry-package
    Successfully installed certifi-2024.8.30 charset-normalizer-3.3.2 idna-3.10 poetry-package-0.1.0 requests-2.32.3 urllib3-2.2.3
    % 
    

4. パッケージのインポート

  1. フォルダを作成します
    mkdir poetry_package_use
    
  2. main.pyファイルを作成し、下記のコードを書きます
    # main.py
    from poetry_package import greet
    
    print(greet("Taro"))
    
  3. 実行します
    (testenv) % python main.py 
    poetry_package has been imported
    Hello, Taro!
    (testenv) % 
    

考察

今回は、Poetryの基礎的な知識の整理と、実際にパッケージを作成しそれを利用するまで試してみました。
次回以降は、tomlファイルの各セクションの理解をしたいと思います。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0