ホームページ >バックエンド開発 >Python チュートリアル >Poetry を使用して新しい Harlequin アダプターを構築する方法

Poetry を使用して新しい Harlequin アダプターを構築する方法

WBOY
WBOYオリジナル
2024-07-18 10:22:21336ブラウズ

How to build a new Harlequin adapter with Poetry

LETSQL のチュートリアル シリーズの最初の投稿へようこそ!

このブログ投稿では、データ パイプラインという通常のテーマから離れて、DataFusion を例として使用して、Poetry で Python パッケージを作成して公開する方法を示します。

導入

Harlequin は、SQL データベースに対する軽量かつ広範なサポートで知られる SQL データベース用の TUI クライアントです。これは、データ探索および分析ワークフローのための多用途ツールです。 Harlequin は、オートコンプリート、構文の強調表示、クエリ履歴などの機能を備えた対話型 SQL エディターを提供します。また、大規模な結果セットを表示できる結果ビューアもあります。ただし、Harlequin にはこれまで DataFusion アダプターがありませんでした。ありがたいことに、追加するのはとても簡単でした。

この投稿では、DataFusion 用の Harlequin アダプターを構築することで、これらの概念を示します。また、そのために、Poetry の重要な機能、プロジェクトのセットアップ、PyPI でパッケージを公開する手順についても説明します。

このガイドを最大限に活用するには、仮想環境、Python パッケージとモジュール、および pip についての基本を理解している必要があります。
私たちの目標は次のとおりです:

  • 詩とその利点を紹介します
  • Poetry を使用してプロジェクトをセットアップする
  • DataFusion 用の Harlequin アダプターを開発します
  • パッケージを準備して PyPI に公開します

最後までに、Poetry の実践的な経験と、最新の Python パッケージ管理についての理解が得られるでしょう。

この投稿で実装されたコードは GitHub で入手可能であり、PyPI でも入手できます。

ハーレクイン

Harlequin は、ターミナルで実行される SQL IDE です。従来のコマンドライン データベース ツールに代わる強力で機能豊富なツールを提供し、データ探索や分析のワークフローに多用途に使用できます。

ハーレクインについて知っておくべき重要な事柄:

  • Harlequin は複数のデータベース アダプターをサポートし、DuckDB、SQLite、PostgreSQL、MySQL などに接続します。
  • Harlequin は、オートコンプリート、構文の強調表示、クエリ履歴などの機能を備えた対話型 SQL エディターを提供します。また、大規模な結果セットを表示できる結果ビューアも備えています。
  • Harlequin は、従来のターミナルベースのデータベース ツールを、より強力でユーザーフレンドリーなインターフェイスに置き換えます。
  • Harlequin は、データベースへの汎用インターフェイスとしてアダプター プラグインを使用します。

データフュージョン

DataFusion は、Apache Arrow インメモリ形式を使用して、Rust で高品質のデータ中心システムを構築するための高速で拡張可能なクエリ エンジンです。

DataFusion は、SQL および Dataframe API、優れたパフォーマンス、CSV、Parquet、JSON、Avro の組み込みサポート、広範なカスタマイズ、優れたコミュニティを提供します。

独自の CLI が同梱されています。詳細については、こちらをご覧ください。

Poetry は、Python プロジェクトの依存関係の管理とパッケージ化を合理化し、開発をより決定的かつ効率的にする、最新の機能豊富なツールです。
ドキュメントより:

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

Harlequin 用の新しいアダプターの作成

Harlequin アダプターは、Harlequin がデータベース システムと連携できるようにする Python パッケージです。

アダプターは、harlequin.adapters グループ内のエントリー ポイントを宣言する Python パッケージです。このエントリ ポイントは、HarlequinAdapter 抽象基本クラスのサブクラスを参照する必要があります。
これにより、Harlequin はインストールされているアダプターを検出し、選択したアダプターを実行時にインスタンス化できるようになります

