mirror of
				https://github.com/explosion/spaCy.git
				synced 2025-11-04 09:57:26 +03:00 
			
		
		
		
	* Use isort with Black profile * isort all the things * Fix import cycles as a result of import sorting * Add DOCBIN_ALL_ATTRS type definition * Add isort to requirements * Remove isort from build dependencies check * Typo
		
			
				
	
	
		
			191 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			191 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import json
 | 
						|
import platform
 | 
						|
from pathlib import Path
 | 
						|
from typing import Any, Dict, List, Optional, Union
 | 
						|
 | 
						|
import srsly
 | 
						|
from wasabi import MarkdownRenderer, Printer
 | 
						|
 | 
						|
from .. import about, util
 | 
						|
from ..compat import importlib_metadata
 | 
						|
from ._util import Arg, Opt, app, string_to_list
 | 
						|
from .download import get_latest_version, get_model_filename
 | 
						|
 | 
						|
 | 
						|
@app.command("info")
 | 
						|
def info_cli(
 | 
						|
    # fmt: off
 | 
						|
    model: Optional[str] = Arg(None, help="Optional loadable spaCy pipeline"),
 | 
						|
    markdown: bool = Opt(False, "--markdown", "-md", help="Generate Markdown for GitHub issues"),
 | 
						|
    silent: bool = Opt(False, "--silent", "-s", "-S", help="Don't print anything (just return)"),
 | 
						|
    exclude: str = Opt("labels", "--exclude", "-e", help="Comma-separated keys to exclude from the print-out"),
 | 
						|
    url: bool = Opt(False, "--url", "-u", help="Print the URL to download the most recent compatible version of the pipeline"),
 | 
						|
    # fmt: on
 | 
						|
):
 | 
						|
    """
 | 
						|
    Print info about spaCy installation. If a pipeline is specified as an argument,
 | 
						|
    print its meta information. Flag --markdown prints details in Markdown for easy
 | 
						|
    copy-pasting to GitHub issues.
 | 
						|
 | 
						|
    Flag --url prints only the download URL of the most recent compatible
 | 
						|
    version of the pipeline.
 | 
						|
 | 
						|
    DOCS: https://spacy.io/api/cli#info
 | 
						|
    """
 | 
						|
    exclude = string_to_list(exclude)
 | 
						|
    info(
 | 
						|
        model,
 | 
						|
        markdown=markdown,
 | 
						|
        silent=silent,
 | 
						|
        exclude=exclude,
 | 
						|
        url=url,
 | 
						|
    )
 | 
						|
 | 
						|
 | 
						|
def info(
 | 
						|
    model: Optional[str] = None,
 | 
						|
    *,
 | 
						|
    markdown: bool = False,
 | 
						|
    silent: bool = True,
 | 
						|
    exclude: Optional[List[str]] = None,
 | 
						|
    url: bool = False,
 | 
						|
) -> Union[str, dict]:
 | 
						|
    msg = Printer(no_print=silent, pretty=not silent)
 | 
						|
    if not exclude:
 | 
						|
        exclude = []
 | 
						|
    if url:
 | 
						|
        if model is not None:
 | 
						|
            title = f"Download info for pipeline '{model}'"
 | 
						|
            data = info_model_url(model)
 | 
						|
            print(data["download_url"])
 | 
						|
            return data
 | 
						|
        else:
 | 
						|
            msg.fail("--url option requires a pipeline name", exits=1)
 | 
						|
    elif model:
 | 
						|
        title = f"Info about pipeline '{model}'"
 | 
						|
        data = info_model(model, silent=silent)
 | 
						|
    else:
 | 
						|
        title = "Info about spaCy"
 | 
						|
        data = info_spacy()
 | 
						|
    raw_data = {k.lower().replace(" ", "_"): v for k, v in data.items()}
 | 
						|
    if "Pipelines" in data and isinstance(data["Pipelines"], dict):
 | 
						|
        data["Pipelines"] = ", ".join(
 | 
						|
            f"{n} ({v})" for n, v in data["Pipelines"].items()
 | 
						|
        )
 | 
						|
    markdown_data = get_markdown(data, title=title, exclude=exclude)
 | 
						|
    if markdown:
 | 
						|
        if not silent:
 | 
						|
            print(markdown_data)
 | 
						|
        return markdown_data
 | 
						|
    if not silent:
 | 
						|
        table_data = {k: v for k, v in data.items() if k not in exclude}
 | 
						|
        msg.table(table_data, title=title)
 | 
						|
    return raw_data
 | 
						|
 | 
						|
 | 
						|
