Skip to content

danijar/flexbuild

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PyPI

🧱 Flexbuild

Simple Python build backend for large codebases.

Add to your pyproject.toml:

[build-system]
requires = ["flexbuild"]
build-backend = "flexbuild"

Features

  • 🤸 Flexible source layouts: Place code directly alongside pyproject.toml or in a subfolder like src/module.
  • 🏷️ Virtual namespaces: Define namespace modules like org.department.package without nested folders.
  • 🏗️ Monorepo support: Handle hierarchies of hundreds of packages with minimal boilerplate.
  • 📝 Rich metadata: Entry points, optional dependencies, author and maintainer list, license, and more.
  • 🤝 Ecosystem integration: Integrates seamlessly with packaging tools like uv and pip.
  • 🐣 Hackable: Under 500 lines of easy-to-read Python code with extensive test coverage.

Options

[build-system]
requires = ["flexbuild"]
build-backend = "flexbuild"
module-folder = "."
include = [
    '*.py',
    'pyproject.toml',
    'README.md',
    'README.rst',
]
exclude = [
    'dist',
    'build',
    '__pycache__',
    '.*',
    '*/.*',
    '*.pyc',
]

Monorepos

Flexbuild supports large repositories that contain hundreds of packages with minimal boilerplate. For example, packages can be organized into a folder hierarchy:

repo
  org
    department1
      package1
        pypackage.toml  # project.name = "org.department1.package2"
        __init__.py     # import org.department1.package1
        README.md
        code.py
      package2
        pypackage.toml
        __init__.py
        ...
      package3
    department2
      package1
      package2
      package3

Optionally, create a file repo/pyroot.toml. This enables checks that package namespaces match the folder hierarchy. It also allows specifying [build-system] defaults that nested pyproject.toml files inherit.

Consider using this layout together with uv path dependencies. Unlike uv workspace dependencies, it allows teams to update their version locks independently, so they can move faster and more predictably.

Background

Expand the sections below to to learn details of how Flexbuild solves problems of other Python build backends.

Flexible source layouts

Many Python build backends require a separate module folder inside the package:

package
  pyproject.toml
  src
    module
      __init__.py

Flexbuild looks for the module code at build-system.module-folder = "." from pyproject.toml, which defaults to the package folder but can also be set to a nested folder like src/module.

Virtual namespaces

To define namespace packages that can be imported as import org.department1.package1, many Python build backends require creating nested folders inside the package:

package
  pyproject.toml  # project.name = "org-department1-package1"
  src
    org
      department1
        package1
          __init__.py

Flexbuild allows specifying namespace packages without the nested folders, simply by setting project.name = "org.department1.package1" in the pyproject.toml. This allows simpler folder structures, for example:

package
  pyproject.toml  # project.name = "org.department1.package1"
  __init__.py

Monorepos

To manage a repository with many namespace packages, most Python build backends would require duplicating the same nested folder structure inside of each package:

repo
  org-department1-package1
    pyproject.toml
    README.md
    src
      org
        department1
          package1
            __init__.py
            code.py
  org-department1-package2
    pyproject.toml
    README.md
    src
      org
        department1
          package2
            __init__.py
            code.py
  org-department1-package2
    pyproject.toml
    README.md
    src
      org
        department1
          package3
            __init__.py
            code.py
  org-department2-package1
    ...
  org-department2-package2
    ...
  org-department2-package3
    ...

Through virtual namespaces, Flexbuild allows using a directory structure for namespace packages that can still import each other as import org.department1.package1:

repo
  org-department1-package1
    pyproject.toml
    README.md
    __init__.py
    code.py
  org-department1-package2
    pyproject.toml
    README.md
    __init__.py
    code.py
  org-department1-package2
    pyproject.toml
    README.md
    __init__.py
    code.py
  org-department2-package1
    ...
  org-department2-package2
    ...
  org-department2-package3
    ...

Moreover, it allows placing the packages as leaves of a folder structure. Note that the pyproject.toml files are inside the leaf folders now. This enables organizing packages in a shared folder structure (instead of duplicating the folder structure inside of each package):

repo
  org
    department1
      package1
        pyproject.toml
        README.md
        __init__.py
        code.py
      package2
        pyproject.toml
        README.md
        __init__.py
        code.py
      package3
        pyproject.toml
        README.md
        __init__.py
        code.py
    ...

Questions

Please open a separate GitHub issue for each question.

About

Simple Python build backend for large codebases

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages