aiexperiments-ai-duet/server/magenta/tools/pip/README.md
2016-11-17 07:33:16 +03:00

141 lines
4.6 KiB
Markdown

## Building a new pip package
### setup.py updates
First, update the `_VERSION` field in `setup.py` to a new version number.
Next, update the `REQUIRED_PACKAGES` list in the same file to ensure that all
of our dependencies are listed and that they match the versions of the packages
referenced in the Bazel `WORKSPACE` file. Also check that the correct version of
tensorflow is listed.
### Building the package
```
bazel build //magenta/tools/pip:build_pip_package
bazel-bin/magenta/tools/pip/build_pip_package /tmp/magenta_pkg
```
Before this next step, make sure your preferred virtualenv or conda environment
is activated.
```
pip install -U /tmp/magenta_pkg/magenta-N.N.N-py2-none-any.whl
```
Next, test that it worked:
```
$ python
>>> from magenta.music import midi_io
>>> midi_io.midi_file_to_sequence_proto('test.mid')
```
You should see the NoteSequence representation of the midi file.
### Upload the new version to pypi
```
twine upload /tmp/magenta_pkg/magenta-N.N.N-py2-none-any.whl
```
After this step, anyone should be able to `pip install magenta` and get the
latest version.
## Adding to the pip package
### Libraries
As a convention, libraries that we want to expose externally through the pip
package should be listed as dependencies in otherwise empty `py_library`
targets that share the same name as their directory. Those targets should then
be referenced as dependencies by the target for the directory above them, all
the way up to the root `//magenta` target. (Targets named the same as their
package are implicit; `//magenta` is short for `//magenta:magenta`.)
This allows us to list `//magenta` as the main `py_library` dependency for
building the pip package and distributes maintenance of public API dependencies
to each package.
For example, to expose `magenta.music.midi_io`, the `magenta/music/BUILD` file will
have a section that looks like this:
```
# The Magenta public API.
py_library(
name = "lib",
deps = [
":midi_io",
],
)
```
And the `magenta/BUILD` file will have a section that looks like this:
```
# The Magenta public API.
py_library(
name = "magenta",
visibility = ["//magenta:__subpackages__"],
deps = [
"//magenta/music",
],
)
```
Because we want `import magenta` to make all modules immediately available,
we also need to create a custom `__init__.py` in the magenta directory and
reference it in the `srcs` field for the `//magenta:magenta` target.
When you add a new module to be exported, you'll also need to add it to this
`__init__.py` file. There are instructions in that file for how to
automatically generate the list based on the python library dependencies.
Now the `//magenta/tools/pip:build_pip_package` target just needs to depend on
`//magenta`.
The `//magenta` dependency also provides an easy way to verify that the models
developed within the magenta repo use the same code that is available to
external developers. Rather than depend directly on library targets, models
should depend only on the `//magenta` target.
Libraries should continue to use dependencies like normal: one target for every
python file, and every `import` statement should have a corresponding
dependency. This ensures we avoid circular dependencies and also makes builds
faster for tests.
### Scripts
Our pip package also includes several executable scripts (e.g.,
`convert_midi_dir_to_note_sequences`). These are just python files that pip
create executable wrappers around and installs to the python binary path. After
installation, users will have the script installed in their path. To add a new
script to the distribution, follow these steps:
First, add the script as a data dependency to the
`//magenta/tools/pip:build_pip_package` target. You will likely also need to
modify the visibility of the script's target so the pip builder can see it by
adding this line to the script's target:
```
visibility = ["//magenta/tools/pip:__subpackages__"],
```
Next, modify `setup.py` so the script's python module is listed under
`CONSOLE_SCRIPTS`.
Finally, you will need to modify the script itself so that it can be invoked
either directly or by the pip-generated wrapper script. The pip wrapper will
look for a method called `console_entry_point` as defined in `setup.py`, but
running the script directly (e.g., after a bazel build'ing it) will just invoke
the `if __name__ == '__main__':` condition. Both of those need to trigger
`tf.app.run` to run the actual `main` function because `tf.app.run` takes care
of things like initializing flags. The easiest way to do this is by adding the
following snippet to the end of your script:
```python
def console_entry_point():
tf.app.run(main)
if __name__ == '__main__':
console_entry_point()
```