def info_spacy() -> Dict[str, Any]:
 | 
						|
    """Generate info about the current spaCy intallation.
 | 
						|
 | 
						|
    RETURNS (dict): The spaCy info.
 | 
						|
    """
 | 
						|
    all_models = {}
 | 
						|
    for pkg_name in util.get_installed_models():
 | 
						|
        package = pkg_name.replace("-", "_")
 | 
						|
        all_models[package] = util.get_package_version(pkg_name)
 | 
						|
    return {
 | 
						|
        "spaCy version": about.__version__,
 | 
						|
        "Location": str(Path(__file__).parent.parent),
 | 
						|
        "Platform": platform.platform(),
 | 
						|
        "Python version": platform.python_version(),
 | 
						|
        "Pipelines": all_models,
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
def info_model(model: str, *, silent: bool = True) -> Dict[str, Any]:
 | 
						|
    """Generate info about a specific model.
 | 
						|
 | 
						|
    model (str): Model name of path.
 | 
						|
    silent (bool): Don't print anything, just return.
 | 
						|
    RETURNS (dict): The model meta.
 | 
						|
    """
 | 
						|
    msg = Printer(no_print=silent, pretty=not silent)
 | 
						|
    if util.is_package(model):
 | 
						|
        model_path = util.get_package_path(model)
 | 
						|
    else:
 | 
						|
        model_path = Path(model)
 | 
						|
    meta_path = model_path / "meta.json"
 | 
						|
    if not meta_path.is_file():
 | 
						|
        msg.fail("Can't find pipeline meta.json", meta_path, exits=1)
 | 
						|
    meta = srsly.read_json(meta_path)
 | 
						|
    if model_path.resolve() != model_path:
 | 
						|
        meta["source"] = str(model_path.resolve())
 | 
						|
    else:
 | 
						|
        meta["source"] = str(model_path)
 | 
						|
    download_url = info_installed_model_url(model)
 | 
						|
    if download_url:
 | 
						|
        meta["download_url"] = download_url
 | 
						|
    return {
 | 
						|
        k: v for k, v in meta.items() if k not in ("accuracy", "performance", "speed")
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
def info_installed_model_url(model: str) -> Optional[str]:
 | 
						|
    """Given a pipeline name, get the download URL if available, otherwise
 | 
						|
    return None.
 | 
						|
 | 
						|
    This is only available for pipelines installed as modules that have
 | 
						|
    dist-info available.
 | 
						|
    """
 | 
						|
    try:
 | 
						|
        dist = importlib_metadata.distribution(model)
 | 
						|
        text = dist.read_text("direct_url.json")
 | 
						|
        if isinstance(text, str):
 | 
						|
            data = json.loads(text)
 | 
						|
            return data["url"]
 | 
						|
    except Exception:
 | 
						|
        pass
 | 
						|
    return None
 | 
						|
 | 
						|
 | 
						|
def info_model_url(model: str) -> Dict[str, Any]:
 | 
						|
    """Return the download URL for the latest version of a pipeline."""
 | 
						|
    version = get_latest_version(model)
 | 
						|
 | 
						|
    filename = get_model_filename(model, version)
 | 
						|
    download_url = about.__download_url__ + "/" + filename
 | 
						|
    release_tpl = "https://github.com/explosion/spacy-models/releases/tag/{m}-{v}"
 | 
						|
    release_url = release_tpl.format(m=model, v=version)
 | 
						|
    return {"download_url": download_url, "release_url": release_url}
 | 
						|
 | 
						|
 | 
						|
def get_markdown(
 | 
						|
    data: Dict[str, Any],
 | 
						|
    title: Optional[str] = None,
 | 
						|
    exclude: Optional[List[str]] = None,
 | 
						|
) -> str:
 | 
						|
    """Get data in GitHub-flavoured Markdown format for issues etc.
 | 
						|
 | 
						|
    data (Dict[str, Any]): Label/value pairs.
 | 
						|
    title (str): Optional title, will be rendered as headline 2.
 | 
						|
    exclude (List[str]): Names of keys to exclude.
 | 
						|
    RETURNS (str): The Markdown string.
 | 
						|
    """
 | 
						|
    md = MarkdownRenderer()
 | 
						|
    if title:
 | 
						|
        md.add(md.title(2, title))
 | 
						|
    items = []
 | 
						|
    for key, value in data.items():
 | 
						|
        if exclude and key in exclude:
 | 
						|
            continue
 | 
						|
        if isinstance(value, str):
 | 
						|
            try:
 | 
						|
                existing_path = Path(value).exists()
 | 
						|
            except Exception:
 | 
						|
                # invalid Path, like a URL string
 | 
						|
                existing_path = False
 | 
						|
            if existing_path:
 | 
						|
                continue
 | 
						|
        items.append(f"{md.bold(f'{key}:')} {value}")
 | 
						|
    md.add(md.list(items))
 | 
						|
    return f"\n{md.text}\n"
 |