Skip to main content

Islamic Inheritance Distribution Calculator (Faraid)

Project description

Farady - Islamic Inheritance Distribution Calculator

License: AGPLv3 Python 3.14 CI

A Python library and CLI tool for calculating Islamic inheritance distribution according to Faraid (Islamic inheritance law).

Table of Contents


Branching Model

Branch Purpose
main Development work
release-pypi Test PyPI publishing
prod-pypi PyPI production (tag v* to release)
release-sa SunnaAssets releases

PyPI Release Flow

  1. Work on main
  2. Merge to release-pypi to test publishing
  3. Merge to prod-pypi when ready
  4. Tag on prod-pypi: git tag v1.0.0 && git push origin v1.0.0

SA Release Flow

Push to release-sa when SA might want new features.


Installation

pip install farady

Development mode:

pip install -e .

Quick Start

from farady import calculate_from_dict

# Simple case: 1 son, 1 daughter, wife
case = calculate_from_dict({"ibn": 1, "bint": 1, "zawja": True})

# Access results
print(case.distribution)   # {'zawja': 0.125, 'ibn': 0.5833, 'bint': 0.2917}
print(case.ending)         # 'taseeb'
print(case.total)          # 1.0
print(case.status)         # 'Complete'
print(case.asib)           # 'ibn-bint'

API Reference

Core Classes

Case

Data class representing a family configuration for inheritance calculation.

from farady import Case

case = Case.from_dict({
    "ibn": 2,        # 2 sons
    "bint": 1,       # 1 daughter
    "zawja": True,   # Wife present
    "umm": 1,        # Mother present
    "ab": 1,         # Father present
})

Properties:

Property Type Description
distribution dict Heir -> share mapping
ending str Distribution method used
asib str Residual heir (if any)
total float Total of all shares
status str Calculation status
raas int Total shares (denominator)
total_shares int Sum of all allocated shares

Class Methods:

Method Description
Case.from_dict(data) Create from dictionary (handles string conversion)
case.to_dict() Convert to dictionary (excludes zero/false values)

Main Functions

calculate(case)

Main function to calculate inheritance distribution.

from farady import Case, calculate

case = Case.from_dict({"ibn": 2, "bint": 1, "zawja": True})
result = calculate(case)

Parameters:

Parameter Type Description
case Case Case object with family member counts

Returns: Case with populated results

calculate_from_dict(data)

Calculate inheritance from a dictionary. Useful for loading from JSON, CSV, or form data.

from farady import calculate_from_dict

# From a dictionary
data = {"ibn": "2", "bint": "1", "zawja": "True"}  # Strings are converted
case = calculate_from_dict(data)

# From form data with mixed types
data = {"ibn": 1, "bint": 2, "zawja": True, "umm": "1"}
case = calculate_from_dict(data)

String Conversion Rules:

Field Type String Value Converted To
Spouse (zawj, zawja) "True", "1", "yes" True
Spouse (zawj, zawja) "False", "0", "no", "" False
Count fields "1", "2", etc. int
Count fields "True", "yes" 1
Count fields "False", "no", "" (excluded)

Returns: Case with populated results

calculate_inheritance(**kwargs)

Calculate inheritance directly from keyword arguments.

from farady import calculate_inheritance

case = calculate_inheritance(ibn=2, bint=1, zawja=True)

Parameters:

Parameter Type Description
ibn int Number of sons
bint int Number of daughters
iibn int Number of grandsons
bibn int Number of granddaughters
iiibn int Number of great-grandsons
biibn int Number of great-granddaughters
umm int Mother (0 or 1)
jadda int Grandmother(s) (0 or 1)
ab int Father (0 or 1)
jadd int Grandfather (0 or 1)
lium int Maternal half-sibling count
shaqiqa int Full sister count
shaqiq int Full brother count
uliab int Paternal half-sister count
aliab int Paternal half-brother count
ibnamm_sh int Full nephew count
ibnamm_liab int Half nephew count
amm int Uncle count
zawj bool Husband present
zawja bool Wife present

Returns: Case with populated results


CSV/Batch Processing

