Source code for nse_xbrl_parser.taxonomy.registry
"""
nse_xbrl_parser.taxonomy.registry
Registry of all 58 NSE & BSE XBRL Taxonomies.
"""
from __future__ import annotations
import json
from pathlib import Path
from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Field
[docs]
class TaxonomyInfo(BaseModel):
"""Metadata describing a specific NSE/BSE filing taxonomy."""
id: int
name: str
regulation: str
all_links: List[str] = Field(default_factory=list)
taxonomy_links: List[str] = Field(default_factory=list)
utility_links: List[str] = Field(default_factory=list)
@property
def primary_taxonomy_url(self) -> Optional[str]:
"""Return the direct download URL for the taxonomy package if available."""
if self.taxonomy_links:
return self.taxonomy_links[0]
if self.all_links:
return self.all_links[0]
return None
@property
def primary_utility_url(self) -> Optional[str]:
"""Return the direct download URL for the Excel utility if available."""
if self.utility_links:
return self.utility_links[0]
return None
[docs]
class TaxonomyRegistry:
"""Registry managing all 58 official taxonomy definitions."""
[docs]
def __init__(self, catalog_path: Optional[Path] = None) -> None:
if catalog_path is None:
catalog_path = Path(__file__).parent / "taxonomies.json"
self._catalog_path = catalog_path
self._taxonomies: Dict[int, TaxonomyInfo] = {}
self._load_catalog()
def _load_catalog(self) -> None:
if not self._catalog_path.exists():
return
data = json.loads(self._catalog_path.read_text(encoding="utf-8"))
for item in data:
# Extract clean regulation name
full_name = item.get("name", "")
info = TaxonomyInfo(
id=item["id"],
name=full_name,
regulation=full_name.split("-")[0].strip() if "-" in full_name else full_name,
all_links=item.get("all_links", []),
taxonomy_links=item.get("taxonomy_links", []),
utility_links=item.get("utility_links", []),
)
self._taxonomies[info.id] = info
[docs]
def count(self) -> int:
"""Total number of registered taxonomies (58)."""
return len(self._taxonomies)
[docs]
def get_all(self) -> List[TaxonomyInfo]:
"""Get all registered taxonomies ordered by ID."""
return sorted(self._taxonomies.values(), key=lambda t: t.id)
[docs]
def get_by_id(self, taxonomy_id: int) -> Optional[TaxonomyInfo]:
"""Lookup taxonomy by its ID (1 to 58)."""
return self._taxonomies.get(taxonomy_id)
[docs]
def find_by_name(self, search_term: str) -> List[TaxonomyInfo]:
"""Search taxonomies by keyword in name or regulation (e.g. 'Shareholding', 'Financial', 'Governance')."""
term = search_term.lower()
return [
t for t in self._taxonomies.values()
if term in t.name.lower() or term in t.regulation.lower()
]
[docs]
def get_financial_taxonomies(self) -> List[TaxonomyInfo]:
"""Get all Regulation 33 Financial Results taxonomies."""
return [t for t in self._taxonomies.values() if "financial results" in t.name.lower()]
[docs]
def get_corporate_governance_taxonomy(self) -> Optional[TaxonomyInfo]:
"""Get Regulation 27(2) Corporate Governance taxonomy."""
matches = self.find_by_name("Corporate Governance")
return matches[0] if matches else None
[docs]
def get_shareholding_pattern_taxonomy(self) -> Optional[TaxonomyInfo]:
"""Get Regulation 31 Shareholding Pattern taxonomy."""
matches = self.find_by_name("Shareholding Pattern")
return matches[0] if matches else None