Skip to content

Extract

This presumes existence of a local path to a separate library where the contents of the rule can be extracted from.

Extract Rules

If text contains serialized (e.g. Republic Act No. 386) and named rules (the Civil Code of the Philippines), extract the Rules into their canonical serial variants.

Examples:

Python Console Session
>>> from statute_patterns import extract_rules
>>> text = "The Civil Code of the Philippines, the old Spanish Civil Code; Rep Act No. 386"
>>> list(extract_rules(text)) # get all rules
[
    Rule(cat='ra', id='386'),
    Rule(cat='ra', id='386'),
    Rule(cat='spain', id='civil')
]

Parameters:

Name Type Description Default
text str

Text to search for statute patterns.

required

Yields:

Type Description
Iterator[Rule]

Iterator[Rule]: Serialized Rules and Named Rule patterns

Source code in statute_patterns/__main__.py
Python
def extract_rules(text: str) -> Iterator[Rule]:
    """If text contains [serialized][serial-pattern] (e.g. _Republic Act No. 386_)
    and [named][named-pattern] rules (_the Civil Code of the Philippines_),
    extract the [`Rules`][rule-model] into their canonical serial variants.

    Examples:
        >>> from statute_patterns import extract_rules
        >>> text = "The Civil Code of the Philippines, the old Spanish Civil Code; Rep Act No. 386"
        >>> list(extract_rules(text)) # get all rules
        [
            Rule(cat='ra', id='386'),
            Rule(cat='ra', id='386'),
            Rule(cat='spain', id='civil')
        ]

    Args:
        text (str): Text to search for statute patterns.

    Yields:
        Iterator[Rule]: Serialized Rules and Named Rule patterns
    """  # noqa: E501
    yield from SerializedRules.extract_rules(text)
    yield from NamedRules.extract_rules(text)

Extract Rule

Thin wrapper over extract_rules(). If text contains a matching Rule, get the first one found.

Examples:

Python Console Session
>>> from statute_patterns import extract_rule
>>> text = "The Civil Code of the Philippines, the old Spanish Civil Code; Rep Act No. 386"
>>> extract_rule(text)  # get the first matching rule
Rule(cat='ra', id='386')

Parameters:

Name Type Description Default
text str

Text to search for statute patterns.

required

Returns:

Type Description
Rule | None

Rule | None: The first Rule found, if it exists

Source code in statute_patterns/__main__.py
Python
def extract_rule(text: str) -> Rule | None:
    """Thin wrapper over [`extract_rules()`][extract-rules]. If text contains a
    matching [`Rule`][rule-model], get the first one found.

    Examples:
        >>> from statute_patterns import extract_rule
        >>> text = "The Civil Code of the Philippines, the old Spanish Civil Code; Rep Act No. 386"
        >>> extract_rule(text)  # get the first matching rule
        Rule(cat='ra', id='386')

    Args:
        text (str): Text to search for statute patterns.

    Returns:
        Rule | None: The first Rule found, if it exists
    """  # noqa: E501
    try:
        return next(extract_rules(text))
    except StopIteration:
        return None

Count Rules

Based on results from extract_rules(), get the count of each unique rule found.

Examples:

Python Console Session
>>> from statute_patterns import count_rules
>>> text = "The Civil Code of the Philippines, the old Spanish Civil Code; Rep Act No. 386"
>>> list(count_rules(text)): # get unique rules with counts
[
    {'cat': 'ra', 'id': '386', 'mentions': 2},
    {'cat': 'spain', 'id': 'civil', 'mentions': 1}
]

Parameters:

Name Type Description Default
text str

Text to search for statute patterns.

required

Returns:

Type Description
Iterator[dict]

Iterator[dict]: Unique rules converted into dicts with their counts

Source code in statute_patterns/__main__.py
Python
def count_rules(text: str) -> Iterator[dict]:
    """Based on results from [`extract_rules()`][extract-rules],
    get the count of each unique rule found.

    Examples:
        >>> from statute_patterns import count_rules
        >>> text = "The Civil Code of the Philippines, the old Spanish Civil Code; Rep Act No. 386"
        >>> list(count_rules(text)): # get unique rules with counts
        [
            {'cat': 'ra', 'id': '386', 'mentions': 2},
            {'cat': 'spain', 'id': 'civil', 'mentions': 1}
        ]

    Args:
        text (str): Text to search for statute patterns.

    Returns:
        Iterator[dict]: Unique rules converted into dicts with their counts
    """  # noqa: E501
    for k, v in Counter(extract_rules(text)).items():
        yield k.dict() | {"mentions": v}

Detail Rule

We can extract the details of the rule with the StatuteDetails.from_rule() also accessible via Rule.get_details().

Statute Details

Bases: BaseModel

A StatuteDetails object presupposes the existence of a Rule object.

After all, it's only when there's a valid path to a Rule that the details and provisions of that rule can be extracted. Some notable fields are described below:

Field Type Function
rule Rule How we source the path
title str The statute's serial title, e.g. Republic Act No. 386
description str The statute's official title, e.g. An Act to...
Source code in statute_patterns/components/details.py
Python
class StatuteDetails(BaseModel):
    """
    A `StatuteDetails` object presupposes the existence of a [`Rule`][rule-model]
    object.

    After all, it's only when there's a valid path to a [`Rule`][rule-model] that the
    details and provisions of that rule can be extracted. Some notable fields
    are described below:

    Field | Type | Function
    :--:|:--:|:--:
    rule | [`Rule`][rule-model] | How we source the path
    title | str | The statute's serial title, e.g. Republic Act No. 386
    description | str | The statute's official title, e.g. An Act to...
    """

    created: float
    modified: float
    rule: Rule
    title: str
    description: str
    id: str
    emails: list[EmailStr]
    date: datetime.date
    variant: int
    titles: list[StatuteTitle]
    units: list[dict]

    @classmethod
    def slug_id(cls, p: Path, dt: str, v: int | None):
        """Use the path's parameters with the date and variant, to
        create a slug that can serve as the url / primary key of the
        statute."""
        _temp = [p.parent.parent.stem, p.parent.stem, dt]
        if v:
            _temp.append(str(v))
        return slugify(" ".join(_temp))

    @classmethod
    def from_rule(cls, rule: Rule, base_path: Path = STATUTE_PATH):
        """From a constructed rule (see [`Rule.from_path`][statute_patterns.components.rule.Rule.from_path]), get the
        details of said rule.  Limitation: the category and identifier must
        be unique."""  # noqa: E501
        if not base_path.exists():
            raise Exception(f"Could not get proper {base_path=}.")

        if not rule.serial_title:
            raise Exception("No serial title created.")

        _file = None
        if folder := rule.get_path(base_path):
            _file = folder / DETAILS_FILE

        if not _file or not _file.exists():
            raise Exception(f"No _file found from {folder=} {base_path=}.")

        d = yaml.safe_load(_file.read_bytes())
        dt, ofc_title, v = d.get("date"), d.get("law_title"), d.get("variant")
        if not all([ofc_title, dt]):
            raise Exception(f"Fail on: {dt=}, {ofc_title=}, {v=}")
        units = set_units(ofc_title, rule.units_path(_file.parent))
        idx = cls.slug_id(_file, dt, v)
        titles = StatuteTitle.generate(
            pk=idx,
            official=ofc_title,
            serial=rule.serial_title,
            short=get_short(units),
            aliases=d.get("aliases"),
        )
        return cls(
            created=_file.stat().st_ctime,
            modified=_file.stat().st_mtime,
            rule=rule,
            id=idx,
            title=rule.serial_title,
            description=ofc_title,
            emails=d.get("emails", ["bot@lawsql.com"]),  # default to generic
            date=parse(d["date"]).date(),
            variant=v or 1,  # default to 1
            units=units,
            titles=list(titles),
        )

Functions

from_rule(rule, base_path=STATUTE_PATH) classmethod

From a constructed rule (see Rule.from_path), get the details of said rule. Limitation: the category and identifier must be unique.

Source code in statute_patterns/components/details.py
Python
@classmethod
def from_rule(cls, rule: Rule, base_path: Path = STATUTE_PATH):
    """From a constructed rule (see [`Rule.from_path`][statute_patterns.components.rule.Rule.from_path]), get the
    details of said rule.  Limitation: the category and identifier must
    be unique."""  # noqa: E501
    if not base_path.exists():
        raise Exception(f"Could not get proper {base_path=}.")

    if not rule.serial_title:
        raise Exception("No serial title created.")

    _file = None
    if folder := rule.get_path(base_path):
        _file = folder / DETAILS_FILE

    if not _file or not _file.exists():
        raise Exception(f"No _file found from {folder=} {base_path=}.")

    d = yaml.safe_load(_file.read_bytes())
    dt, ofc_title, v = d.get("date"), d.get("law_title"), d.get("variant")
    if not all([ofc_title, dt]):
        raise Exception(f"Fail on: {dt=}, {ofc_title=}, {v=}")
    units = set_units(ofc_title, rule.units_path(_file.parent))
    idx = cls.slug_id(_file, dt, v)
    titles = StatuteTitle.generate(
        pk=idx,
        official=ofc_title,
        serial=rule.serial_title,
        short=get_short(units),
        aliases=d.get("aliases"),
    )
    return cls(
        created=_file.stat().st_ctime,
        modified=_file.stat().st_mtime,
        rule=rule,
        id=idx,
        title=rule.serial_title,
        description=ofc_title,
        emails=d.get("emails", ["bot@lawsql.com"]),  # default to generic
        date=parse(d["date"]).date(),
        variant=v or 1,  # default to 1
        units=units,
        titles=list(titles),
    )

slug_id(p, dt, v) classmethod

Use the path's parameters with the date and variant, to create a slug that can serve as the url / primary key of the statute.

Source code in statute_patterns/components/details.py
Python
@classmethod
def slug_id(cls, p: Path, dt: str, v: int | None):
    """Use the path's parameters with the date and variant, to
    create a slug that can serve as the url / primary key of the
    statute."""
    _temp = [p.parent.parent.stem, p.parent.stem, dt]
    if v:
        _temp.append(str(v))
    return slugify(" ".join(_temp))