Add preferred use of build for package CLI (#13109)

Build with `build` if available. Warn and fall back to previous
`setup.py`-based builds if `build` build fails.
This commit is contained in:
Adriane Boyd 2023-11-08 17:35:24 +01:00 committed by GitHub
parent 2b8da84717
commit 513bbd5fa3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 8 deletions

View File

@ -1,5 +1,7 @@
import os
import re import re
import shutil import shutil
import subprocess
import sys import sys
from collections import defaultdict from collections import defaultdict
from pathlib import Path from pathlib import Path
@ -11,6 +13,7 @@ from thinc.api import Config
from wasabi import MarkdownRenderer, Printer, get_raw_input from wasabi import MarkdownRenderer, Printer, get_raw_input
from .. import about, util from .. import about, util
from ..compat import importlib_metadata
from ..schemas import ModelMetaSchema, validate from ..schemas import ModelMetaSchema, validate
from ._util import SDIST_SUFFIX, WHEEL_SUFFIX, Arg, Opt, app, string_to_list from ._util import SDIST_SUFFIX, WHEEL_SUFFIX, Arg, Opt, app, string_to_list
@ -35,7 +38,7 @@ def package_cli(
specified output directory, and the data will be copied over. If 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, --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. 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". 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 If additional code files are provided (e.g. Python files containing custom
@ -78,9 +81,17 @@ def package(
input_path = util.ensure_path(input_dir) input_path = util.ensure_path(input_dir)
output_path = util.ensure_path(output_dir) output_path = util.ensure_path(output_dir)
meta_path = util.ensure_path(meta_path) meta_path = util.ensure_path(meta_path)
if create_wheel and not has_wheel(): if create_wheel and not has_wheel() and not has_build():
err = "Generating a binary .whl file requires wheel to be installed" err = (
msg.fail(err, "pip install wheel", exits=1) "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(): if not input_path or not input_path.exists():
msg.fail("Can't locate pipeline data", input_path, exits=1) msg.fail("Can't locate pipeline data", input_path, exits=1)
if not output_path or not output_path.exists(): if not output_path or not output_path.exists():
@ -184,12 +195,37 @@ def package(
msg.good(f"Successfully created package directory '{model_name_v}'", main_path) msg.good(f"Successfully created package directory '{model_name_v}'", main_path)
if create_sdist: if create_sdist:
with util.working_dir(main_path): with util.working_dir(main_path):
# 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) util.run_command([sys.executable, "setup.py", "sdist"], capture=False)
zip_file = main_path / "dist" / f"{model_name_v}{SDIST_SUFFIX}" zip_file = main_path / "dist" / f"{model_name_v}{SDIST_SUFFIX}"
msg.good(f"Successfully created zipped Python package", zip_file) msg.good(f"Successfully created zipped Python package", zip_file)
if create_wheel: if create_wheel:
with util.working_dir(main_path): 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_name_squashed = re.sub("_+", "_", model_name_v)
wheel = main_path / "dist" / f"{wheel_name_squashed}{WHEEL_SUFFIX}" wheel = main_path / "dist" / f"{wheel_name_squashed}{WHEEL_SUFFIX}"
msg.good(f"Successfully created binary wheel", wheel) msg.good(f"Successfully created binary wheel", wheel)
@ -209,6 +245,17 @@ def has_wheel() -> bool:
return False 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( def get_third_party_dependencies(
config: Config, exclude: List[str] = util.SimpleFrozenList() config: Config, exclude: List[str] = util.SimpleFrozenList()
) -> List[str]: ) -> List[str]:

View File

@ -405,7 +405,7 @@ available to spaCy, all you need to do is install the package in your
environment: environment:
```bash ```bash
$ python setup.py develop $ python -m pip install .
``` ```
spaCy is now able to create the pipeline component `"snek"` even though you spaCy is now able to create the pipeline component `"snek"` even though you
@ -673,7 +673,7 @@ $ python -m spacy package ./en_example_pipeline ./packages
``` ```
This command will create a pipeline package directory and will run 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`. `.tar.gz` archive of your package that can be installed using `pip install`.
Installing the binary wheel is usually more efficient. Installing the binary wheel is usually more efficient.