{"id":51177854,"url":"https://github.com/kaierikniermann/result-py","last_synced_at":"2026-06-27T05:01:04.635Z","repository":{"id":323214732,"uuid":"1092500448","full_name":"KaiErikNiermann/result-py","owner":"KaiErikNiermann","description":"Small functional library with strict typing in python 3.14","archived":false,"fork":false,"pushed_at":"2026-02-24T15:25:01.000Z","size":5600,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-24T19:06:52.733Z","etag":null,"topics":["functional-programming","monads","python314","type-safety"],"latest_commit_sha":null,"homepage":"https://kaierikniermann.github.io/result-py/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KaiErikNiermann.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-08T18:35:08.000Z","updated_at":"2026-02-24T15:35:39.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/KaiErikNiermann/result-py","commit_stats":null,"previous_names":["kaierikniermann/effect-py","kaierikniermann/result-py"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/KaiErikNiermann/result-py","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KaiErikNiermann%2Fresult-py","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KaiErikNiermann%2Fresult-py/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KaiErikNiermann%2Fresult-py/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KaiErikNiermann%2Fresult-py/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KaiErikNiermann","download_url":"https://codeload.github.com/KaiErikNiermann/result-py/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KaiErikNiermann%2Fresult-py/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34841990,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-27T02:00:06.362Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["functional-programming","monads","python314","type-safety"],"created_at":"2026-06-27T05:00:48.454Z","updated_at":"2026-06-27T05:01:04.629Z","avatar_url":"https://github.com/KaiErikNiermann.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# result-py\n\nA functional programming library for Python.\n\n## Features\n\n- **Type-Safe Error Handling**: Errors are values, not exceptions. Your type checker knows exactly what can go wrong.\n- **Railway-Oriented Programming**: Chain operations elegantly with `.pipe()` and handle both success and failure paths.\n- **Rich Collection Operations**: `map`, `filter`, `reduce`, `flat_map`, and more—all within the Either context.\n- **Modern Python**: Built for Python 3.14+ with full type annotations and generics.\n- **Functional Composition**: Build complex pipelines from simple, testable functions.\n\n## Installation\n\n```bash\npip install fn-result-py\n```\n\nOr with Poetry:\n\n```bash\npoetry add fn-result-py\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nfrom result_py import Either\n\n# Create success and failure values\nsuccess = Either.right(42)       # Right = success\nfailure = Either.left(\"Error\")   # Left = failure\n\n# Chain operations - failures short-circuit automatically\nresult = (\n    Either.right(10)\n    .pipe(lambda x: x * 2)       # 20\n    .pipe(lambda x: x + 5)       # 25\n)\nprint(result)  # Either(_left=None, _right=25)\n```\n\n### Error Handling Made Explicit\n\n```python\nfrom result_py import Either\n\ndef divide(a: float, b: float) -\u003e Either[str, float]:\n    if b == 0:\n        return Either.left(\"Division by zero!\")\n    return Either.right(a / b)\n\ndef sqrt(x: float) -\u003e Either[str, float]:\n    if x \u003c 0:\n        return Either.left(\"Cannot take sqrt of negative number!\")\n    return Either.right(x ** 0.5)\n\n# Chain operations - first error stops the pipeline\nresult = (\n    Either.right(16.0)\n    .pipe(lambda x: divide(x, 2))   # Right(8.0)\n    .pipe(sqrt)                      # Right(2.83...)\n)\n\n# Handle both cases with match\nmessage = result.match(\n    left=lambda err: f\"Failed: {err}\",\n    right=lambda val: f\"Result: {val:.2f}\"\n)\nprint(message)  # \"Result: 2.83\"\n```\n\n### Working with Collections\n\n```python\nfrom result_py import Either\n\n# Transform collections within Either context\nresult = (\n    Either.right([1, 2, 3, 4, 5])\n    .filter(lambda x: x % 2 == 0)     # [2, 4]\n    .map(lambda x: x * 10)            # [20, 40]\n    .to_list()\n)\nprint(result)  # Either(_left=None, _right=[20, 40])\n\n# Filter and transform in one step\nresult = (\n    Either.right([1, 2, 3, 4, 5])\n    .filter_map(lambda x: x * 2 if x \u003e 2 else None)\n    .to_list()\n)\nprint(result)  # Either(_left=None, _right=[6, 8, 10])\n```\n\n### Wrapping External Code\n\nUse `wrap_external` to safely wrap functions that might throw exceptions:\n\n```python\nfrom result_py import wrap_external\nimport json\n\n# Wrap a function that might raise exceptions\nsafe_json_loads = wrap_external(json.loads, json.JSONDecodeError)\n\nresult = safe_json_loads('{\"valid\": \"json\"}')\nprint(result)  # Either(_left=None, _right={'valid': 'json'})\n\nresult = safe_json_loads('not valid json')\nprint(result)  # Either(_left=JSONDecodeError(...), _right=None)\n```\n\n### Using the `@throws` Decorator\n\nDeclare which exceptions your function might throw, and have them automatically converted to `Either.left`:\n\n```python\nfrom result_py import Either, throws\n\n@throws(ValueError, KeyError)\ndef risky_operation(data: dict, key: str) -\u003e Either[ValueError | KeyError, int]:\n    value = data[key]  # Might raise KeyError\n    if value \u003c 0:\n        raise ValueError(\"Value must be positive\")\n    return Either.right(value * 2)\n\nresult = risky_operation({\"x\": 10}, \"x\")\nprint(result)  # Either(_left=None, _right=20)\n\nresult = risky_operation({}, \"x\")\nprint(result)  # Either(_left=KeyError('x'), _right=None)\n```\n\n## API Reference\n\n### Creating Either Values\n\n| Method | Description |\n|--------|-------------|\n| `Either.right(value)` | Create a success value |\n| `Either.left(error)` | Create a failure value |\n| `Either.success(value)` | Alias for `right` |\n| `Either.failure(error)` | Alias for `left` |\n\n### Transformations\n\n| Method | Description |\n|--------|-------------|\n| `.pipe(f)` | Apply function to right value, supports both `T -\u003e U` and `T -\u003e Either[E, U]` |\n| `.and_then(f)` | Monadic bind: chain `T -\u003e Either[E2, U]` functions (alias-like to pipe for Either-returning fns) |\n| `.map(f)` | Apply function to each item in an iterable |\n| `.map_left(f)` | Transform the left (error) value |\n| `.filter(f)` | Filter items in an iterable |\n| `.filter_map(f)` | Filter and map in one step (None values filtered out) |\n| `.flat_map(f)` | Map and flatten nested iterables |\n| `.flatten()` | Flatten nested iterables |\n\n### Tuple Unpacking Variants\n\n| Method | Description |\n|--------|-------------|\n| `.n_pipe(f)` | Unpack tuple and apply multi-argument function |\n| `.n_map(f)` | Map with tuple unpacking (lazy generator) |\n| `.n_filter_map(f)` | Filter-map with tuple unpacking (lazy generator) |\n\n### Aggregations\n\n| Method | Description |\n|--------|-------------|\n| `.reduce(f, initial)` | Reduce iterable to single value |\n| `.map_reduce(f, initial)` | Map then reduce |\n| `.to_list()` | Convert iterable to list |\n| `.to_set()` | Convert iterable to set |\n| `.to_counter()` | Count occurrences of items |\n\n### Combining \u0026 Matching\n\n| Method | Description |\n|--------|-------------|\n| `.zip(other)` | Combine two Eithers into tuple |\n| `.then(other)` | Chain to next Either if current is Right |\n| `.or_else(f)` | Recover from error with `E -\u003e Either[E2, T]` function |\n| `.match(left, right)` | Pattern match on Left/Right |\n| `.unwrap_or(default)` | Get right value or default |\n\n### Properties\n\n| Property | Description |\n|----------|-------------|\n| `.is_right` | `True` if this is a Right value |\n| `.is_left` | `True` if this is a Left value |\n\n### Utilities\n\n| Method | Description |\n|--------|-------------|\n| `.partition(f)` | Split iterable into two based on predicate |\n| `.to_json()` | Convert right value to JSON string |\n| `.write_json_out(path)` | Write Pydantic model to JSON file |\n| `.ctx_pipe(f)` | Apply side-effect function, keep original value |\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaierikniermann%2Fresult-py","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkaierikniermann%2Fresult-py","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaierikniermann%2Fresult-py/lists"}