Basic workflow#

The editables project is designed to support build backends, allowing them to declare what they wish to expose as “editable”, and returning a list of support files that need to be included in the wheel generated by the build_editable backend hook. Note that the editables library does not build wheel files directly - it returns the content that needs to be added to the wheel, but it is the build backend’s responsibility to actually create the wheel from that data.

Create a project#

The first step is for the backend to create an “editable project”. The project name must follow the normal rules for Python project names from PEP 426.

project = EditableProject("myproject")

Specify what to expose#

Once the project has been created, the backend can specify which files should be exposed when the editable install is done. There are two mechanisms currently implemented for this.

Adding a directory to sys.path#

To add a particular directory (typically the project’s “src” directory) to sys.path at runtime, simply call the add_to_path method

project.add_to_path("src")

This will simply write the given directory into the .pth file added to the wheel. See the “Implementation Details” section for more information. Note that this method requires no runtime support.

Adding a directory as package content#

To expose a directory as a package on sys.path, call the add_to_subpackage method, giving the package name to use, and the path to the directory containing the contents of that package.

For example, if the directory src contains a package my_pkg, which you want to expose to the target interpreter as some.package.my_pkg, run the following:

project.add_to_subpackage("some.package", "src")

Note that everything in the source directory will be available under the given package name, and the source directory should not contain an __init__.py file (if it does, that file will simply be ignored).

Also, the target (some.package here) must not be an existing package that is already part of the editable wheel. This is because its __init__.py file will be overwritten by the one created by this method.

Mapping individual files/packages#

To expose a single .py file as a module, call the map method, giving the name by which the module can be imported, and the path to the implementation .py file. It is possible to give the module a name that is not the same as the implementation filename, although this is expected to be extremely uncommon.

project.map("module", "src/module.py")

To expose a directory with an __init__.py file as a package, the map method is used in precisely the same way, but with the directory name:

project.map("mypackage", "src/mypackage")

The directory must be a Python package - i.e., it must contain an __init__.py file, and the target package name must be a top-level name, not a dotted name.

Using the map method does require a runtime support module.

Build the wheel#

Files to add#

Once all of the content to expose is specified, the backend can start building the wheel. To determine what files to write to the wheel, the files method should be used. This returns a sequence of pairs, each of which specifies a filename, and the content to write to that file. Both the name and the content are strings, and so should be encoded appropriately (i.e., in UTF-8) when writing to the wheel.

for name, content in my_project.files():
    wheel.add_file(name, content)

Note that the files to be added must be included unchanged - it is not supported for the caller to modify the returned content. Also, it is the caller’s responsibility to ensure that none of the generated files clash with files that the caller is adding to the wheel as part of its own processes.

Runtime dependencies#

If the map method is used, the resulting wheel will require that the runtime support module is installed. To ensure that is the case, dependency metadata must be added to the wheel. The dependencies method provides the required metadata.

for dep in my_project.dependencies():
    wheel.metadata.dependencies.add(dep)

Note that if the backend only uses the add_to_path method, no runtime support is needed, so the dependencies method will return an empty list. For safety, and to protect against future changes, it should still be called, though.