Poetry를 사용하여 새로운 Harlequin 어댑터를 구축하는 방법

WBOY
풀어 주다: 2024-07-18 10:22:21
원래의
240명이 탐색했습니다.

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에 대한 기본적인 이해가 있어야 합니다.
우리의 목표는 다음과 같습니다:

  • 시를 소개하고 그 장점을 소개
  • 시를 활용한 프로젝트 설정
  • 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에는 필수 클래스를 정의하기 위한 일부 상용구 코드 외에도 poem.lock 파일과 pyproject.toml 파일이 함께 제공됩니다.

어댑터 코딩

코딩의 구체적인 내용을 알아보기 전에 패키지 배포에 필요한 필수 파일을 살펴보겠습니다.

패키지 구성

pyproject.toml 파일은 이제 게시 및 기타 도구용 Python 패키지를 구성하기 위한 표준입니다. PEP 518 및 PEP 621에 도입된 이 TOML 형식 파일은 여러 구성 파일을 하나로 통합합니다. 더욱 강력하고 표준화되어 종속성 관리가 향상됩니다.

Poetry는 pyproject.toml을 활용하여 프로젝트의 가상 환경을 처리하고 종속성을 해결하며 패키지를 생성합니다.

템플릿의 pyproject.toml은 다음과 같습니다.

[tool.poetry]
name = "harlequin-myadapter"
version = "0.1.0"
description = "A Harlequin adapter for <my favorite database>."
authors = ["Ted Conbeer <tconbeer@users.noreply.github.com>"]
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,<4.0"
harlequin = "^1.7"

[tool.poetry.group.dev.dependencies]
ruff = "^0.1.6"
pytest = "^7.4.3"
mypy = "^1.7.0"
pre-commit = "^3.5.0"
importlib_metadata = { version = ">=4.6.0", python = "<3.10.0" }

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
로그인 후 복사

보시다시피:

  • pyproject.toml 파일의 [tool.poetry] 섹션에서는 이름, 버전, 설명, 작성자 등과 같은 Python 패키지의 메타데이터를 정의합니다.

  • [tool.poetry.dependent] 하위 섹션에서는 프로젝트에 필요한 런타임 종속성을 선언합니다. 실행 시 추가 <패키지> 이 섹션은 자동으로 업데이트됩니다.

  • [tool.poetry.dev-dependents] 하위 섹션에서는 테스트 프레임워크, 린터 등과 같은 개발 전용 종속성을 선언합니다.

  • [build-system] 섹션은 빌드 관련 데이터를 저장하는 데 사용됩니다. 이 경우 빌드 백엔드를 "poetry.core.masonry.api"로 지정합니다. 좁은 의미에서
    의 핵심 책임은 build-backend는 휠과 sdist를 빌드하는 것입니다.

  • 저장소에는 poem 설치 또는 시 업데이트를 실행하여 생성된 Poetry 관련 구성 요소인 poem.lock 파일도 포함되어 있습니다. 이 잠금 파일은 프로젝트의 모든 종속성과 하위 종속성의 정확한 버전을 지정하여 다양한 환경에서 재현 가능한 설치를 보장합니다.

    poetry.lock 파일을 수동으로 편집하지 않는 것이 중요합니다. 이렇게 하면 불일치와 설치 문제가 발생할 수 있습니다. 대신, pyproject.toml 파일을 변경하고 Poetry Lock을 실행하여 Poetry가 자동으로 잠금 파일을 업데이트하도록 허용하세요.

    시를 얻기

    Per Poetry의 설치 주의사항

    ::: {.경고}
    Poetry는 항상 전용 가상 환경에 설치하여 시스템의 나머지 부분과 격리되어야 합니다. 포에트리가 관리하는 프로젝트 환경에는 어떠한 경우에도 설치해서는 안 됩니다.
    :::

    여기서는 pipx install poem을 실행하여 Poetry에 액세스할 수 있다고 가정합니다

    가상 환경에서 개발

    파일 구조가 명확해졌으니 환경을 설정하여 개발 프로세스를 시작하겠습니다. 우리 프로젝트에는 이미 pyproject.toml 및 poem.lock 파일이 포함되어 있으므로 poem 셸 명령을 사용하여 환경을 시작할 수 있습니다.

    이 명령은 현재 Poetry 프로젝트에 연결된 가상 환경을 활성화하여 모든 후속 작업이 프로젝트의 종속성 컨텍스트 내에서 발생하도록 합니다. 가상 환경이 없으면 Poetry Shell이 ​​자동으로 가상 환경을 생성하고 활성화합니다.

    poetry shell은 현재 쉘을 감지하고 가상 환경 내에서 새 인스턴스를 시작합니다. Poetry는 기본적으로 가상 환경을 중앙 집중화하므로 이 명령을 사용하면 활성화 스크립트에 대한 특정 경로를 찾거나 불러올 필요가 없습니다.

    현재 Poetry와 함께 사용 중인 Python 환경을 확인하려면 다음 명령을 사용할 수 있습니다.

    poetry env list --full-path
    
    로그인 후 복사

    이렇게 하면 프로젝트와 관련된 모든 가상 환경이 표시되고 현재 활성화된 환경이 무엇인지 알 수 있습니다.
    대안으로, 현재 환경의 전체 경로만 얻을 수 있습니다:

    poetry env info -p
    
    로그인 후 복사

    환경이 활성화된 상태에서 poem install을 사용하여 필요한 종속성을 설치하세요. 명령은 다음과 같이 작동합니다

    1. poem.lock 파일이 있는 경우 poem 설치는 종속성을 동적으로 해결하는 대신 해당 파일에 지정된 정확한 버전을 사용합니다. 이를 통해 다양한 환경에서 일관되고 반복 가능한 설치가 보장됩니다. 나. Poetry install을 실행했지만 진행되지 않는 것 같으면 설치하려는 셸에서 내보내기 PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring을 실행해야 할 수도 있습니다
    2. 그렇지 않으면 현재 프로젝트의 pyproject.toml 파일을 읽고 거기에 나열된 종속성을 해결한 후 설치합니다.
    3. poet.lock 파일이 없으면 poem 설치는 종속성을 해결한 후 파일을 생성하고, 그렇지 않으면 기존 파일을 업데이트합니다.

    환경 설정을 완료하려면 종속 항목에 datafusion 라이브러리를 추가해야 합니다. 다음 명령을 실행합니다:

    poetry add datafusion
    
    로그인 후 복사

    이 명령은 pyproject.toml 파일을 datafusion 패키지로 업데이트하고 설치합니다. 버전을 지정하지 않으면 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 < (3, 10):
        from importlib_metadata import entry_points
    else:
        from importlib.metadata import entry_points
    
    
    def test_plugin_discovery() -> 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 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 <package-name>
    
    로그인 후 복사

    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 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!