always-decimal


Namealways-decimal JSON
Version 1.0.1 PyPI version JSON
download
home_pageNone
SummaryCoerce floats/strings/Decimals to Decimal with predictable scale and rounding.
upload_time2025-08-20 00:38:49
maintainerNone
docs_urlNone
authorUtkarsh Singh
requires_python>=3.10
licenseMIT
keywords decimal numeric postgres precision
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            
# always-decimal

A tiny Python package to safely convert floats, strings, and numbers into [`Decimal`](https://docs.python.org/3/library/decimal.html) objects.  
It solves common headaches when comparing **PostgreSQL `numeric`** values with Python floats by ensuring **consistent `Decimal` values**.

---

## โœจ Features

- ๐Ÿ”’ **Exact conversion** from `float` โ†’ `Decimal` (no hidden rounding).
- โš–๏ธ **Configurable coercion**: set scale, rounding mode, normalize trailing zeros.
- ๐Ÿงฉ Works with `float`, `int`, `str`, or `Decimal`.
- ๐Ÿ›ก๏ธ Raises clear `DecimalCoercionError` on invalid inputs.
- ๐Ÿ Compatible with Python **3.10+**.
- ๐Ÿ“ฆ Easy install via **uv** or **pip**.

---

## ๐Ÿ“ฆ Installation

### Using [uv](https://github.com/astral-sh/uv) (recommended)

```bash
uv add always-decimal
````

### Using pip

```bash
pip install always-decimal
```

For local development:

```bash
uv pip install -e ".[dev]"
# or
pip install -e ".[dev]"
```

---

## ๐Ÿš€ Usage

```python
from always_decimal import ensure_decimal, to_decimal_exact

# 1. Exact conversion: no rounding, no scale changes
d1 = to_decimal_exact(0.1)
print(d1)
# Decimal('0.1000000000000000055511151231257827021181583404541015625')

# 2. Safe coercion with fixed scale
price = ensure_decimal(19.995, scale=2)
print(price)
# Decimal('20.00')  (ROUND_HALF_EVEN default)

# 3. String input with quantization
val = ensure_decimal("1.2345", scale=3)
print(val)
# Decimal('1.235')

# 4. Normalizing (remove trailing zeros)
norm = ensure_decimal("1.2300", scale=4, normalize=True)
print(norm)
# Decimal('1.23')
```

---

## โš™๏ธ API

### `to_decimal_exact(value: float | Decimal) -> Decimal`

Convert a `float` or `Decimal` to a `Decimal` **exactly**:

* `float` โ†’ `Decimal.from_float(value)`
* `Decimal` โ†’ returned as-is
  Raises `TypeError` for other types.

### `ensure_decimal(value, *, scale=None, rounding=ROUND_HALF_EVEN, clamp_exp=True, normalize=False) -> Decimal`

Convert and coerce input to `Decimal`.

* **scale**: number of fractional digits to quantize (e.g., 2 โ†’ cents).
* **rounding**: rounding mode (default: bankers rounding).
* **clamp\_exp**: clamp exponents to context limits.
* **normalize**: trim trailing zeros.

---

## ๐Ÿงช Running Tests

```bash
make test
```

or directly:

```bash
pytest
```

---

## ๐Ÿ“„ License

[MIT](LICENSE)

---

## ๐Ÿ™Œ Contributing

Issues and PRs are welcome!
Please format with `ruff`, type-check with `mypy`, and run `pytest` before submitting.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "always-decimal",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "decimal, numeric, postgres, precision",
    "author": "Utkarsh Singh",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/dc/a8/1a8a5ecb05cdbb6d13562f7a21a80d7c92ae4fb14cc8892dc3491e5828eb/always_decimal-1.0.1.tar.gz",
    "platform": null,
    "description": "\n# always-decimal\n\nA tiny Python package to safely convert floats, strings, and numbers into [`Decimal`](https://docs.python.org/3/library/decimal.html) objects.  \nIt solves common headaches when comparing **PostgreSQL `numeric`** values with Python floats by ensuring **consistent `Decimal` values**.\n\n---\n\n## \u2728 Features\n\n- \ud83d\udd12 **Exact conversion** from `float` \u2192 `Decimal` (no hidden rounding).\n- \u2696\ufe0f **Configurable coercion**: set scale, rounding mode, normalize trailing zeros.\n- \ud83e\udde9 Works with `float`, `int`, `str`, or `Decimal`.\n- \ud83d\udee1\ufe0f Raises clear `DecimalCoercionError` on invalid inputs.\n- \ud83d\udc0d Compatible with Python **3.10+**.\n- \ud83d\udce6 Easy install via **uv** or **pip**.\n\n---\n\n## \ud83d\udce6 Installation\n\n### Using [uv](https://github.com/astral-sh/uv) (recommended)\n\n```bash\nuv add always-decimal\n````\n\n### Using pip\n\n```bash\npip install always-decimal\n```\n\nFor local development:\n\n```bash\nuv pip install -e \".[dev]\"\n# or\npip install -e \".[dev]\"\n```\n\n---\n\n## \ud83d\ude80 Usage\n\n```python\nfrom always_decimal import ensure_decimal, to_decimal_exact\n\n# 1. Exact conversion: no rounding, no scale changes\nd1 = to_decimal_exact(0.1)\nprint(d1)\n# Decimal('0.1000000000000000055511151231257827021181583404541015625')\n\n# 2. Safe coercion with fixed scale\nprice = ensure_decimal(19.995, scale=2)\nprint(price)\n# Decimal('20.00')  (ROUND_HALF_EVEN default)\n\n# 3. String input with quantization\nval = ensure_decimal(\"1.2345\", scale=3)\nprint(val)\n# Decimal('1.235')\n\n# 4. Normalizing (remove trailing zeros)\nnorm = ensure_decimal(\"1.2300\", scale=4, normalize=True)\nprint(norm)\n# Decimal('1.23')\n```\n\n---\n\n## \u2699\ufe0f API\n\n### `to_decimal_exact(value: float | Decimal) -> Decimal`\n\nConvert a `float` or `Decimal` to a `Decimal` **exactly**:\n\n* `float` \u2192 `Decimal.from_float(value)`\n* `Decimal` \u2192 returned as-is\n  Raises `TypeError` for other types.\n\n### `ensure_decimal(value, *, scale=None, rounding=ROUND_HALF_EVEN, clamp_exp=True, normalize=False) -> Decimal`\n\nConvert and coerce input to `Decimal`.\n\n* **scale**: number of fractional digits to quantize (e.g., 2 \u2192 cents).\n* **rounding**: rounding mode (default: bankers rounding).\n* **clamp\\_exp**: clamp exponents to context limits.\n* **normalize**: trim trailing zeros.\n\n---\n\n## \ud83e\uddea Running Tests\n\n```bash\nmake test\n```\n\nor directly:\n\n```bash\npytest\n```\n\n---\n\n## \ud83d\udcc4 License\n\n[MIT](LICENSE)\n\n---\n\n## \ud83d\ude4c Contributing\n\nIssues and PRs are welcome!\nPlease format with `ruff`, type-check with `mypy`, and run `pytest` before submitting.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Coerce floats/strings/Decimals to Decimal with predictable scale and rounding.",
    "version": "1.0.1",
    "project_urls": null,
    "split_keywords": [
        "decimal",
        " numeric",
        " postgres",
        " precision"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "673665fcb697d0d6898486529fe0409a92f33e1279cfad35a2b392fb5f97a26d",
                "md5": "767116f0e7f29797e981cbf7d0be06e9",
                "sha256": "bf606e7ba2dba22dbe82381d3a0ded9041328580b9adc3d7ceff22c18202a42a"
            },
            "downloads": -1,
            "filename": "always_decimal-1.0.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "767116f0e7f29797e981cbf7d0be06e9",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 4824,
            "upload_time": "2025-08-20T00:38:48",
            "upload_time_iso_8601": "2025-08-20T00:38:48.432535Z",
            "url": "https://files.pythonhosted.org/packages/67/36/65fcb697d0d6898486529fe0409a92f33e1279cfad35a2b392fb5f97a26d/always_decimal-1.0.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "dca81a8a5ecb05cdbb6d13562f7a21a80d7c92ae4fb14cc8892dc3491e5828eb",
                "md5": "e6426629bd892e51511189b6f548f31d",
                "sha256": "850eaafc53b02cc2c98359e9fdd6753b18e15b91f4f7cac6b59f76ca88d1cf62"
            },
            "downloads": -1,
            "filename": "always_decimal-1.0.1.tar.gz",
            "has_sig": false,
            "md5_digest": "e6426629bd892e51511189b6f548f31d",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 39340,
            "upload_time": "2025-08-20T00:38:49",
            "upload_time_iso_8601": "2025-08-20T00:38:49.673987Z",
            "url": "https://files.pythonhosted.org/packages/dc/a8/1a8a5ecb05cdbb6d13562f7a21a80d7c92ae4fb14cc8892dc3491e5828eb/always_decimal-1.0.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-20 00:38:49",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "always-decimal"
}
        
Elapsed time: 1.73696s