load_csv_cases(csv_path)

Load inheritance cases from a CSV file.

from farady import load_csv_cases

cases = load_csv_cases("tests/test_cases.csv")
# Returns: List[Case]

for case in cases:
    print(case.to_dict())

CSV Format:

ibn,bint,zawja,expected_total,notes
1,1,True,1.0,Son + daughter + wife
2,0,True,1.0,Two sons + wife
0,2,True,1.125,Two daughters + wife (awl)
  • Column headers must match valid field names (Arabic: ibn, bint, zawja, etc.)
  • Extra columns (like notes, expected_total) are ignored
  • String values are converted using same rules as from_dict()

Returns: List[Case]

process_csv_results(csv_path)

Load CSV and calculate results for each row. Returns full context for testing/debugging.

from farady import process_csv_results

results = process_csv_results("tests/test_cases.csv")

for item in results:
    row = item["row_data"]       # Original CSV row (dict)
    case = item["case"]          # Case object (before calculation)
    result = item["result"]      # Case object (after calculation)
    
    print(f"Case: {row.get('notes')}")
    print(f"  Distribution: {result.distribution}")
    print(f"  Ending: {result.ending}")
    print(f"  Total: {result.total}")
    print(f"  Status: {result.status}")

Returns: List[Dict] with keys:

Key Type Description
row_data dict Original CSV row data
case Case Parsed case object
result Case Calculated result case

Case Fields

Family Member Fields (Arabic Names)

