Spaces:
Running on Zero
Running on Zero
| """Typer CLI: turn federal/state regulation & statute citations into Cornell LII links. | |
| Links are built offline by default. ``--verify`` (CFR) and ``search`` (federal) | |
| are the only paths that reach the network, via the public eCFR API. | |
| """ | |
| from __future__ import annotations | |
| import typer | |
| from . import citations, ecfr, output, states, urls | |
| from .citations import Citation, CitationError | |
| from .client import HttpError, url_exists | |
| app = typer.Typer( | |
| add_completion=False, | |
| no_args_is_help=True, | |
| help="Query Cornell LII (law.cornell.edu) for federal & state regulation links.", | |
| ) | |
| # Reusable --json flag, shared across commands. | |
| JSON = typer.Option(False, "--json", "-j", help="Emit JSON instead of human-readable text.") | |
| def _fail(message: str) -> "typer.NoReturn": | |
| typer.secho(f"error: {message}", fg=typer.colors.RED, err=True) | |
| raise typer.Exit(1) | |
| def _parse(text: str | None, title: str | None, section: str | None, corpus: str) -> Citation: | |
| """Build a Citation from a free-form string or explicit --title/--section.""" | |
| if text: | |
| try: | |
| return citations.parse_cfr(text) if corpus == "cfr" else citations.parse_usc(text) | |
| except CitationError as e: | |
| _fail(str(e)) | |
| if title and section: | |
| return Citation(corpus, str(title), str(section)) | |
| word = "CFR" if corpus == "cfr" else "USC" | |
| _fail(f"Provide a citation (e.g. '29 {word} 1604.11') or both --title and --section.") | |
| # --- Federal CFR (regulations) ------------------------------------------------ | |
| def cfr( | |
| citation: str = typer.Argument(None, help="e.g. '29 CFR 1604.11' or '29/1604.11'"), | |
| title: str = typer.Option(None, "--title", "-t", help="CFR title number."), | |
| section: str = typer.Option(None, "--section", "-s", help="Section number, e.g. 1604.11."), | |
| verify: bool = typer.Option(False, "--verify", help="Confirm the citation exists via the eCFR API."), | |
| json_out: bool = JSON, | |
| ) -> None: | |
| """Resolve a Code of Federal Regulations citation to its LII page.""" | |
| cit = _parse(citation, title, section, "cfr") | |
| result = { | |
| "corpus": "cfr", | |
| "citation": cit.label, | |
| "title": cit.title, | |
| "section": cit.section, | |
| "url": urls.cfr_section_url(cit.title, cit.section), | |
| } | |
| if verify: | |
| try: | |
| v = ecfr.verify_cfr(cit.title, cit.section) | |
| except HttpError as e: | |
| _fail(f"eCFR verification failed: {e}") | |
| result["verified"] = v["valid"] | |
| result["date"] = v["date"] | |
| if v.get("heading"): | |
| result["label"] = v["heading"] | |
| if v.get("detail"): | |
| result["detail"] = v["detail"] | |
| output.show(result, json_out) | |
| def cfr_part( | |
| title: str = typer.Argument(..., help="CFR title number, e.g. 29."), | |
| part: str = typer.Argument(..., help="Part number, e.g. 1604."), | |
| json_out: bool = JSON, | |
| ) -> None: | |
| """Link to a CFR part's browse page (lists its sections).""" | |
| result = { | |
| "corpus": "cfr", | |
| "citation": f"{title} CFR Part {part}", | |
| "url": urls.cfr_part_url(title, part), | |
| } | |
| output.show(result, json_out) | |
| def cfr_title( | |
| title: str = typer.Argument(..., help="CFR title number, e.g. 29."), | |
| json_out: bool = JSON, | |
| ) -> None: | |
| """Link to a CFR title's index page.""" | |
| result = {"corpus": "cfr", "citation": f"{title} CFR", "url": urls.cfr_title_url(title)} | |
| output.show(result, json_out) | |
| # --- Federal USC (statutes) --------------------------------------------------- | |
| def usc( | |
| citation: str = typer.Argument(None, help="e.g. '42 USC 1983' or '42/1983'"), | |
| title: str = typer.Option(None, "--title", "-t", help="USC title number."), | |
| section: str = typer.Option(None, "--section", "-s", help="Section number, e.g. 1983."), | |
| verify: bool = typer.Option(False, "--verify", help="Confirm the LII page resolves (HTTP check)."), | |
| json_out: bool = JSON, | |
| ) -> None: | |
| """Resolve a US Code citation to its LII page.""" | |
| cit = _parse(citation, title, section, "usc") | |
| url = urls.usc_section_url(cit.title, cit.section) | |
| result = { | |
| "corpus": "usc", | |
| "citation": cit.label, | |
| "title": cit.title, | |
| "section": cit.section, | |
| "url": url, | |
| } | |
| if verify: | |
| ok = url_exists(url) | |
| result["verified"] = ok | |
| if not ok: | |
| result["detail"] = "LII page did not return HTTP 200." | |
| output.show(result, json_out) | |
| # --- State materials ---------------------------------------------------------- | |
| def state_regs( | |
| state: str = typer.Argument(..., help="State name or USPS abbreviation, e.g. 'maine' or 'ME'."), | |
| json_out: bool = JSON, | |
| ) -> None: | |
| """Link to a state's LII-hosted administrative code (regulations).""" | |
| try: | |
| slug = states.resolve_state(state) | |
| except ValueError as e: | |
| _fail(str(e)) | |
| result = { | |
| "corpus": "state-regs", | |
| "citation": f"{slug.replace('_', ' ').title()} regulations", | |
| "url": urls.state_regs_url(slug), | |
| } | |
| output.show(result, json_out) | |
| def state( | |
| state: str = typer.Argument(..., help="State name or USPS abbreviation, e.g. 'new york' or 'NY'."), | |
| json_out: bool = JSON, | |
| ) -> None: | |
| """Link to a state's LII portal page (statutes link out to official sources).""" | |
| try: | |
| slug = states.resolve_state(state) | |
| except ValueError as e: | |
| _fail(str(e)) | |
| result = { | |
| "corpus": "state", | |
| "citation": f"{slug.replace('_', ' ').title()} legal materials", | |
| "url": urls.state_portal_url(slug), | |
| } | |
| output.show(result, json_out) | |
| def states_cmd(json_out: bool = JSON) -> None: | |
| """Link to the LII states & regulations directories.""" | |
| result = { | |
| "links": [ | |
| {"citation": "All states", "url": urls.states_directory_url()}, | |
| {"citation": "All state regulations", "url": urls.regulations_directory_url()}, | |
| ] | |
| } | |
| output.show(result, json_out) | |
| # --- Search ------------------------------------------------------------------- | |
| def search( | |
| query: str = typer.Argument(..., help="Search terms."), | |
| corpus: str = typer.Option("cfr", "--corpus", "-c", help="'cfr' = eCFR API deep links; 'lii' = LII site-search URL."), | |
| limit: int = typer.Option(10, "--limit", "-n", help="Max results (cfr corpus)."), | |
| json_out: bool = JSON, | |
| ) -> None: | |
| """Search federal regulations (eCFR -> LII links), or get the LII site-search URL.""" | |
| corpus = corpus.lower() | |
| if corpus == "cfr": | |
| try: | |
| hits = ecfr.search_federal(query, limit) | |
| except HttpError as e: | |
| _fail(f"eCFR search failed: {e}") | |
| output.show({"query": query, "corpus": "cfr", "links": hits}, json_out, attribution=True) | |
| elif corpus == "lii": | |
| result = { | |
| "query": query, | |
| "corpus": "lii", | |
| "links": [ | |
| { | |
| "citation": f"LII site search: {query}", | |
| "url": urls.lii_search_url(query), | |
| "note": "Open in a browser — LII search is not crawlable (robots.txt) and renders client-side.", | |
| } | |
| ], | |
| } | |
| output.show(result, json_out, attribution=True) | |
| else: | |
| _fail("--corpus must be 'cfr' or 'lii'.") | |
| if __name__ == "__main__": | |
| app() | |