Skip to content

Commit

Permalink
Add preferred use of build for package CLI (#13109)
Browse files Browse the repository at this point in the history
Build with `build` if available. Warn and fall back to previous
`setup.py`-based builds if `build` build fails.
  • Loading branch information
adrianeboyd authored Nov 8, 2023
1 parent 2b8da84 commit 513bbd5
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 8 deletions.
59 changes: 53 additions & 6 deletions spacy/cli/package.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import os
import re
import shutil
import subprocess
import sys
from collections import defaultdict
from pathlib import Path
Expand All @@ -11,6 +13,7 @@
from wasabi import MarkdownRenderer, Printer, get_raw_input

from .. import about, util
from ..compat import importlib_metadata
from ..schemas import ModelMetaSchema, validate
from ._util import SDIST_SUFFIX, WHEEL_SUFFIX, Arg, Opt, app, string_to_list

Expand All @@ -35,7 +38,7 @@ def package_cli(
specified output directory, and the data will be copied over. If
--create-meta is set and a meta.json already exists in the output directory,
the existing values will be used as the defaults in the command-line prompt.
After packaging, "python setup.py sdist" is run in the package directory,
After packaging, "python -m build --sdist" is run in the package directory,
which will create a .tar.gz archive that can be installed via "pip install".
If additional code files are provided (e.g. Python files containing custom
Expand Down Expand Up @@ -78,9 +81,17 @@ def package(
input_path = util.ensure_path(input_dir)
output_path = util.ensure_path(output_dir)
meta_path = util.ensure_path(meta_path)
if create_wheel and not has_wheel():
err = "Generating a binary .whl file requires wheel to be installed"
msg.fail(err, "pip install wheel", exits=1)
if create_wheel and not has_wheel() and not has_build():
err = (
"Generating wheels requires 'build' or 'wheel' (deprecated) to be installed"
)
msg.fail(err, "pip install build", exits=1)
if not has_build():
msg.warn(
"Generating packages without the 'build' package is deprecated and "
"will not be supported in the future. To install 'build': pip "
"install build"
)
if not input_path or not input_path.exists():
msg.fail("Can't locate pipeline data", input_path, exits=1)
if not output_path or not output_path.exists():
Expand Down Expand Up @@ -184,12 +195,37 @@ def package(
msg.good(f"Successfully created package directory '{model_name_v}'", main_path)
if create_sdist:
with util.working_dir(main_path):
util.run_command([sys.executable, "setup.py", "sdist"], capture=False)
# run directly, since util.run_command is not designed to continue
# after a command fails
ret = subprocess.run(
[sys.executable, "-m", "build", ".", "--sdist"],
env=os.environ.copy(),
)
if ret.returncode != 0:
msg.warn(
"Creating sdist with 'python -m build' failed. Falling "
"back to deprecated use of 'python setup.py sdist'"
)
util.run_command([sys.executable, "setup.py", "sdist"], capture=False)
zip_file = main_path / "dist" / f"{model_name_v}{SDIST_SUFFIX}"
msg.good(f"Successfully created zipped Python package", zip_file)
if create_wheel:
with util.working_dir(main_path):
util.run_command([sys.executable, "setup.py", "bdist_wheel"], capture=False)
# run directly, since util.run_command is not designed to continue
# after a command fails
ret = subprocess.run(
[sys.executable, "-m", "build", ".", "--wheel"],
env=os.environ.copy(),
)
if ret.returncode != 0:
msg.warn(
"Creating wheel with 'python -m build' failed. Falling "
"back to deprecated use of 'wheel' with "
"'python setup.py bdist_wheel'"
)
util.run_command(
[sys.executable, "setup.py", "bdist_wheel"], capture=False
)
wheel_name_squashed = re.sub("_+", "_", model_name_v)
wheel = main_path / "dist" / f"{wheel_name_squashed}{WHEEL_SUFFIX}"
msg.good(f"Successfully created binary wheel", wheel)
Expand All @@ -209,6 +245,17 @@ def has_wheel() -> bool:
return False


def has_build() -> bool:
# it's very likely that there is a local directory named build/ (especially
# in an editable install), so an import check is not sufficient; instead
# check that there is a package version
try:
importlib_metadata.version("build")
return True
except importlib_metadata.PackageNotFoundError: # type: ignore[attr-defined]
return False


def get_third_party_dependencies(
config: Config, exclude: List[str] = util.SimpleFrozenList()
) -> List[str]:
Expand Down
4 changes: 2 additions & 2 deletions website/docs/usage/saving-loading.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ available to spaCy, all you need to do is install the package in your
environment:
```bash
$ python setup.py develop
$ python -m pip install .
```
spaCy is now able to create the pipeline component `"snek"` – even though you
Expand Down Expand Up @@ -673,7 +673,7 @@ $ python -m spacy package ./en_example_pipeline ./packages
```
This command will create a pipeline package directory and will run
`python setup.py sdist` in that directory to create a binary `.whl` file or
`python -m build` in that directory to create a binary `.whl` file or
`.tar.gz` archive of your package that can be installed using `pip install`.
Installing the binary wheel is usually more efficient.

Expand Down

0 comments on commit 513bbd5

Please sign in to comment.