---
name: parser_registry
kind: function
lang: py
domain: core
version: "1.0.0"
purity: impure
signature: "class ParserRegistry: register(name: str, parser: BaseParser) -> None; unregister(name: str) -> None; get_parser(name: str) -> BaseParser | None; get_parser_for_file(path: str) -> BaseParser | None; async parse(source: str, **kwargs) -> ParseResult; list_parsers() -> list[str]; list_supported_extensions() -> list[str]"
description: "Registry extensible que despacha parsing de archivos al parser correcto basado en extension. Patron plugin: registrar parsers por nombre y extensiones, resolver automaticamente. Mantiene estado mutable (mapa extension→parser). Singleton global disponible via get_registry()."
tags: [parser, registry, plugin, extensible, dispatch, pattern, singleton, pendiente-usar]
uses_functions: []
uses_types: [base_parser_py_core, parse_result_py_core]
returns: [parse_result_py_core]
returns_optional: false
error_type: "error_go_core"
imports: []
params: []
output: "ParseResult con contenido parseado y metadatos del parsing"
tested: true
tests:
  - "registrar parser custom"
  - "resolver parser por extension de archivo"
  - "parsear archivo existente con extension registrada"
  - "parsear string de contenido sin path"
  - "desregistrar parser elimina nombre y extensiones"
  - "extension desconocida hace fallback al parser text"
test_file_path: "python/functions/core/parser_registry_test.py"
file_path: "python/functions/core/parser_registry.py"
---

## Ejemplo

```python
from parser_registry import ParserRegistry, get_registry

# Usar instancia propia
registry = ParserRegistry()
registry.register("markdown", MarkdownParser())
registry.register("pdf", PDFParser())
registry.register("text", TextParser())

result = await registry.parse("documento.md")
result2 = await registry.parse("Contenido directo\ncon varias lineas")

# Usar singleton global
global_registry = get_registry()
global_registry.register("markdown", MarkdownParser())
```

## Algoritmo de despacho

`parse(source)` sigue este orden de decision:

1. Si `source` es URL de repositorio de codigo (github.com, gitlab.com, bitbucket.org) → delega al parser `"code"`.
2. Si `source` parece path de archivo (longitud ≤ 512, sin newlines) y existe en disco:
   - Si es directorio → delega al parser `"directory"`.
   - Resuelve parser por extension → delega.
   - Sin parser para la extension → fallback al parser `"text"` via `parse_content`.
3. Si no parece path (contenido largo o con newlines) → parsea como string con parser `"text"` via `parse_content`.

## Notas

Patron plugin extensible: cada parser se registra por nombre y declara sus extensiones. El mapa extension→nombre se construye automaticamente al registrar. Unregister limpia el mapa solo si el parser registrado sigue siendo el mismo (evita colisiones si dos parsers comparten extension).

El singleton `get_registry()` usa lazy initialization thread-unsafe — suficiente para la mayoria de casos. Para uso multi-threaded, crear instancias propias de ParserRegistry.

Los parsers especiales `"text"`, `"directory"` y `"code"` son convencion — el registry no los crea automaticamente, deben registrarse explicitamente.