HarlequinAdapter クラスに加えて、パッケージは HarlequinConnection および HarlequinCursor の実装も提供する必要があります。より詳しい説明は、こちら
でご覧いただけます。 ガイド。

Harlequin アダプター テンプレート

Harlequin アダプターを開発するための最初のステップは、既存の harlequin-adapter-template から新しいリポジトリを生成することです

GitHub テンプレートは、新しいプロジェクトの開始点として機能するリポジトリです。新しいリポジトリにコピーされる事前構成されたファイル、構造、設定が提供されるため、フォークのオーバーヘッドなしでプロジェクトを迅速にセットアップできます。
この機能は、確立されたパターンに基づいて、一貫性があり、適切に構造化されたプロジェクトを作成するプロセスを合理化します。

harlequin-adapter-template には、必要なクラスを定義するための定型コードに加えて、poeter.lock ファイルと pyproject.toml ファイルが付属しています。

アダプターのコーディング

コーディングの詳細に入る前に、パッケージの配布に必要な必須ファイルについて調べてみましょう。

パッケージ構成

pyproject.toml ファイルは、公開およびその他のツール用に Python パッケージを構成するための標準になりました。 PEP 518 および PEP 621 で導入されたこの TOML 形式のファイルは、複数の構成ファイルを 1 つに統合します。依存関係管理をより堅牢かつ標準化することで、依存関係管理を強化します。

Poetry は、pyproject.toml を利用してプロジェクトの仮想環境を処理し、依存関係を解決し、パッケージを作成します。

テンプレートの pyproject.toml は次のとおりです:

[tool.poetry]
name = "harlequin-myadapter"
version = "0.1.0"
description = "A Harlequin adapter for 2da0dc96d989c23227dfa4db76fedb27."
authors = ["Ted Conbeer 6da378a5ba0e452039972dddc494b9b0"]
license = "MIT"
readme = "README.md"
packages = [
    { include = "harlequin_myadapter", from = "src" },
]

[tool.poetry.plugins."harlequin.adapter"]
my-adapter = "harlequin_myadapter:MyAdapter"