Field Type Description Fixed Share
ibn int Sons Variable (asib)
bint int Daughters 1/2 (single), 2/3 (multiple), or variable
iibn int Grandsons (son's sons) Variable
bibn int Granddaughters (son's daughters) Variable
iiibn int Great-grandsons Variable
biibn int Great-granddaughters Variable
umm int Mother 1/6 (with children) or 1/3
jadda int Grandmother(s) 1/6 (if mother absent)
ab int Father 1/6 (with children) or variable
jadd int Grandfather Variable
lium int Maternal half-siblings 1/3 (collectively)
shaqiqa int Full sisters Variable
shaqiq int Full brothers Variable (asib)
uliab int Paternal half-sisters Variable
aliab int Paternal half-brothers Variable
ibnamm_sh int Full nephews Variable
ibnamm_liab int Half nephews Variable
amm int Uncles Variable
zawj bool Husband 1/2 (no kids) or 1/4
zawja bool Wife 1/4 (no kids) or 1/8

Pretty Names Reference

from farady import PRETTY_NAMES

PRETTY_NAMES = {
    'ibn': 'Son(s)',
    'bint': 'Daughter(s)',
    'iibn': 'Grandson(s)',
    'bibn': 'Granddaughter(s)',
    'iiibn': 'Great-grandson(s)',
    'biibn': 'Great-granddaughter(s)',
    'umm': 'Mother',
    'jadda': 'Grandmother(s)',
    'ab': 'Father',
    'jadd': 'Grandfather (nearest in relation)',
    'lium': 'Maternal Half-sibling(s)',
    'shaqiqa': 'Full Sister(s)',
    'shaqiq': 'Full Brother(s)',
    'uliab': 'Paternal Half-sister(s)',
    'aliab': 'Paternal Half-brother(s)',
    'ibnamm_sh': 'Full Nephew',
    'ibnamm_liab': 'Half Nephew',
    'amm': 'Uncle',
    'zawj': 'Husband',
    'zawja': 'Wife',
}

CLI Usage

# Basic usage
farady --ibn 2 --bint 1 --zawja

# Verbose output (shows ending, asib, status)
farady --ibn 2 --bint 1 --zawja --verbose

# All flags
farady --ibn 1 --bint 2 --iibn 0 --bibn 0 --umm 1 --ab 1 --zawja

Examples

Example 1: Basic Case

from farady import calculate_from_dict

case = calculate_from_dict({"ibn": 1, "bint": 1, "zawja": True})

print(f"Distribution: {case.distribution}")
# Distribution: {'zawja': 0.125, 'ibn': 0.5833, 'bint': 0.2917}

print(f"Ending: {case.ending}")
# Ending: taseeb

print(f"Raas: {case.raas}")
# Raas: 24

# For document generation:
# "Divide into 24 shares: 3 to Wife, 14 to Son(s), 7 to Daughter(s)"

Example 2: Awl Case (Shares Exceed 1)

case = calculate_from_dict({"bint": 2, "zawja": True})

print(f"Total: {case.total}")       # 1.125 (exceeds 1)
print(f"Ending: {case.ending}")     # awl

Example 3: Radd Case (Leftover After Fixed Shares)

case = calculate_from_dict({"bint": 2})

print(f"Distribution: {case.distribution}")  # {'bint': 1.0}
print(f"Total: {case.total}")                # 1.0
print(f"Ending: {case.ending}")              # radd
# Two daughters: 2/3 fixed, remaining 1/3 returned via radd

Example 4: CSV Batch Processing

from farady import process_csv_results

results = process_csv_results("test_cases.csv")

for item in results:
    row = item["row_data"]
    result = item["result"]
    
    # Debug output
    print(f"Case: {row.get('case_name', 'unnamed')}")
    print(f"  Ending method: {result.ending}")
    print(f"  Total: {result.total}")
    print(f"  Status: {result.status}")
    if result.asib:
        print(f"  Residual heir: {result.asib}")
    print()

Example 5: Form Data Integration

from farady import calculate_from_dict

# From web form (strings)
form_data = {
    "ibn": "2",
    "bint": "1",
    "zawja": "yes",  # Will be converted to True
    "umm": "1",
}

case = calculate_from_dict(form_data)

# Use raas for will document
if case.raas:
    shares_text = []
    for heir, share in case.distribution.items():
        num_shares = round(share * case.raas)
        shares_text.append(f"{num_shares} shares to {heir}")
    
    print(f"Divide into {case.raas} shares:")
    print("\n".join(shares_text))

License

GNU Affero General Public License v3.0 (AGPLv3)

This software is licensed under AGPLv3. See the LICENSE file for the full text.

Key Points of AGPLv3

  • Commercial Use Allowed: You may use this software for commercial purposes
  • Source Required: If you modify this software and run it as a network service, you must make your modifications available to users
  • Share Alike: If you distribute modified versions, they must be licensed under AGPLv3
  • Attribution: You must give appropriate credit to Adam Ahmed

Enterprise & Commercial Use

AGPLv3 is a strong copyleft license. If you:

  • Use it as-is: No restrictions
  • Host it as a service: You must provide source code to users
  • Modify it: Must distribute your modifications under AGPLv3

For traditional commercial licensing (to avoid copyleft obligations), please contact the author.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

farady-1.0.0.tar.gz (39.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

farady-1.0.0-py3-none-any.whl (43.8 kB view details)

Uploaded Python 3

File details

Details for the file farady-1.0.0.tar.gz.

File metadata

  • Download URL: farady-1.0.0.tar.gz
  • Upload date:
  • Size: 39.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for farady-1.0.0.tar.gz
Algorithm Hash digest
SHA256 be267a3e3ea549746ee0715fa6f0e9b6bfb55ecf0c1bebd7c2ddcfd72a9bf12f
MD5 8819dbb979c96ad103450004077da13d
BLAKE2b-256 7abb52f59e01065e0f28a1c1c30432b92cca303dda2f966a1a34fd251d05d94e

See more details on using hashes here.

Provenance

The following attestation bundles were made for farady-1.0.0.tar.gz:

Publisher: release-pypi.yml on adamquant/farady

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file farady-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: farady-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 43.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for farady-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b0ea5c6541103ab1d2d930981678dba4b23d9edb0471308476b5021b00e134be
MD5 b49b12909dbf45456bee50507db1371f
BLAKE2b-256 d60bf11a31eec9808dea59bcdb06b24d9539e2ffede5ec18b1d12b1ff3aa2480

See more details on using hashes here.

Provenance

The following attestation bundles were made for farady-1.0.0-py3-none-any.whl:

Publisher: release-pypi.yml on adamquant/farady

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page