1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
# 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](https://peps.python.org/pep-0660/#build-editable).
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](https://peps.python.org/pep-0426/#name).
```python
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
```python
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:
```python
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.
```python
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:
```python
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.
```python
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.
```python
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.
|