{"id":19097287,"url":"https://github.com/lycantropos/lz","last_synced_at":"2025-04-30T14:30:15.252Z","repository":{"id":57438929,"uuid":"132186508","full_name":"lycantropos/lz","owner":"lycantropos","description":"Functional utilities","archived":false,"fork":false,"pushed_at":"2023-02-23T23:36:37.000Z","size":511,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-13T11:18:20.930Z","etag":null,"topics":["currying","functional-programming","lazy-evaluation"],"latest_commit_sha":null,"homepage":"https://lz.readthedocs.io","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lycantropos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-05-04T20:33:42.000Z","updated_at":"2023-02-07T23:12:21.000Z","dependencies_parsed_at":"2022-09-11T12:43:06.793Z","dependency_job_id":null,"html_url":"https://github.com/lycantropos/lz","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lycantropos%2Flz","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lycantropos%2Flz/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lycantropos%2Flz/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lycantropos%2Flz/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lycantropos","download_url":"https://codeload.github.com/lycantropos/lz/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251721368,"owners_count":21632825,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["currying","functional-programming","lazy-evaluation"],"created_at":"2024-11-09T03:39:48.181Z","updated_at":"2025-04-30T14:30:15.213Z","avatar_url":"https://github.com/lycantropos.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"lz\n==\n\n[![](https://github.com/lycantropos/lz/workflows/CI/badge.svg)](https://github.com/lycantropos/lz/actions/workflows/ci.yml \"Github Actions\")\n[![](https://codecov.io/gh/lycantropos/lz/branch/master/graph/badge.svg)](https://codecov.io/gh/lycantropos/lz \"Codecov\")\n[![](https://readthedocs.org/projects/lz/badge/?version=latest)](https://lz.readthedocs.io/en/latest \"Documentation\")\n[![](https://img.shields.io/github/license/lycantropos/lz.svg)](https://github.com/lycantropos/lz/blob/master/LICENSE \"License\")\n[![](https://badge.fury.io/py/lz.svg)](https://badge.fury.io/py/lz \"PyPI\")\n\nIn what follows `python` is an alias for `python3.7` or `pypy3.7`\nor any later version (`python3.8`, `pypy3.8` and so on).\n\nInstallation\n------------\n\nInstall the latest `pip` \u0026 `setuptools` packages versions\n```bash\npython -m pip install --upgrade pip setuptools\n```\n\n### User\n\nDownload and install the latest stable version from `PyPI` repository\n```bash\npython -m pip install --upgrade lz\n```\n\n### Developer\n\nDownload the latest version from `GitHub` repository\n```bash\ngit clone https://github.com/lycantropos/lz.git\ncd lz\n```\n\nInstall dependencies\n```bash\npython -m pip install -r requirements.txt\n```\n\nInstall\n```bash\npython setup.py install\n```\n\nUsage \n----- \n \n`lz` provides a bunch of utilities for working with functions, predicates \u0026 iterables such as\n\n1. [function composition](https://en.wikipedia.org/wiki/Function_composition)\n    ```python\n    \u003e\u003e\u003e from lz.functional import compose\n    \u003e\u003e\u003e sum_of_first_n_natural_numbers = compose(sum, range)\n    \u003e\u003e\u003e sum_of_first_n_natural_numbers(10)\n    45\n\n    ```\n\n2. [currying](https://en.wikipedia.org/wiki/Currying)\n    ```python\n    \u003e\u003e\u003e from lz.functional import curry \n    \u003e\u003e\u003e curried_power = curry(pow) \n    \u003e\u003e\u003e two_to_power = curried_power(2) \n    \u003e\u003e\u003e two_to_power(10)\n    1024\n\n    ```\n\n3. flipping positional parameters order\n    ```python\n    \u003e\u003e\u003e from lz.functional import flip\n    \u003e\u003e\u003e flipped_power = flip(pow)\n    \u003e\u003e\u003e flipped_power(2, 3)\n    9\n\n    ```\n\n4. packing function's arguments\n    ```python\n    \u003e\u003e\u003e from lz.functional import pack\n    \u003e\u003e\u003e packed_int = pack(int)\n    \u003e\u003e\u003e packed_int(['10'])\n    10\n    \u003e\u003e\u003e packed_int(['10'], {'base': 2})\n    2\n\n    ```\n\n5. left [partial application](https://en.wikipedia.org/wiki/Partial_application)\n    ```python\n    \u003e\u003e\u003e from lz import left\n    \u003e\u003e\u003e count_from_zero_to = left.applier(range, 0)\n    \u003e\u003e\u003e list(count_from_zero_to(10))\n    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n\n    ```\n\n6. right [partial application](https://en.wikipedia.org/wiki/Partial_application)\n    ```python\n    \u003e\u003e\u003e from lz import right\n    \u003e\u003e\u003e square = right.applier(pow, 2)\n    \u003e\u003e\u003e square(10)\n    100\n\n    ```\n\n7. [negating](https://en.wikipedia.org/wiki/Negation) predicate\n    ```python\n    \u003e\u003e\u003e from lz.logical import negate\n    \u003e\u003e\u003e false_like = negate(bool)\n    \u003e\u003e\u003e false_like([])\n    True\n    \u003e\u003e\u003e false_like([0])\n    False\n\n    ```\n\n8. [conjoining](https://en.wikipedia.org/wiki/Logical_conjunction) predicates\n    ```python\n    \u003e\u003e\u003e from lz.logical import conjoin\n    \u003e\u003e\u003e is_valid_constant_identifier = conjoin(str.isupper, str.isidentifier)\n    \u003e\u003e\u003e is_valid_constant_identifier('SECOND_SECTION')\n    True\n    \u003e\u003e\u003e is_valid_constant_identifier('2ND_SECTION')\n    False\n\n    ```\n\n9. [disjoining](https://en.wikipedia.org/wiki/Logical_disjunction) predicates\n    ```python\n    \u003e\u003e\u003e from lz.logical import disjoin\n    \u003e\u003e\u003e alphabetic_or_numeric = disjoin(str.isalpha, str.isnumeric)\n    \u003e\u003e\u003e alphabetic_or_numeric('Hello')\n    True\n    \u003e\u003e\u003e alphabetic_or_numeric('42')\n    True\n    \u003e\u003e\u003e alphabetic_or_numeric('Hello42')\n    False\n\n    ```\n\n10. [exclusive disjoining](https://en.wikipedia.org/wiki/Exclusive_or) predicates\n    ```python\n    \u003e\u003e\u003e from lz.logical import exclusive_disjoin\n    \u003e\u003e\u003e from keyword import iskeyword\n    \u003e\u003e\u003e valid_object_name = exclusive_disjoin(str.isidentifier, iskeyword)\n    \u003e\u003e\u003e valid_object_name('valid_object_name')\n    True\n    \u003e\u003e\u003e valid_object_name('_')\n    True\n    \u003e\u003e\u003e valid_object_name('1')\n    False\n    \u003e\u003e\u003e valid_object_name('lambda')\n    False\n\n    ```\n\n11. reversing sequences and any string streams\n    ```python\n    \u003e\u003e\u003e from lz.reversal import reverse\n    \u003e\u003e\u003e list(reverse(range(10)))\n    [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]\n    \u003e\u003e\u003e import io\n    \u003e\u003e\u003e list(reverse(io.BytesIO(b'Hello\\nWorld!')))\n    [b'World!', b'Hello\\n']\n\n    ```\n\n12. chunking iterable\n    ```python\n    \u003e\u003e\u003e from lz.iterating import chopper\n    \u003e\u003e\u003e to_triplets = chopper(3)\n    \u003e\u003e\u003e list(map(tuple, to_triplets(range(10))))\n    [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9,)]\n\n    ```\n\n13. sliding over iterable\n    ```python\n    \u003e\u003e\u003e from lz.iterating import slider\n    \u003e\u003e\u003e slide_pairwise = slider(2)\n    \u003e\u003e\u003e list(slide_pairwise(range(10)))\n    [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9)]\n \n    ```\n\n14. [interleaving](https://en.wikipedia.org/wiki/Interleave_sequence) iterables\n    ```python\n    \u003e\u003e\u003e from lz.iterating import interleave\n    \u003e\u003e\u003e list(interleave([range(10), range(10, 20)]))\n    [0, 10, 1, 11, 2, 12, 3, 13, 4, 14, 5, 15, 6, 16, 7, 17, 8, 18, 9, 19]\n  \n    ```\n\n15. iterable [transposition](https://en.wikipedia.org/wiki/Transpose)\n    ```python\n    \u003e\u003e\u003e from lz.transposition import transpose\n    \u003e\u003e\u003e list(map(tuple, transpose(zip(range(10), range(10, 20)))))\n    [(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), (10, 11, 12, 13, 14, 15, 16, 17, 18, 19)]\n \n    ```\n\n16. iterable duplication\n    ```python\n    \u003e\u003e\u003e from lz.replication import duplicate\n    \u003e\u003e\u003e list(map(tuple, duplicate(range(10))))\n    [(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)]\n  \n    ```\n\nand [many more](https://lz.readthedocs.io/en/latest).\n\nDevelopment\n-----------\n\n### Building docs\n\nInstall project in editable mode\n```bash\npython -m pip install -e .\n```\n\nInstall dependencies\n```bash\npython -m pip install -r docs/requirements.txt\n```\n\nBuild docs\n```bash\ncd docs\nmake html\n```\n\n### Bumping version\n\n#### Preparation\n\nInstall\n[bump2version](https://github.com/c4urself/bump2version#installation).\n\n#### Pre-release\n\nChoose which version number category to bump following [semver\nspecification](http://semver.org/).\n\nTest bumping version\n```bash\nbump2version --dry-run --verbose $CATEGORY\n```\n\nwhere `$CATEGORY` is the target version number category name, possible\nvalues are `patch`/`minor`/`major`.\n\nBump version\n```bash\nbump2version --verbose $CATEGORY\n```\n\nThis will set version to `major.minor.patch-alpha`. \n\n#### Release\n\nTest bumping version\n```bash\nbump2version --dry-run --verbose release\n```\n\nBump version\n```bash\nbump2version --verbose release\n```\n\nThis will set version to `major.minor.patch`.\n\n### Running tests\n\nInstall dependencies\n```bash\npython -m pip install -r requirements-tests.txt\n```\n\nPlain\n```bash\npytest\n```\n\nInside `Docker` container:\n- with `CPython`\n  ```bash\n  docker-compose --file docker-compose.cpython.yml up\n  ```\n- with `PyPy`\n  ```bash\n  docker-compose --file docker-compose.pypy.yml up\n  ```\n\n`Bash` script (e.g. can be used in `Git` hooks):\n- with `CPython`\n  ```bash\n  ./run-tests.sh\n  ```\n  or\n  ```bash\n  ./run-tests.sh cpython\n  ```\n\n- with `PyPy`\n  ```bash\n  ./run-tests.sh pypy\n  ```\n\n`PowerShell` script (e.g. can be used in `Git` hooks):\n- with `CPython`\n  ```powershell\n  .\\run-tests.ps1\n  ```\n  or\n  ```powershell\n  .\\run-tests.ps1 cpython\n  ```\n- with `PyPy`\n  ```powershell\n  .\\run-tests.ps1 pypy\n  ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flycantropos%2Flz","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flycantropos%2Flz","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flycantropos%2Flz/lists"}