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"
def debug_diff( config_path: Path, compare_to: Optional[Path], gpu: bool, optimize: Optimizations, pretraining: bool, markdown: bool, ): msg = Printer() with show_validation_error(hint_fill=False): user_config = load_config(config_path) if compare_to: other_config = load_config(compare_to) else: # Recreate a default config based from user's config lang = user_config["nlp"]["lang"] pipeline = list(user_config["nlp"]["pipeline"]) msg.info(f"Found user-defined language: '{lang}'") msg.info(f"Found user-defined pipelines: {pipeline}") other_config = init_config( lang=lang, pipeline=pipeline, optimize=optimize.value, gpu=gpu, pretraining=pretraining, silent=True, ) user = user_config.to_str() other = other_config.to_str() if user == other: msg.warn("No diff to show: configs are identical") else: diff_text = diff_strings(other, user, add_symbols=markdown) if markdown: md = MarkdownRenderer() md.add(md.code_block(diff_text, "diff")) print(md.text) else: print(diff_text)
def _format_accuracy(data: Dict[str, Any], exclude: List[str] = ["speed"]) -> str: if not data: return "" md = MarkdownRenderer() scalars = [(k, v) for k, v in data.items() if isinstance(v, (int, float))] scores = [(md.code(acc.upper()), f"{score*100:.2f}") for acc, score in scalars if acc not in exclude] md.add(md.table(scores, ["Type", "Score"])) return md.text
def project_document(project_dir: Path, output_file: Path, *, no_emoji: bool = False) -> None: is_stdout = str(output_file) == "-" config = load_project_config(project_dir) md = MarkdownRenderer(no_emoji=no_emoji) md.add(MARKER_START) title = config.get("title") description = config.get("description") md.add(md.title(1, f"spaCy Project{f': {title}' if title else ''}", "🪐")) if description: md.add(description) md.add(md.title(2, PROJECT_FILE, "📋")) md.add(INTRO_PROJECT) # Commands cmds = config.get("commands", []) data = [(md.code(cmd["name"]), cmd.get("help", "")) for cmd in cmds] if data: md.add(md.title(3, "Commands", "⏯")) md.add(INTRO_COMMANDS) md.add(md.table(data, ["Command", "Description"])) # Workflows wfs = config.get("workflows", {}).items() data = [(md.code(n), " → ".join(md.code(w) for w in stp)) for n, stp in wfs] if data: md.add(md.title(3, "Workflows", "⏭")) md.add(INTRO_WORKFLOWS) md.add(md.table(data, ["Workflow", "Steps"])) # Assets assets = config.get("assets", []) data = [] for a in assets: source = "Git" if a.get("git") else "URL" if a.get("url") else "Local" dest_path = a["dest"] dest = md.code(dest_path) if source == "Local": # Only link assets if they're in the repo with working_dir(project_dir) as p: if (p / dest_path).exists(): dest = md.link(dest, dest_path) data.append((dest, source, a.get("description", ""))) if data: md.add(md.title(3, "Assets", "🗂")) md.add(INTRO_ASSETS) md.add(md.table(data, ["File", "Source", "Description"])) md.add(MARKER_END) # Output result if is_stdout: print(md.text) else: content = md.text if output_file.exists(): with output_file.open("r", encoding="utf8") as f: existing = f.read() if MARKER_IGNORE in existing: msg.warn("Found ignore marker in existing file: skipping", output_file) return if MARKER_START in existing and MARKER_END in existing: msg.info( "Found existing file: only replacing auto-generated docs") before = existing.split(MARKER_START)[0] after = existing.split(MARKER_END)[1] content = f"{before}{content}{after}" else: msg.warn("Replacing existing file") with output_file.open("w", encoding="utf8") as f: f.write(content) msg.good("Saved project documentation", output_file)
def _format_label_scheme(data: Dict[str, Any]) -> str: if not data: return "" md = MarkdownRenderer() n_labels = 0 n_pipes = 0 label_data = [] for pipe, labels in data.items(): if not labels: continue col1 = md.bold(md.code(pipe)) col2 = ", ".join([ md.code(label.replace("|", "\\|")) for label in labels ]) # noqa: W605 label_data.append((col1, col2)) n_labels += len(labels) n_pipes += 1 if not label_data: return "" label_info = f"View label scheme ({n_labels} labels for {n_pipes} components)" md.add("<details>") md.add(f"<summary>{label_info}</summary>") md.add(md.table(label_data, ["Component", "Labels"])) md.add("</details>") return md.text
def generate_readme(meta: Dict[str, Any]) -> str: """ Generate a Markdown-formatted README text from a model meta.json. Used within the GitHub release notes and as content for README.md file added to model packages. """ md = MarkdownRenderer() lang = meta["lang"] name = f"{lang}_{meta['name']}" version = meta["version"] pipeline = ", ".join([md.code(p) for p in meta.get("pipeline", [])]) components = ", ".join([md.code(p) for p in meta.get("components", [])]) vecs = meta.get("vectors", {}) vectors = f"{vecs.get('keys', 0)} keys, {vecs.get('vectors', 0)} unique vectors ({ vecs.get('width', 0)} dimensions)" author = meta.get("author") or "n/a" notes = meta.get("notes", "") license_name = meta.get("license") sources = _format_sources(meta.get("sources")) description = meta.get("description") label_scheme = _format_label_scheme(meta.get("labels")) accuracy = _format_accuracy(meta.get("performance")) table_data = [ (md.bold("Name"), md.code(name)), (md.bold("Version"), md.code(version)), (md.bold("spaCy"), md.code(meta["spacy_version"])), (md.bold("Default Pipeline"), pipeline), (md.bold("Components"), components), (md.bold("Vectors"), vectors), (md.bold("Sources"), sources or "n/a"), (md.bold("License"), md.code(license_name) if license_name else "n/a"), (md.bold("Author"), md.link(author, meta["url"]) if "url" in meta else author), ] # Put together Markdown body if description: md.add(description) md.add(md.table(table_data, ["Feature", "Description"])) if label_scheme: md.add(md.title(3, "Label Scheme")) md.add(label_scheme) if accuracy: md.add(md.title(3, "Accuracy")) md.add(accuracy) if notes: md.add(notes) return md.text