python-polylith

repository·main·Indexed 19 days ago

https://github.com/davidvujic/python-polylith

A collection of tools and plugins to implement the Polylith Architecture in Python, enabling component-based development within a Monorepo. It provides tooling support including the polylith-cli and specialized build hooks and plugins for Poetry (poetry-polylith-plugin), Hatch (hatch-polylith-bricks), and PDM (pdm-polylith-bricks, pdm-polylith-workspace) to manage components, bases, and projects.

Tokens
13.3K
Snippets
58
Records
77
Agent score
68%

What's inside python-polylith

  1. What is Polylith Architecture in Python?

    main

    Polylith is a components-first software architecture designed to apply functional thinking at the system scale. It uses a Monorepo approach where code is organized into reusable 'bricks' (components and bases) that are separated from infrastructure and artifact building.

    Key benefits include:

    • Microservices and Apps: Easily share code between multiple services or applications within a single Monorepo.
    • Libraries: Support for building and packaging libraries for distribution (e.g., to PyPI).
    • Scalability: Helps build simple, maintainable, and testable backend systems by decoupling logic from deployment concerns.
  2. Why use pdm-polylith-workspace instead of project-dir

    main

    While PDM provides a project-dir configuration option to define a custom path to Python source code, it only supports a single directory.

    In a Polylith workspace, code is organized into multiple distinct directories—specifically bases and components. The pdm-polylith-workspace build hook is required to handle this multi-directory structure by injecting all necessary paths into the virtual environment.

  3. Use a custom top namespace to prevent library collisions

    main

    When building multiple libraries from the same monorepo, they may share the same top-level namespace, causing collisions if installed in the same virtual environment. You can use this plugin to prepend a custom top-level namespace to all imports via AST (Abstract Syntax Tree) rewriting during the build process.

    To enable this, add a top-namespace key to the [tool.polylith.build] section in pyproject.toml.

    Example Transformation: If you set top-namespace = "my_custom_namespace", an import like: from my_namespace.my_package import my_function

    will be rewritten to: from my_custom_namespace.my_namespace.my_package import my_function

    [tool.polylith.build]
    top-namespace = "my_custom_namespace"
  4. Choose a Polylith tooling integration

    main

    The python-polylith ecosystem provides several ways to integrate Polylith patterns depending on your preferred Package and Dependency Manager (PDM).

    Standalone CLI

    • polylith-cli: Provides tooling support for various managers including Hatch, PDM, Rye, Maturin, Pixi, and uv.

    Plugin and Build Hook Integrations

    • Poetry: Use the poetry-polylith-plugin to add Polylith support directly to Poetry.
    • Hatch: Use hatch-polylith-bricks (a Hatch Build Hook) to add build-specific support. This works with hatchling as the build backend and supports uv, Rye, Pixi, and Pantsbuild.
    • PDM:
      • pdm-polylith-bricks: Adds build-specific support for individual PDM projects.
      • pdm-polylith-workspace: Makes the virtual environment aware of the Polylith organization (the bases and components folders).
  5. Create Polylith components, bases, and projects

    main

    Once your workspace is initialized, use the poly CLI to scaffold the core building blocks of your Polylith architecture. Commands must be run through your specific package manager (e.g., hatch run, pdm run, rye run, or uv run).

    • Component: A unit of business logic.
    • Base: A unit of shared code (e.g., an endpoint or interface).
    • Project: A deployable unit that composes components and bases.

    Examples:

    # Using Hatch
    hatch run poly create component --name my_component
    hatch run poly create base --name my_example_endpoint
    hatch run poly create project --name my_example_project
    
    # Using PDM
    pdm run poly create component --name my_component
    pdm run poly create base --name my_example_endpoint
    pdm run poly create project --name my_example_project
    
    # Using Rye
    rye run poly create component --name my_component
    rye run poly create base --name my_example_endpoint
    rye run poly create project --name my_example_project
    
    # Using uv
    uv run poly create component --name my_component
    uv run poly create base --name my_example_endpoint
    uv run poly create project --name my_example_project
    hatch run poly create component --name my_component
    
    hatch run poly create base --name my_example_endpoint
    
    hatch run poly create project --name my_example_project
  6. Setup for uv users

    main

    To use Polylith with uv, initialize a repository, add polylith-cli as a development dependency, and sync the environment.

    Note: Since uv uses Hatch as its default build backend, you must also configure the dev-mode-dirs in pyproject.toml to make uv aware of the Polylith structure, then run uv sync and remove the default src directory.

    1. Initialize and add CLI:
    uv init -name my_repo
    cd my_repo
    uv add polylith-cli --dev
    uv sync
    1. Configure Hatch build settings in pyproject.toml:
    [tool.hatch.build]
    dev-mode-dirs = ["components", "bases", "development", "."]
    1. Sync and cleanup:
    uv sync
    rm -r src
    1. Create workspace:
    uv run poly create workspace --name my_namespace --theme loose
  7. Setup for Rye users

    main

    To use Polylith with Rye, initialize a repository, add polylith-cli as a development dependency, and sync the environment.

    Note: Since Rye uses Hatch as its default build backend, you must also configure the dev-mode-dirs in pyproject.toml to make Rye aware of the Polylith structure, then run rye sync and remove the default src directory.

    1. Initialize and add CLI:
    rye init my_repo
    cd my_repo
    rye add polylith-cli --dev
    rye sync
    1. Configure Hatch build settings in pyproject.toml:
    [tool.hatch.build]
    dev-mode-dirs = ["components", "bases", "development", "."]
    1. Sync and cleanup:
    rye sync
    rm -r src
    1. Create workspace:
    rye run poly create workspace --name my_namespace --theme loose
  8. Install pdm-polylith-bricks for PDM

    main

    To use the Polylith build hook with PDM, add pdm-polylith-bricks to your [build-system] requirements in pyproject.toml. This allows the build process to identify and include Polylith bricks in the resulting wheel and sdist by copying them into the temporary .pdm-build folder.

    [build-system]
    requires = ["pdm-backend", "pdm-polylith-bricks"]
    build-backend = "pdm.backend"
  9. Use a custom top namespace during PDM builds

    main

    To prevent namespace collisions when multiple libraries from the same monorepo are installed in the same virtual environment, you can use the top-namespace configuration. When this is set, the build hook uses AST (Abstract Syntax Tree) parsing to rewrite imports in your source code to include the custom namespace prefix.

    [tool.polylith.build]
    top-namespace = "my_custom_namespace"

    Example of import rewriting:

    Before:

    from my_namespace.my_package import my_function

    After:

    from my_custom_namespace.my_namespace.my_package import my_function

  10. Install the Poetry Polylith Plugin

    main

    To use Polylith commands within Poetry, you must have Poetry version 1.2 or later installed. The installation requires two plugins: the poetry-multiproject-plugin (to enable workspace support and relative package includes) and the poetry-polylith-plugin itself.

    Run the following commands to install them as Poetry self-plugins:

    # 1. Add the Multiproject plugin for workspace support
    poetry self add poetry-multiproject-plugin
    
    # 2. Add the Polylith plugin
    poetry self add poetry-polylith-plugin
  11. Setup for PDM users

    main

    To use Polylith with PDM, initialize a PDM project and add the pdm-polylith-workspace build hook to ensure the virtual environment includes paths to your Polylith bases and components. Add polylith-cli as a development dependency.

    1. Initialize project:
    git init
    pdm init -n --backend pdm-backend minimal
    1. Configure pyproject.toml build system:
    [build-system]
    requires = ["pdm-backend", "pdm-polylith-workspace"]
    build-backend = "pdm.backend"
    1. Add CLI and install:
    touch README.md
    pdm add -d polylith-cli
    pdm install
    1. Create workspace:
    pdm run poly create workspace --name my_namespace --theme loose
  12. Setup for Hatch users

    main

    To use Polylith with Hatch, initialize a git repository and a Hatch project, then configure pyproject.toml to include polylith-cli as a dependency and define the Polylith directory structure for Hatch's build system. Use hatch run poly to execute Polylith commands.

    1. Initialize project:
    git init
    hatch new --init
    1. Configure pyproject.toml:
    [tool.hatch.envs.default]
    dependencies = ["polylith-cli"]
    type = "virtual"
    path = ".venv"
    python = "3.12"  # your preferred version here
    
    [tool.hatch.build]
    dev-mode-dirs = ["components", "bases", "development", "."]
    1. Create workspace:
    hatch run poly create workspace --name my_namespace --theme loose