threadx


Namethreadx JSON
Version 0.1.0a2 PyPI version JSON
download
home_pageNone
SummaryChaining function calls on steroids
upload_time2024-09-22 04:10:11
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseNone
keywords chain chaining clojure compose functions data transformation function chaining functional programming pipe pipeline threading
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            **threadx** - Create elegant data transformation pipelines.
It lets you thread values through a sequence of operations with a sense of clarity and simplicity that feels natural. And it all revolves around two key elements:
- **thread**: Passes the result of each step as the input to the next.
- **x**: A smart placeholder that knows exactly where to inject the previous result, whether in a method call, item lookup, or even unpacking.

Here’s what it looks like in action:
```python
from threadx import thread, x

thread('./data.log', 
       read_file, 
       x.splitlines, 
       (map, x.strip, x), 
       (map, json.loads, x), 
       (map, x['time'], x), 
       sum)
```

What’s happening here? The file content is being read, split, stripped, converted to JSON, and the execution-time summed—all in a linear and readable way. No intermediary variables, no nesting, just the data flowing from one step to the next. <br>

The `data.log` file (generated by [inspector](https://github.com/withjak/inspector)) contains entries like this:
```json
{"time": 12000, "fn": "foo", ...}
{"time": 12345, "fn": "bar", ...}
```

What Makes threadx Interesting?
- **Readable Flow**: Instead of diving into layers of nested calls, you write each transformation as a clear, sequential step. 
- **The `x` Factor**: `x` acts as a placeholder for where the output of the previous step goes. It’s surprisingly flexible, supporting method calls, attribute/item lookups, and more.
- **No Extra Variables**: Avoid the noise of intermediate variables or lambda functions. Your transformations stay clean and minimal.

# Table of Contents
- [Install](#Install)
- [Usage](#Usage)
    - [Pass result as first argument](#Pass-result-as-first-argument)
    - [Pass x as nth argument](#Pass-x-as-nth-argument)
    - [Unpacking arguments](#Unpacking-arguments)
    - [Method call](#Method-call)
    - [Attribute lookup](#Attribute-lookup)
    - [Getting Item And Slicing](#Getting-Item-And-Slicing)
    - [Debugging](#Debugging)
    - [Fewer lambdas](#Fewer-lambdas)
    - [Build data transformation pipeline](#Build-data-transformation-pipeline)
- [Why I Built This](#Why-I-Built-This)


## Install 
```bash
pip install threadx 
```

## Usage

### Import
```python
from threadx import thread, x, stop
```

### Pass result as first argument
`thread` allows you to pass the result of the previous step automatically as the first argument in each new function:
```python
thread([1, 2, 3],  # => [1, 2, 3]
       sum,        # => 6
       str)        # => '6'
```

Or, be explicit about it:
```python
thread([1, 2, 3],
       (sum, x),
       (str, x))
```

### Pass x as nth argument
Want to pass the result into a different argument position? No problem:
```python
thread(10, 
       (range, x, 20, 3),  # same as (range, 20, 3)
       list)               # => [10, 13, 16, 19]

thread(20, 
       (range, 10, x, 3),
       list)               # => [10, 13, 16, 19]

thread(3, 
       (range, 10, 20, x),
       list)               # => [10, 13, 16, 19]
```

### Unpacking arguments 

Unpacking works as usual

```python 
thread([10, 20], 
       (range, *x, 3),     # unpack to (range, 10, 20, 3)
       list)               # => [10, 13, 16, 19]
```

### Method call
Use `x.method_name` for method calls, just like magic.
```python
thread(['a', 'b'], 
       (x.index, 'a'))      # => 0

thread(['a', 'b'], 
       (x.count, 'b'))      # => 1
```

### Attribute lookup
Use `x.attribute_name` to lookup class and instance attributes. 
```python 
thread({'a': 1, 'b': 2},
       x.keys, 
       list)                # => ['a', 'b']

```

### Getting Item And Slicing
```python
data = {'a': {'b': [1, 2, 3, 4]}}

thread(data, 
       x['a'], 
       x['b'][0])                   # => 1

thread(data, 
       x['a']['b'][:2])             # => [1, 2]

```

### Debugging 
Easily inspect intermediate results using `stop`. Usefull for debugging.
```python
thread(data, 
       x['a'], 
       x['b'], 
       stop,                    # => [1, 2, 3, 4], Stop and return for inspection
       sum,                     # This won’t be executed
       str)

```

### Fewer lambdas
Remove verbose lambdas in **simple cases**.
```python 
data = [[1, 2, 3, 4], [10, 20, 30, 40]]

# Normal way:
thread(data, 
       (map, lambda i: i[0], x), 
       list)                                   # => [1, 10]
# or
thread(data, 
       (map, x[0], x), 
       list)                                   # => [1, 10]


# Normal way:
thread(range(12), 
       (filter, lambda i: i % 2 == 0, x), 
       list)                                   # => [0, 2, 4, 6, 8, 10]
# or
thread(range(12), 
       (filter, x % 2 == 0, x), 
       list)                                   # => [0, 2, 4, 6, 8, 10]
```

### Build data transformation pipeline
```python
# make a tuple or list
pipeline = (read_file, 
            x.splitlines, 
            (map, x.strip, x), 
            (map, json.loads, x), 
            (map, x['time'], x), 
            sum)

thread('./data.log', *pipeline)  # works jsut like any other function.
```

## Why I Built This
After spending a few years working with Clojure, I found myself missing its threading macros when I returned to Python (for a side project). Sure, Python has some tools for chaining operations, but nothing quite as elegant or powerful as what I was used to.







            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "threadx",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "chain, chaining, clojure, compose functions, data transformation, function chaining, functional programming, pipe, pipeline, threading",
    "author": null,
    "author_email": "Akshay Patel <akshaybishnoi@protonmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/81/81/90d6c8f24e5d4a64c3866bc05cf821d946358b25e3e3da09809a9d4633bb/threadx-0.1.0a2.tar.gz",
    "platform": null,
    "description": "**threadx** - Create elegant data transformation pipelines.\nIt lets you thread values through a sequence of operations with a sense of clarity and simplicity that feels natural. And it all revolves around two key elements:\n- **thread**: Passes the result of each step as the input to the next.\n- **x**: A smart placeholder that knows exactly where to inject the previous result, whether in a method call, item lookup, or even unpacking.\n\nHere\u2019s what it looks like in action:\n```python\nfrom threadx import thread, x\n\nthread('./data.log', \n       read_file, \n       x.splitlines, \n       (map, x.strip, x), \n       (map, json.loads, x), \n       (map, x['time'], x), \n       sum)\n```\n\nWhat\u2019s happening here? The file content is being read, split, stripped, converted to JSON, and the execution-time summed\u2014all in a linear and readable way. No intermediary variables, no nesting, just the data flowing from one step to the next. <br>\n\nThe `data.log` file (generated by [inspector](https://github.com/withjak/inspector)) contains entries like this:\n```json\n{\"time\": 12000, \"fn\": \"foo\", ...}\n{\"time\": 12345, \"fn\": \"bar\", ...}\n```\n\nWhat Makes threadx Interesting?\n- **Readable Flow**: Instead of diving into layers of nested calls, you write each transformation as a clear, sequential step. \n- **The `x` Factor**: `x` acts as a placeholder for where the output of the previous step goes. It\u2019s surprisingly flexible, supporting method calls, attribute/item lookups, and more.\n- **No Extra Variables**: Avoid the noise of intermediate variables or lambda functions. Your transformations stay clean and minimal.\n\n# Table of Contents\n- [Install](#Install)\n- [Usage](#Usage)\n    - [Pass result as first argument](#Pass-result-as-first-argument)\n    - [Pass x as nth argument](#Pass-x-as-nth-argument)\n    - [Unpacking arguments](#Unpacking-arguments)\n    - [Method call](#Method-call)\n    - [Attribute lookup](#Attribute-lookup)\n    - [Getting Item And Slicing](#Getting-Item-And-Slicing)\n    - [Debugging](#Debugging)\n    - [Fewer lambdas](#Fewer-lambdas)\n    - [Build data transformation pipeline](#Build-data-transformation-pipeline)\n- [Why I Built This](#Why-I-Built-This)\n\n\n## Install \n```bash\npip install threadx \n```\n\n## Usage\n\n### Import\n```python\nfrom threadx import thread, x, stop\n```\n\n### Pass result as first argument\n`thread` allows you to pass the result of the previous step automatically as the first argument in each new function:\n```python\nthread([1, 2, 3],  # => [1, 2, 3]\n       sum,        # => 6\n       str)        # => '6'\n```\n\nOr, be explicit about it:\n```python\nthread([1, 2, 3],\n       (sum, x),\n       (str, x))\n```\n\n### Pass x as nth argument\nWant to pass the result into a different argument position? No problem:\n```python\nthread(10, \n       (range, x, 20, 3),  # same as (range, 20, 3)\n       list)               # => [10, 13, 16, 19]\n\nthread(20, \n       (range, 10, x, 3),\n       list)               # => [10, 13, 16, 19]\n\nthread(3, \n       (range, 10, 20, x),\n       list)               # => [10, 13, 16, 19]\n```\n\n### Unpacking arguments \n\nUnpacking works as usual\n\n```python \nthread([10, 20], \n       (range, *x, 3),     # unpack to (range, 10, 20, 3)\n       list)               # => [10, 13, 16, 19]\n```\n\n### Method call\nUse `x.method_name` for method calls, just like magic.\n```python\nthread(['a', 'b'], \n       (x.index, 'a'))      # => 0\n\nthread(['a', 'b'], \n       (x.count, 'b'))      # => 1\n```\n\n### Attribute lookup\nUse `x.attribute_name` to lookup class and instance attributes. \n```python \nthread({'a': 1, 'b': 2},\n       x.keys, \n       list)                # => ['a', 'b']\n\n```\n\n### Getting Item And Slicing\n```python\ndata = {'a': {'b': [1, 2, 3, 4]}}\n\nthread(data, \n       x['a'], \n       x['b'][0])                   # => 1\n\nthread(data, \n       x['a']['b'][:2])             # => [1, 2]\n\n```\n\n### Debugging \nEasily inspect intermediate results using `stop`. Usefull for debugging.\n```python\nthread(data, \n       x['a'], \n       x['b'], \n       stop,                    # => [1, 2, 3, 4], Stop and return for inspection\n       sum,                     # This won\u2019t be executed\n       str)\n\n```\n\n### Fewer lambdas\nRemove verbose lambdas in **simple cases**.\n```python \ndata = [[1, 2, 3, 4], [10, 20, 30, 40]]\n\n# Normal way:\nthread(data, \n       (map, lambda i: i[0], x), \n       list)                                   # => [1, 10]\n# or\nthread(data, \n       (map, x[0], x), \n       list)                                   # => [1, 10]\n\n\n# Normal way:\nthread(range(12), \n       (filter, lambda i: i % 2 == 0, x), \n       list)                                   # => [0, 2, 4, 6, 8, 10]\n# or\nthread(range(12), \n       (filter, x % 2 == 0, x), \n       list)                                   # => [0, 2, 4, 6, 8, 10]\n```\n\n### Build data transformation pipeline\n```python\n# make a tuple or list\npipeline = (read_file, \n            x.splitlines, \n            (map, x.strip, x), \n            (map, json.loads, x), \n            (map, x['time'], x), \n            sum)\n\nthread('./data.log', *pipeline)  # works jsut like any other function.\n```\n\n## Why I Built This\nAfter spending a few years working with Clojure, I found myself missing its threading macros when I returned to Python (for a side project). Sure, Python has some tools for chaining operations, but nothing quite as elegant or powerful as what I was used to.\n\n\n\n\n\n\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Chaining function calls on steroids",
    "version": "0.1.0a2",
    "project_urls": {
        "Homepage": "https://github.com/withjak/threadx",
        "Issues": "https://github.com/withjak/threadx/issues"
    },
    "split_keywords": [
        "chain",
        " chaining",
        " clojure",
        " compose functions",
        " data transformation",
        " function chaining",
        " functional programming",
        " pipe",
        " pipeline",
        " threading"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "a0c71eb18906570d0257e3d618e828b1711a273b20461d5304f219cbada79116",
                "md5": "33ed041a65be603857809ef8e03852b3",
                "sha256": "248567afc95d7d01aa3557ee7235bbd26df6d91fbaf45e2fc85193dbb7e92a28"
            },
            "downloads": -1,
            "filename": "threadx-0.1.0a2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "33ed041a65be603857809ef8e03852b3",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 9860,
            "upload_time": "2024-09-22T04:10:10",
            "upload_time_iso_8601": "2024-09-22T04:10:10.200179Z",
            "url": "https://files.pythonhosted.org/packages/a0/c7/1eb18906570d0257e3d618e828b1711a273b20461d5304f219cbada79116/threadx-0.1.0a2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "818190d6c8f24e5d4a64c3866bc05cf821d946358b25e3e3da09809a9d4633bb",
                "md5": "148203a4cabe3be1c56e08a32b70f524",
                "sha256": "5728d4716092c02efec166466b3c6d2940ceb1086ef8c986b0fe1828a7956038"
            },
            "downloads": -1,
            "filename": "threadx-0.1.0a2.tar.gz",
            "has_sig": false,
            "md5_digest": "148203a4cabe3be1c56e08a32b70f524",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 10739,
            "upload_time": "2024-09-22T04:10:11",
            "upload_time_iso_8601": "2024-09-22T04:10:11.913933Z",
            "url": "https://files.pythonhosted.org/packages/81/81/90d6c8f24e5d4a64c3866bc05cf821d946358b25e3e3da09809a9d4633bb/threadx-0.1.0a2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-09-22 04:10:11",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "withjak",
    "github_project": "threadx",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "threadx"
}
        
Elapsed time: 0.71519s