[tool.poetry.dependencies]
python = ">=3.8.1,f681e766a553307a093124d04136e013=4.6.0", python = "fc2f4b881ac07ba465dc9655697c018bこのセクションは自動的に更新されます。
  • [tool.poetry.dev-dependency] サブセクションでは、テスト フレームワークやリンターなどの開発専用の依存関係を宣言します。

  • [build-system] セクションは、ビルド関連のデータを保存するために使用されます。この場合、ビルドバックエンドを「poetry.core.masonry.api」として指定します。狭義には、
    の中核となる責任 build-backend は、wheels と sdist をビルドすることです。

  • リポジトリには、詩のインストールまたは詩の更新を実行することによって生成される詩固有のコンポーネントである詩.lock ファイルも含まれています。このロック ファイルは、プロジェクトのすべての依存関係とサブ依存関係の正確なバージョンを指定し、さまざまな環境間でインストールを再現できるようにします。

    poet.lock ファイルを手動で編集しないことが重要です。これは、不整合やインストールの問題を引き起こす可能性があるためです。代わりに、pyproject.toml ファイルを変更し、Poetry が Poetry lock を実行してロック ファイルを自動的に更新できるようにします。

    詩を手に入れる

    詩ごとのインストールに関する警告

    ::: {.warning}
    Poetry は、システムの他の部分から隔離するために、常に専用の仮想環境にインストールする必要があります。 Poetry が管理するプロジェクトの環境には決してインストールしないでください。
    :::

    ここでは、pipx install quote を実行して Poetry にアクセスできると仮定します

    仮想環境での開発

    ファイル構造が明確になったので、環境を設定して開発プロセスを開始しましょう。私たちのプロジェクトにはすでに pyproject.toml と Poetry.lock ファイルが含まれているため、Poetie シェル コマンドを使用して環境を開始できます。

    このコマンドは、現在の Poetry プロジェクトにリンクされた仮想環境をアクティブにし、後続のすべての操作がプロジェクトの依存関係コンテキスト内で行われるようにします。仮想環境が存在しない場合は、詩シェルが自動的に仮想環境を作成してアクティブ化します。

    poetry シェルは現在のシェルを検出し、仮想環境内で新しいインスタンスを起動します。 Poetry はデフォルトで仮想環境を一元化するため、このコマンドにより、アクティブ化スクリプトへの特定のパスを見つけたり呼び出したりする必要がなくなります。

    Poetry で現在どの Python 環境が使用されているかを確認するには、次のコマンドを使用できます。

    poetry env list --full-path
    

    これにより、プロジェクトに関連付けられたすべての仮想環境が表示され、現在アクティブな仮想環境が示されます。
    代わりに、現在の環境のみのフルパスを取得できます:

    poetry env info -p
    

    環境がアクティブになったら、poetry install を使用して必要な依存関係をインストールします。コマンドは次のように機能します

    1. poeter.lock ファイルが存在する場合、poetry のインストールは依存関係を動的に解決するのではなく、そのファイルで指定されている正確なバージョンを使用します。これにより、さまざまな環境間で一貫性のある反復可能なインストールが保証されます。 私。詩のインストールを実行しても進んでいないように見える場合は、インストールしているシェルでexport PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyringを実行する必要がある場合があります
    2. それ以外の場合は、現在のプロジェクトの pyproject.toml ファイルを読み取り、そこにリストされている依存関係を解決して、インストールします。
    3. poetry.lock ファイルが存在しない場合、poetry インストールは依存関係を解決した後にファイルを作成します。それ以外の場合は、既存のファイルが更新されます。

    環境セットアップを完了するには、datafusion ライブラリを依存関係に追加する必要があります。次のコマンドを実行します:

    poetry add datafusion
    

    このコマンドは、datafusion パッケージを使用して pyproject.toml ファイルを更新し、インストールします。バージョンを指定しない場合、Poetry は利用可能なパッケージ バージョンに基づいて適切なバージョンを自動的に選択します。

    Implementing the Interfaces

    To create a Harlequin Adapter, you need to implement three interfaces defined as abstract classes in the harlequin.adapter module.

    The first one is the HarlequinAdapter.

    #| eval: false
    #| code-fold: false
    #| code-summary: implementation of HarlequinAdapter
    
    class DataFusionAdapter(HarlequinAdapter):
        def __init__(self, conn_str: Sequence[str], **options: Any) -> None:
            self.conn_str = conn_str
            self.options = options
    
        def connect(self) -> DataFusionConnection:
            conn = DataFusionConnection(self.conn_str, self.options)
            return conn
    

    The second one is the HarlequinConnection, particularly the methods execute and get_catalog.

    #| eval: false
    #| code-fold: false
    #| code-summary: implementation of execution of HarlequinConnection
    
     def execute(self, query: str) -> HarlequinCursor | None:
         try:
             cur = self.conn.sql(query)  # type: ignore
             if str(cur.logical_plan()) == "EmptyRelation":
                 return None
         except Exception as e:
             raise HarlequinQueryError(
                 msg=str(e),
                 title="Harlequin encountered an error while executing your query.",
             ) from e
         else:
             if cur is not None:
                 return DataFusionCursor(cur)
             else:
                 return None
    

    For brevity, we've omitted the implementation of the get_catalog function. You can find the full code in the adapter.py file within our GitHub repository.

    Finally, a HarlequinCursor implementation must be provided as well:

    #| eval: false
    #| code-fold: false
    #| code-summary: implementation of HarlequinCursor
    
    class DataFusionCursor(HarlequinCursor):
        def __init__(self, *args: Any, **kwargs: Any) -> None:
            self.cur = args[0]
            self._limit: int | None = None
    
        def columns(self) -> list[tuple[str, str]]:
            return [
                (field.name, _mapping.get(field.type, "?")) for field in self.cur.schema()
            ]
    
        def set_limit(self, limit: int) -> DataFusionCursor:
            self._limit = limit
            return self
    
        def fetchall(self) -> AutoBackendType:
            try:
                if self._limit is None:
                    return self.cur.to_arrow_table()
                else:
                    return self.cur.limit(self._limit).to_arrow_table()
            except Exception as e:
                raise HarlequinQueryError(
                    msg=str(e),
                    title="Harlequin encountered an error while executing your query.",
                ) from e
    

    Making the plugin discoverable

    Your adapter must register an entry point in the harlequin.adapters group using the packaging software you use to build your project.
    If you use Poetry, you can define the entry point in your pyproject.toml file:

    [tool.poetry.plugins."harlequin.adapter"]
    datafusion = "harlequin_datafusion:DataFusionAdapter"
    

    An entry point is a mechanism for code to advertise components it provides to be discovered and used by other code.

    Notice that registering a plugin with Poetry is equivalent to the following pyproject.toml specification for entry points:

    [project.entry-points."harlequin.adapter"]
    datafusion = "harlequin_datafusion:DataFusionAdapter"
    

    Testing

    The template provides a set of pre-configured tests, some of which are applicable to DataFusion while others may not be relevant. One test that's pretty cool checks if the plugin can be discovered, which is crucial for ensuring proper integration:

    #| eval: false
    #| code-fold: false
    if sys.version_info f92766c91ae8e699e6db3bc44a8ef3ea None:
        PLUGIN_NAME = "datafusion"
        eps = entry_points(group="harlequin.adapter")
        assert eps[PLUGIN_NAME]
        adapter_cls = eps[PLUGIN_NAME].load()
        assert issubclass(adapter_cls, HarlequinAdapter)
        assert adapter_cls == DataFusionAdapter
    

    To make sure the tests are passing, run:

    poetry run pytest
    

    The run command executes the given command inside the project’s virtualenv.

    Building and Publishing to PyPI

    With the tests passing, we're nearly ready to publish our project. Let's enhance our pyproject.toml file to make our package more discoverable and appealing on PyPI. We'll add key metadata including:

    1. A link to the GitHub repository
    2. A path to the README file
    3. A list of relevant classifiers

    These additions will help potential users find and understand our package more easily.

    classifiers = [
        "Development Status :: 3 - Alpha",
        "Intended Audience :: Developers",
        "Topic :: Software Development :: User Interfaces",
        "Topic :: Database :: Database Engines/Servers",
        "License :: OSI Approved :: MIT License",
        "Programming Language :: Python :: Implementation :: CPython"
    ]
    readme = "README.md"
    repository = "https://github.com/mesejo/datafusion-adapter"
    

    For reference:

    • The complete list of classifiers is available on PyPI's website.
    • For a detailed guide on writing pyproject.toml, check out this resource.
    • The formal, technical specification for pyproject.toml can be found on packaging.python.org.

    Building

    We're now ready to build our library and verify its functionality by installing it in a clean virtual environment. Let's start with the build process:

    poetry build
    

    This command will create distribution packages (both source and wheel) in the dist directory.

    The wheel file should have a name like harlequin_datafusion-0.1.1-py3-none-any.whl. This follows the standard naming convention:

    • harlequin_datafusion is the package (or distribution) name
    • 0.1.1 is the version number
    • py3 indicates it's compatible with Python 3
    • none compatible with any CPU architecture
    • any with no ABI (pure Python)

    To test the installation, create a new directory called test_install. Then, set up a fresh virtual environment with the following command:

    python -m venv .venv
    

    To activate the virtual environment on MacOS or Linux:

    source .venv/bin/activate
    

    After running this command, you should see the name of your virtual environment (.venv) prepended to your command prompt, indicating that the virtual environment is now active.

    To install the wheel file we just built, use pip as follows:

    pip install /path/to/harlequin_datafusion-0.1.1-py3-none-any.whl
    

    Replace /path/to/harlequin_datafusion-0.1.1-py3-none-any.whl with the actual path to the wheel file you want to install.

    If everything works fined, you should see some dependencies installed, and you should be able to do:

    harlequin -a datafusion
    

    Congrats! You have built a Python library. Now it is time to share it with the world.

    Publishing to PyPI

    The best practice before publishing to PyPI is to actually publish to the Test Python Package Index (TestPyPI)

    To publish a package to TestPyPI using Poetry, follow these steps:

    1. Create an account at TestPyPI if you haven't already.

    2. Generate an API token on your TestPyPI account page.

    3. Register the TestPyPI repository with Poetry by running:

      poetry config repositories.test-pypi https://test.pypi.org/legacy/
      
    4. To publish your package, run:

      poetry publish -r testpypi --username __token__ --password <token>
      

    Replace d6fb5a6237ab04b68d3c67881a9080fa with the actual token value you generated in step 2. To verify the publishing process, use the following command:

    python -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple 232e112a1ffb9f21e3b1b7ffee4c43c2
    

    This command uses two key arguments:

    • --index-url: Directs pip to find your package on TestPyPI.
    • --extra-index-url: Allows pip to fetch any dependencies from the main PyPI repository.

    Replace 232e112a1ffb9f21e3b1b7ffee4c43c2 with your specific package name (e.g., harlequin-datafusion if following this post). For additional details, consult the information provided in this post.

    To publish to the actual Python Package Index (PyPI) instead:

    1. Create an account at https://pypi.org/ if you haven't already.

    2. Generate an API token on your PyPI account page.

    3. Run:

      poetry publish --username __token__ --password <token>
      

    The default repository is PyPI, so there's no need to specify it.

    Is worth noting that Poetry only supports the Legacy Upload API when publishing your project.

    Automated Publishing on GitHub release

    Manually publishing each time is repetitive and error-prone, so to fix this problem, let us create a GitHub Action to
    publish each time we create a release.

    Here are the key steps to publish a Python package to PyPI using GitHub Actions and Poetry:

    1. Set up PyPI authentication: You must provide your PyPI credentials (the API token) as GitHub secrets so the GitHub Actions workflow can access them. Name these secrets something like PYPI_TOKEN.

    2. Create a GitHub Actions workflow file: In your project's .github/workflows directory, create a new file like publish.yml with the following content:

       name: Build and publish python package
    
       on:
         release:
           types: [ published ]
    
       jobs:
         publish-package:
           runs-on: ubuntu-latest
           permissions:
             contents: write
           steps:
             - uses: actions/checkout@v3
             - uses: actions/setup-python@v4
               with:
                 python-version: '3.10'
    
             - name: Install Poetry
               uses: snok/install-poetry@v1
    
             - run: poetry config pypi-token.pypi "${{ secrets.PYPI_TOKEN }}"
    
             - name: Publish package
               run: poetry publish --build --username __token__
    

    The key is to leverage GitHub Actions to automate the publishing process and use Poetry to manage your package's dependencies and metadata.

    Conclusion

    Poetry is a user-friendly Python package management tool that simplifies project setup and publication. Its intuitive command-line interface streamlines environment management and dependency installation. It supports plugin development, integrates with other tools, and emphasizes testing for robust code. With straightforward commands for building and publishing packages, Poetry makes it easier for developers to share their work with the Python community.

    At LETSQL, we're committed to contributing to the developer community. We hope this blog post serves as a straightforward guide to developing and publishing Python packages, emphasizing best practices and providing valuable resources.
    To subscribe to our newsletter, visit letsql.com.

    Future Work

    As we continue to refine the adapter, we would like to provide better autocompletion and direct reading from files (parquet, csv) as in the DataFusion-cli. This requires a tighter integration with the Rust library without going through the Python bindings.

    Your thoughts and feedback are invaluable as we navigate this journey. Share your experiences, questions, or suggestions in the comments below or on our community forum. Let's redefine the boundaries of data science and machine learning integration.

    Acknowledgements

    Thanks to Dan Lovell and Hussain Sultan for the comments and the thorough review.

    以上がPoetry を使用して新しい Harlequin アダプターを構築する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。