fix sup: tags to use human-readable YEAR_PFS_{FR|PR|CR} slugs instead of opaque item keys
This commit is contained in:
@@ -32,7 +32,7 @@ from typing import TYPE_CHECKING
|
|||||||
|
|
||||||
from bib import translate
|
from bib import translate
|
||||||
from bib.item import Source
|
from bib.item import Source
|
||||||
from bib.tag import Tag
|
from bib.tag import Tag, rule_slug
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from bib.store import Store
|
from bib.store import Store
|
||||||
@@ -304,12 +304,14 @@ def _translate_url(url: str) -> Source | None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _link_existing(store: Store, url: str, parent_key: str) -> None:
|
def _link_existing(store: Store, url: str, parent_slug: str) -> None:
|
||||||
"""Add a ``sup:{parent_key}`` tag to an existing item by URL."""
|
"""Add a ``sup:{slug}`` tag to an existing item by URL."""
|
||||||
|
if not parent_slug:
|
||||||
|
return
|
||||||
con = store._con()
|
con = store._con()
|
||||||
row = con.execute("SELECT key FROM items WHERE url = ?", (url,)).fetchone()
|
row = con.execute("SELECT key FROM items WHERE url = ?", (url,)).fetchone()
|
||||||
if row:
|
if row:
|
||||||
store.add_tag(row["key"], Tag.sup(parent_key).label)
|
store.add_tag(row["key"], Tag.sup(parent_slug).label)
|
||||||
|
|
||||||
|
|
||||||
# ── Main crawl ────────────────────────────────────────────────────
|
# ── Main crawl ────────────────────────────────────────────────────
|
||||||
@@ -385,7 +387,9 @@ def crawl(
|
|||||||
for t in item.tags:
|
for t in item.tags:
|
||||||
if t.startswith("module:") or t.startswith("year:"):
|
if t.startswith("module:") or t.startswith("year:"):
|
||||||
inherit_tags.append(Tag.from_label(t))
|
inherit_tags.append(Tag.from_label(t))
|
||||||
inherit_tags.append(Tag.sup(key))
|
slug = rule_slug(item.title)
|
||||||
|
if slug:
|
||||||
|
inherit_tags.append(Tag.sup(slug))
|
||||||
inherit_tags.append(Tag.source("spider"))
|
inherit_tags.append(Tag.source("spider"))
|
||||||
|
|
||||||
sup_col = _get_sup_collection(store, item)
|
sup_col = _get_sup_collection(store, item)
|
||||||
@@ -393,7 +397,7 @@ def crawl(
|
|||||||
discovered: list[str] = []
|
discovered: list[str] = []
|
||||||
for url in all_urls:
|
for url in all_urls:
|
||||||
if url in _seen:
|
if url in _seen:
|
||||||
_link_existing(store, url, key)
|
_link_existing(store, url, slug)
|
||||||
continue
|
continue
|
||||||
_seen.add(url)
|
_seen.add(url)
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ Namespaces
|
|||||||
``file:rvu``, ``file:gpci``, ``file:pe-labor``,
|
``file:rvu``, ``file:gpci``, ``file:pe-labor``,
|
||||||
``file:pe-supply``, ``file:pe-equipment``, ``file:carrier``
|
``file:pe-supply``, ``file:pe-equipment``, ``file:carrier``
|
||||||
|
|
||||||
|
``sup``
|
||||||
|
Supplemental link to a parent rule using a human-readable
|
||||||
|
slug (``YEAR_ASSET_VERSION``):
|
||||||
|
``sup:2023_PFS_PR``, ``sup:2026_PFS_FR``
|
||||||
|
|
||||||
Usage::
|
Usage::
|
||||||
|
|
||||||
from bib.tag import Tag
|
from bib.tag import Tag
|
||||||
@@ -53,6 +58,8 @@ Usage::
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
@@ -113,9 +120,40 @@ class Tag(BaseModel):
|
|||||||
return cls(namespace="file", value=file_type)
|
return cls(namespace="file", value=file_type)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def sup(cls, parent_key: str) -> Tag:
|
def sup(cls, slug: str) -> Tag:
|
||||||
"""Tag linking a supplemental item back to its parent."""
|
"""Tag linking a supplemental item back to its parent rule.
|
||||||
return cls(namespace="sup", value=parent_key)
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
slug : str
|
||||||
|
Human-readable identifier, e.g. ``2023_PFS_PR``.
|
||||||
|
Use :func:`rule_slug` to derive from a rule title.
|
||||||
|
"""
|
||||||
|
return cls(namespace="sup", value=slug)
|
||||||
|
|
||||||
|
|
||||||
|
_RULE_KIND = {"Final": "FR", "Proposed": "PR", "Correction": "CR"}
|
||||||
|
|
||||||
|
# Match "CY YYYY PFS Final Rule" (or Proposed/Correction)
|
||||||
|
_RULE_RE = re.compile(r"CY\s+(\d{4})\s+PFS\s+(Final|Proposed|Correction)")
|
||||||
|
|
||||||
|
|
||||||
|
def rule_slug(title: str) -> str:
|
||||||
|
"""Derive a human-readable slug from a Federal Register rule title.
|
||||||
|
|
||||||
|
Examples::
|
||||||
|
|
||||||
|
>>> rule_slug("Medicare Program; CY 2023 PFS Proposed Rule")
|
||||||
|
'2023_PFS_PR'
|
||||||
|
>>> rule_slug("Medicare Program; CY 2017 PFS Final Rule")
|
||||||
|
'2017_PFS_FR'
|
||||||
|
>>> rule_slug("Something else entirely")
|
||||||
|
''
|
||||||
|
"""
|
||||||
|
m = _RULE_RE.search(title)
|
||||||
|
if not m:
|
||||||
|
return ""
|
||||||
|
return f"{m.group(1)}_PFS_{_RULE_KIND[m.group(2)]}"
|
||||||
|
|
||||||
|
|
||||||
def filter_tags(
|
def filter_tags(
|
||||||
|
|||||||
Reference in New Issue
Block a user