mirror of https://github.com/explosion/spaCy.git
Add warning for loose version constraints (#5536)
* Add warning for loose version constraints * Update wording [ci skip] * Tweak error message Co-authored-by: Matthew Honnibal <honnibal+gh@gmail.com>
This commit is contained in:
parent
8411d4f4e6
commit
d93cbeb14f
|
@ -113,6 +113,12 @@ class Warnings(object):
|
||||||
"ignored during training.")
|
"ignored during training.")
|
||||||
|
|
||||||
# TODO: fix numbering after merging develop into master
|
# TODO: fix numbering after merging develop into master
|
||||||
|
W094 = ("Model '{model}' ({model_version}) specifies an under-constrained "
|
||||||
|
"spaCy version requirement: {version}. This can lead to compatibility "
|
||||||
|
"problems with older versions, or as new spaCy versions are "
|
||||||
|
"released, because the model may say it's compatible when it's "
|
||||||
|
'not. Consider changing the "spacy_version" in your meta.json to a '
|
||||||
|
"version range, with a lower and upper pin. For example: {example}")
|
||||||
W095 = ("Model '{model}' ({model_version}) requires spaCy {version} and is "
|
W095 = ("Model '{model}' ({model_version}) requires spaCy {version} and is "
|
||||||
"incompatible with the current version ({current}). This may lead "
|
"incompatible with the current version ({current}). This may lead "
|
||||||
"to unexpected results or runtime errors. To resolve this, "
|
"to unexpected results or runtime errors. To resolve this, "
|
||||||
|
|
|
@ -109,3 +109,21 @@ def test_ascii_filenames():
|
||||||
)
|
)
|
||||||
def test_is_compatible_version(version, constraint, compatible):
|
def test_is_compatible_version(version, constraint, compatible):
|
||||||
assert util.is_compatible_version(version, constraint) is compatible
|
assert util.is_compatible_version(version, constraint) is compatible
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"constraint,expected",
|
||||||
|
[
|
||||||
|
("3.0.0", False),
|
||||||
|
("==3.0.0", False),
|
||||||
|
(">=2.3.0", True),
|
||||||
|
(">2.0.0", True),
|
||||||
|
("<=2.0.0", True),
|
||||||
|
(">2.0.0,<3.0.0", False),
|
||||||
|
(">=2.0.0,<3.0.0", False),
|
||||||
|
("!=1.1,>=1.0,~=1.0", True),
|
||||||
|
("n/a", None),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_is_unconstrained_version(constraint, expected):
|
||||||
|
assert util.is_unconstrained_version(constraint) is expected
|
||||||
|
|
|
@ -264,6 +264,31 @@ def is_compatible_version(version, constraint, prereleases=True):
|
||||||
return version in spec
|
return version in spec
|
||||||
|
|
||||||
|
|
||||||
|
def is_unconstrained_version(constraint, prereleases=True):
|
||||||
|
# We have an exact version, this is the ultimate constrained version
|
||||||
|
if constraint[0].isdigit():
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
spec = SpecifierSet(constraint)
|
||||||
|
except InvalidSpecifier:
|
||||||
|
return None
|
||||||
|
spec.prereleases = prereleases
|
||||||
|
specs = [sp for sp in spec]
|
||||||
|
# We only have one version spec and it defines > or >=
|
||||||
|
if len(specs) == 1 and specs[0].operator in (">", ">="):
|
||||||
|
return True
|
||||||
|
# One specifier is exact version
|
||||||
|
if any(sp.operator in ("==") for sp in specs):
|
||||||
|
return False
|
||||||
|
has_upper = any(sp.operator in ("<", "<=") for sp in specs)
|
||||||
|
has_lower = any(sp.operator in (">", ">=") for sp in specs)
|
||||||
|
# We have a version spec that defines an upper and lower bound
|
||||||
|
if has_upper and has_lower:
|
||||||
|
return False
|
||||||
|
# Everything else, like only an upper version, only a lower version etc.
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def get_model_version_range(spacy_version):
|
def get_model_version_range(spacy_version):
|
||||||
"""Generate a version range like >=1.2.3,<1.3.0 based on a given spaCy
|
"""Generate a version range like >=1.2.3,<1.3.0 based on a given spaCy
|
||||||
version. Models are always compatible across patch versions but not
|
version. Models are always compatible across patch versions but not
|
||||||
|
@ -334,14 +359,21 @@ def get_model_meta(path):
|
||||||
raise ValueError(Errors.E054.format(setting=setting))
|
raise ValueError(Errors.E054.format(setting=setting))
|
||||||
if "spacy_version" in meta:
|
if "spacy_version" in meta:
|
||||||
if not is_compatible_version(about.__version__, meta["spacy_version"]):
|
if not is_compatible_version(about.__version__, meta["spacy_version"]):
|
||||||
warnings.warn(
|
warn_msg = Warnings.W095.format(
|
||||||
Warnings.W095.format(
|
|
||||||
model=f"{meta['lang']}_{meta['name']}",
|
model=f"{meta['lang']}_{meta['name']}",
|
||||||
model_version=meta["version"],
|
model_version=meta["version"],
|
||||||
version=meta["spacy_version"],
|
version=meta["spacy_version"],
|
||||||
current=about.__version__,
|
current=about.__version__,
|
||||||
)
|
)
|
||||||
|
warnings.warn(warn_msg)
|
||||||
|
if is_unconstrained_version(meta["spacy_version"]):
|
||||||
|
warn_msg = Warnings.W094.format(
|
||||||
|
model=f"{meta['lang']}_{meta['name']}",
|
||||||
|
model_version=meta["version"],
|
||||||
|
version=meta["spacy_version"],
|
||||||
|
example=get_model_version_range(about.__version__),
|
||||||
)
|
)
|
||||||
|
warnings.warn(warn_msg)
|
||||||
return meta
|
return meta
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue