Functional Weave
Code in Python

validation.bic@1.0.0

impl/python.py

1,468 bytes · the Python implementation · view raw

from .validation_bic_types import BicCheck


def _invalid(reason: str) -> BicCheck:
    return BicCheck(
        valid=False, normalised=None, institution=None, country=None, location=None, branch=None, reason=reason
    )


def _is_upper(ch: str) -> bool:
    return "A" <= ch <= "Z"


def validate_bic(value: str) -> BicCheck:
    """Check the format of a BIC and split it into institution, country,
    location and branch.

    Well formed is not registered: only SWIFT's directory knows whether the
    code is assigned. Validators answer rather than raise.
    """
    if not isinstance(value, str):
        return _invalid("empty")

    # Folded by hand: str.upper() is Unicode-aware and Rust's ASCII fold is not.
    bic = "".join(chr(ord(ch) - 32) if "a" <= ch <= "z" else ch for ch in value if ch != " ")
    if not bic:
        return _invalid("empty")
    if any(not (_is_upper(ch) or "0" <= ch <= "9") for ch in bic):
        return _invalid("bad-character")
    if len(bic) != 8 and len(bic) != 11:
        return _invalid("bad-length")
    if not _is_upper(bic[4]) or not _is_upper(bic[5]):
        return _invalid("bad-country")

    return BicCheck(
        valid=True,
        normalised=bic,
        institution=bic[0:4],
        country=bic[4:6],
        location=bic[6:8],
        # An 8-character BIC is the primary office, which the 11-character form spells XXX.
        branch=bic[8:11] if len(bic) == 11 else "XXX",
        reason=None,
    )