mirror of
				https://github.com/explosion/spaCy.git
				synced 2025-10-30 23:47:31 +03:00 
			
		
		
		
	Use minor version for compatibility check (#8403)
* Use minor version for compatibility check * Use minor version of compatibility table * Soften warning message about incompatible models * Add test for presence of current version in compatibility table * Add test for download compatibility table * Use minor version of lower pin in error message if possible * Fall back to spacy_git_version if available * Fix unknown version string
This commit is contained in:
		
							parent
							
								
									ec71a6b572
								
							
						
					
					
						commit
						9fde258053
					
				|  | @ -6,7 +6,7 @@ import typer | |||
| 
 | ||||
| from ._util import app, Arg, Opt, WHEEL_SUFFIX, SDIST_SUFFIX | ||||
| from .. import about | ||||
| from ..util import is_package, get_base_version, run_command | ||||
| from ..util import is_package, get_minor_version, run_command | ||||
| from ..errors import OLD_MODEL_SHORTCUTS | ||||
| 
 | ||||
| 
 | ||||
|  | @ -74,7 +74,7 @@ def download(model: str, direct: bool = False, sdist: bool = False, *pip_args) - | |||
| 
 | ||||
| 
 | ||||
| def get_compatibility() -> dict: | ||||
|     version = get_base_version(about.__version__) | ||||
|     version = get_minor_version(about.__version__) | ||||
|     r = requests.get(about.__compatibility__) | ||||
|     if r.status_code != 200: | ||||
|         msg.fail( | ||||
|  |  | |||
|  | @ -3,10 +3,12 @@ from pathlib import Path | |||
| import sys | ||||
| import requests | ||||
| from wasabi import msg, Printer | ||||
| import warnings | ||||
| 
 | ||||
| from ..errors import Warnings | ||||
| from ._util import app | ||||
| from .. import about | ||||
| from ..util import get_package_version, get_installed_models, get_base_version | ||||
| from ..util import get_package_version, get_installed_models, get_minor_version | ||||
| from ..util import get_package_path, get_model_meta, is_compatible_version | ||||
| 
 | ||||
| 
 | ||||
|  | @ -24,7 +26,7 @@ def validate_cli(): | |||
| 
 | ||||
| def validate() -> None: | ||||
|     model_pkgs, compat = get_model_pkgs() | ||||
|     spacy_version = get_base_version(about.__version__) | ||||
|     spacy_version = get_minor_version(about.__version__) | ||||
|     current_compat = compat.get(spacy_version, {}) | ||||
|     if not current_compat: | ||||
|         msg.warn(f"No compatible packages found for v{spacy_version} of spaCy") | ||||
|  | @ -44,8 +46,8 @@ def validate() -> None: | |||
|                 comp = msg.text("", color="green", icon="good", no_print=True) | ||||
|                 version = msg.text(data["version"], color="green", no_print=True) | ||||
|             else: | ||||
|                 version = msg.text(data["version"], color="red", no_print=True) | ||||
|                 comp = f"--> {compat.get(data['name'], ['n/a'])[0]}" | ||||
|                 version = msg.text(data["version"], color="yellow", no_print=True) | ||||
|                 comp = f"--> {current_compat.get(data['name'], ['n/a'])[0]}" | ||||
|             rows.append((data["name"], data["spacy"], version, comp)) | ||||
|         msg.table(rows, header=header) | ||||
|     else: | ||||
|  | @ -78,7 +80,9 @@ def get_model_pkgs(silent: bool = False) -> Tuple[dict, dict]: | |||
|     msg.good("Loaded compatibility table") | ||||
|     compat = r.json()["spacy"] | ||||
|     all_models = set() | ||||
|     installed_models = get_installed_models() | ||||
|     with warnings.catch_warnings(): | ||||
|         warnings.filterwarnings("ignore", message="\\[W09[45]") | ||||
|         installed_models = get_installed_models() | ||||
|     for spacy_v, models in dict(compat).items(): | ||||
|         all_models.update(models.keys()) | ||||
|         for model, model_vs in models.items(): | ||||
|  | @ -92,7 +96,9 @@ def get_model_pkgs(silent: bool = False) -> Tuple[dict, dict]: | |||
|             spacy_version = about.__version__ | ||||
|         else: | ||||
|             model_path = get_package_path(package) | ||||
|             model_meta = get_model_meta(model_path) | ||||
|             with warnings.catch_warnings(): | ||||
|                 warnings.filterwarnings("ignore", message="\\[W09[45]") | ||||
|                 model_meta = get_model_meta(model_path) | ||||
|             spacy_version = model_meta.get("spacy_version", "n/a") | ||||
|             is_compat = is_compatible_version(about.__version__, spacy_version) | ||||
|         pkgs[pkg_name] = { | ||||
|  |  | |||
|  | @ -150,12 +150,12 @@ class Warnings: | |||
|             "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 " | ||||
|             "incompatible with the current version ({current}). This may lead " | ||||
|             "to unexpected results or runtime errors. To resolve this, " | ||||
|             "download a newer compatible model or retrain your custom model " | ||||
|             "with the current spaCy version. For more details and available " | ||||
|             "updates, run: python -m spacy validate") | ||||
|     W095 = ("Model '{model}' ({model_version}) was trained with spaCy " | ||||
|             "{version} and may not be 100% compatible with the current version " | ||||
|             "({current}). If you see errors or degraded performance, download " | ||||
|             "a newer compatible model or retrain your custom model with the " | ||||
|             "current spaCy version. For more details and available updates, " | ||||
|             "run: python -m spacy validate") | ||||
|     W096 = ("The method `nlp.disable_pipes` is now deprecated - use " | ||||
|             "`nlp.select_pipes` instead.") | ||||
|     W100 = ("Skipping unsupported morphological feature(s): '{feature}'. " | ||||
|  |  | |||
|  | @ -10,6 +10,10 @@ from spacy.cli.init_config import init_config, RECOMMENDATIONS | |||
| from spacy.cli._util import validate_project_commands, parse_config_overrides | ||||
| from spacy.cli._util import load_project_config, substitute_project_variables | ||||
| from spacy.cli._util import string_to_list | ||||
| from spacy import about | ||||
| from spacy.util import get_minor_version | ||||
| from spacy.cli.validate import get_model_pkgs | ||||
| from spacy.cli.download import get_compatibility, get_version | ||||
| from thinc.api import ConfigValidationError, Config | ||||
| import srsly | ||||
| import os | ||||
|  | @ -308,7 +312,8 @@ def test_project_config_validation2(config, n_errors): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize( | ||||
|     "int_value", [10, pytest.param("10", marks=pytest.mark.xfail)], | ||||
|     "int_value", | ||||
|     [10, pytest.param("10", marks=pytest.mark.xfail)], | ||||
| ) | ||||
| def test_project_config_interpolation(int_value): | ||||
|     variables = {"a": int_value, "b": {"c": "foo", "d": True}} | ||||
|  | @ -331,7 +336,8 @@ def test_project_config_interpolation(int_value): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize( | ||||
|     "greeting", [342, "everyone", "tout le monde", pytest.param("42", marks=pytest.mark.xfail)], | ||||
|     "greeting", | ||||
|     [342, "everyone", "tout le monde", pytest.param("42", marks=pytest.mark.xfail)], | ||||
| ) | ||||
| def test_project_config_interpolation_override(greeting): | ||||
|     variables = {"a": "world"} | ||||
|  | @ -423,7 +429,13 @@ def test_parse_cli_overrides(): | |||
| @pytest.mark.parametrize("pretraining", [True, False]) | ||||
| def test_init_config(lang, pipeline, optimize, pretraining): | ||||
|     # TODO: add more tests and also check for GPU with transformers | ||||
|     config = init_config(lang=lang, pipeline=pipeline, optimize=optimize, pretraining=pretraining, gpu=False) | ||||
|     config = init_config( | ||||
|         lang=lang, | ||||
|         pipeline=pipeline, | ||||
|         optimize=optimize, | ||||
|         pretraining=pretraining, | ||||
|         gpu=False, | ||||
|     ) | ||||
|     assert isinstance(config, Config) | ||||
|     if pretraining: | ||||
|         config["paths"]["raw_text"] = "my_data.jsonl" | ||||
|  | @ -474,3 +486,18 @@ def test_string_to_list(value): | |||
| def test_string_to_list_intify(value): | ||||
|     assert string_to_list(value, intify=False) == ["1", "2", "3"] | ||||
|     assert string_to_list(value, intify=True) == [1, 2, 3] | ||||
| 
 | ||||
| 
 | ||||
| def test_download_compatibility(): | ||||
|     model_name = "en_core_web_sm" | ||||
|     compatibility = get_compatibility() | ||||
|     version = get_version(model_name, compatibility) | ||||
|     assert get_minor_version(about.__version__) == get_minor_version(version) | ||||
| 
 | ||||
| 
 | ||||
| def test_validate_compatibility_table(): | ||||
|     model_pkgs, compat = get_model_pkgs() | ||||
|     spacy_version = get_minor_version(about.__version__) | ||||
|     current_compat = compat.get(spacy_version, {}) | ||||
|     assert len(current_compat) > 0 | ||||
|     assert "en_core_web_sm" in current_compat | ||||
|  |  | |||
|  | @ -648,6 +648,19 @@ def get_model_version_range(spacy_version: str) -> str: | |||
|     return f">={spacy_version},<{release[0]}.{release[1] + 1}.0" | ||||
| 
 | ||||
| 
 | ||||
| def get_model_lower_version(constraint: str) -> Optional[str]: | ||||
|     """From a version range like >=1.2.3,<1.3.0 return the lower pin. | ||||
|     """ | ||||
|     try: | ||||
|         specset = SpecifierSet(constraint) | ||||
|         for spec in specset: | ||||
|             if spec.operator in (">=", "==", "~="): | ||||
|                 return spec.version | ||||
|     except Exception: | ||||
|         pass | ||||
|     return None | ||||
| 
 | ||||
| 
 | ||||
| def get_base_version(version: str) -> str: | ||||
|     """Generate the base version without any prerelease identifiers. | ||||
| 
 | ||||
|  | @ -701,10 +714,18 @@ def load_meta(path: Union[str, Path]) -> Dict[str, Any]: | |||
|             raise ValueError(Errors.E054.format(setting=setting)) | ||||
|     if "spacy_version" in meta: | ||||
|         if not is_compatible_version(about.__version__, meta["spacy_version"]): | ||||
|             lower_version = get_model_lower_version(meta["spacy_version"]) | ||||
|             lower_version = get_minor_version(lower_version) | ||||
|             if lower_version is not None: | ||||
|                 lower_version = "v" + lower_version | ||||
|             elif "spacy_git_version" in meta: | ||||
|                 lower_version = "git commit " + meta["spacy_git_version"] | ||||
|             else: | ||||
|                 lower_version = "version unknown" | ||||
|             warn_msg = Warnings.W095.format( | ||||
|                 model=f"{meta['lang']}_{meta['name']}", | ||||
|                 model_version=meta["version"], | ||||
|                 version=meta["spacy_version"], | ||||
|                 version=lower_version, | ||||
|                 current=about.__version__, | ||||
|             ) | ||||
|             warnings.warn(warn_msg) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user