mirror of
https://github.com/explosion/spaCy.git
synced 2025-01-12 10:16:27 +03:00
Use more sophisticated version parsing logic
This commit is contained in:
parent
bed62991ad
commit
e47e5a4b10
|
@ -5,7 +5,7 @@ import sys
|
||||||
from wasabi import msg
|
from wasabi import msg
|
||||||
|
|
||||||
from .. import about
|
from .. import about
|
||||||
from ..util import is_package
|
from ..util import is_package, get_base_version
|
||||||
|
|
||||||
|
|
||||||
def download(
|
def download(
|
||||||
|
@ -63,8 +63,7 @@ def get_json(url, desc):
|
||||||
|
|
||||||
|
|
||||||
def get_compatibility():
|
def get_compatibility():
|
||||||
version = about.__version__
|
version = get_base_version(about.__version__)
|
||||||
version = version.rsplit(".dev", 1)[0]
|
|
||||||
comp_table = get_json(about.__compatibility__, "compatibility table")
|
comp_table = get_json(about.__compatibility__, "compatibility table")
|
||||||
comp = comp_table["spacy"]
|
comp = comp_table["spacy"]
|
||||||
if version not in comp:
|
if version not in comp:
|
||||||
|
@ -73,7 +72,7 @@ def get_compatibility():
|
||||||
|
|
||||||
|
|
||||||
def get_version(model, comp):
|
def get_version(model, comp):
|
||||||
model = model.rsplit(".dev", 1)[0]
|
model = get_base_version(model)
|
||||||
if model not in comp:
|
if model not in comp:
|
||||||
msg.fail(
|
msg.fail(
|
||||||
f"No compatible model found for '{model}' (spaCy v{about.__version__})",
|
f"No compatible model found for '{model}' (spaCy v{about.__version__})",
|
||||||
|
|
|
@ -90,7 +90,7 @@ def generate_meta(model_path, existing_meta, msg):
|
||||||
("license", "License", meta.get("license", "MIT")),
|
("license", "License", meta.get("license", "MIT")),
|
||||||
]
|
]
|
||||||
nlp = util.load_model_from_path(Path(model_path))
|
nlp = util.load_model_from_path(Path(model_path))
|
||||||
meta["spacy_version"] = about.__version__
|
meta["spacy_version"] = util.get_model_version_range(about.__version__)
|
||||||
meta["pipeline"] = nlp.pipe_names
|
meta["pipeline"] = nlp.pipe_names
|
||||||
meta["vectors"] = {
|
meta["vectors"] = {
|
||||||
"width": nlp.vocab.vectors_length,
|
"width": nlp.vocab.vectors_length,
|
||||||
|
@ -138,7 +138,7 @@ def list_files(data_dir):
|
||||||
|
|
||||||
def list_requirements(meta):
|
def list_requirements(meta):
|
||||||
parent_package = meta.get('parent_package', 'spacy')
|
parent_package = meta.get('parent_package', 'spacy')
|
||||||
requirements = [parent_package + '>=' + meta['spacy_version']]
|
requirements = [parent_package + meta['spacy_version']]
|
||||||
if 'setup_requires' in meta:
|
if 'setup_requires' in meta:
|
||||||
requirements += meta['setup_requires']
|
requirements += meta['setup_requires']
|
||||||
if 'requirements' in meta:
|
if 'requirements' in meta:
|
||||||
|
|
|
@ -4,7 +4,7 @@ import requests
|
||||||
from wasabi import msg
|
from wasabi import msg
|
||||||
|
|
||||||
from .. import about
|
from .. import about
|
||||||
from ..util import get_package_version, get_installed_models, split_version
|
from ..util import get_package_version, get_installed_models, get_base_version
|
||||||
from ..util import get_package_path, get_model_meta, is_compatible_model
|
from ..util import get_package_path, get_model_meta, is_compatible_model
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ def validate():
|
||||||
with the installed models. Should be run after `pip install -U spacy`.
|
with the installed models. Should be run after `pip install -U spacy`.
|
||||||
"""
|
"""
|
||||||
model_pkgs, compat = get_model_pkgs()
|
model_pkgs, compat = get_model_pkgs()
|
||||||
spacy_version = about.__version__.rsplit(".dev", 1)[0]
|
spacy_version = get_base_version(about.__version__)
|
||||||
current_compat = compat.get(spacy_version, {})
|
current_compat = compat.get(spacy_version, {})
|
||||||
if not current_compat:
|
if not current_compat:
|
||||||
msg.warn(f"No compatible models found for v{spacy_version} of spaCy")
|
msg.warn(f"No compatible models found for v{spacy_version} of spaCy")
|
||||||
|
@ -78,13 +78,12 @@ def get_model_pkgs():
|
||||||
version = get_package_version(pkg_name)
|
version = get_package_version(pkg_name)
|
||||||
if package in compat:
|
if package in compat:
|
||||||
is_compat = version in compat[package]
|
is_compat = version in compat[package]
|
||||||
v_maj, v_min = split_version(about.__version__)
|
spacy_version = about.__version__
|
||||||
spacy_version = f"{v_maj}.{v_min}"
|
|
||||||
else:
|
else:
|
||||||
model_path = get_package_path(package)
|
model_path = get_package_path(package)
|
||||||
model_meta = get_model_meta(model_path)
|
model_meta = get_model_meta(model_path)
|
||||||
is_compat = is_compatible_model(model_meta)
|
|
||||||
spacy_version = model_meta.get("spacy_version", "n/a")
|
spacy_version = model_meta.get("spacy_version", "n/a")
|
||||||
|
is_compat = is_compatible_model(spacy_version)
|
||||||
pkgs[pkg_name] = {
|
pkgs[pkg_name] = {
|
||||||
"name": package,
|
"name": package,
|
||||||
"version": version,
|
"version": version,
|
||||||
|
|
|
@ -191,13 +191,14 @@ class Language(object):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def meta(self):
|
def meta(self):
|
||||||
|
spacy_version = util.get_model_version_range(about.__version__)
|
||||||
if self.vocab.lang:
|
if self.vocab.lang:
|
||||||
self._meta.setdefault("lang", self.vocab.lang)
|
self._meta.setdefault("lang", self.vocab.lang)
|
||||||
else:
|
else:
|
||||||
self._meta.setdefault("lang", self.lang)
|
self._meta.setdefault("lang", self.lang)
|
||||||
self._meta.setdefault("name", "model")
|
self._meta.setdefault("name", "model")
|
||||||
self._meta.setdefault("version", "0.0.0")
|
self._meta.setdefault("version", "0.0.0")
|
||||||
self._meta.setdefault("spacy_version", about.__version__)
|
self._meta.setdefault("spacy_version", spacy_version)
|
||||||
self._meta.setdefault("description", "")
|
self._meta.setdefault("description", "")
|
||||||
self._meta.setdefault("author", "")
|
self._meta.setdefault("author", "")
|
||||||
self._meta.setdefault("email", "")
|
self._meta.setdefault("email", "")
|
||||||
|
|
|
@ -95,7 +95,15 @@ def test_ascii_filenames():
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"version,compatible",
|
"version,compatible",
|
||||||
[(spacy_version, True), ("2.0.0", False), (">=1.2.3,<4.5.6", False)],
|
[
|
||||||
|
(spacy_version, True),
|
||||||
|
(f">={spacy_version}", True),
|
||||||
|
("2.0.0", False),
|
||||||
|
(">=2.0.0", True),
|
||||||
|
(">=1.0.0,<2.1.1", False),
|
||||||
|
(">=1.2.3,<4.5.6", True),
|
||||||
|
("n/a", None),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
def test_is_compatible_model(version, compatible):
|
def test_is_compatible_model(version, compatible):
|
||||||
assert util.is_compatible_model({"spacy_version": version}) is compatible
|
assert util.is_compatible_model(version) is compatible
|
||||||
|
|
|
@ -14,6 +14,8 @@ import srsly
|
||||||
import catalogue
|
import catalogue
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
|
from packaging.specifiers import SpecifierSet, InvalidSpecifier
|
||||||
|
from packaging.version import Version, InvalidVersion
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -236,42 +238,31 @@ def get_package_version(name):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def split_version(version):
|
def is_compatible_model(constraint):
|
||||||
"""RETURNS (tuple): Two integers, the major and minor spaCy version."""
|
version = Version(about.__version__)
|
||||||
pieces = version.split(".", 3)
|
if constraint[0].isdigit():
|
||||||
return int(pieces[0]), int(pieces[1])
|
# Handle cases where exact version is provided as constraint
|
||||||
|
constraint = f"=={constraint}"
|
||||||
|
try:
|
||||||
def is_compatible_model(meta):
|
spec = SpecifierSet(constraint)
|
||||||
"""Check if a model is compatible with the current version of spaCy, based
|
except InvalidSpecifier:
|
||||||
on its meta.json. We compare the version of spaCy the model was created with
|
|
||||||
with the current version. If the minor version is different, it's considered
|
|
||||||
incompatible.
|
|
||||||
|
|
||||||
meta (dict): The model's meta.
|
|
||||||
RETURNS (bool / None): Whether the model is compatible with the current
|
|
||||||
spaCy or None if we don't have enough info.
|
|
||||||
"""
|
|
||||||
cur_v = about.__version__
|
|
||||||
pkg_v = meta.get("spacy_version")
|
|
||||||
if not pkg_v or not isinstance(pkg_v, str):
|
|
||||||
return None
|
return None
|
||||||
# Handle spacy_version values like >=x,<y, just in case
|
# Allow prereleases and dev versions
|
||||||
pkg_v = re.sub(r"[^0-9.]", "", pkg_v.split(",")[0])
|
spec.prereleases = True
|
||||||
cur_major, cur_minor = split_version(cur_v)
|
return version in spec
|
||||||
pkg_major, pkg_minor = split_version(pkg_v)
|
|
||||||
if cur_major != pkg_major or cur_minor != pkg_minor:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def get_model_version_range(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
|
||||||
across minor or major versions.
|
across minor or major versions.
|
||||||
"""
|
"""
|
||||||
major, minor = split_version(version)
|
release = Version(spacy_version).release
|
||||||
return f">={version},<{major}.{minor + 1}.0"
|
return f">={spacy_version},<{release[0]}.{release[1] + 1}.0"
|
||||||
|
|
||||||
|
|
||||||
|
def get_base_version(version):
|
||||||
|
return Version(version).base_version
|
||||||
|
|
||||||
|
|
||||||
def load_config(path, create_objects=False):
|
def load_config(path, create_objects=False):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user