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. The following mechanisms are 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.

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.

The map method does not support mapping implicit namespace packages (directories which do not contain an __init__.py file).

There are two different ways that the map method can be implemented at runtime. To choose which one to use, set the map_method attribute on your EditableProject instance. The two methods are import_hook (the default) and self_replace. For details on the differences between the two methods, see the “Implementation Details” section of the documentation.

Using the map method with the import_hook method requires 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 with the “import_hook” implementation, 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 when runtime support is not needed, the dependencies method will return an empty list. So it is safe (and recommended) to call it in all cases.