{"id":17970876,"url":"https://github.com/achadha235/rxflow","last_synced_at":"2025-10-26T13:18:34.291Z","repository":{"id":150997420,"uuid":"539195769","full_name":"achadha235/rxflow","owner":"achadha235","description":"minimal reactive state management in Python","archived":false,"fork":false,"pushed_at":"2022-09-20T21:21:56.000Z","size":1669,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-11T03:08:46.954Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/achadha235.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-20T21:19:40.000Z","updated_at":"2024-01-12T04:50:21.000Z","dependencies_parsed_at":"2023-04-14T09:36:45.400Z","dependency_job_id":null,"html_url":"https://github.com/achadha235/rxflow","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achadha235%2Frxflow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achadha235%2Frxflow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achadha235%2Frxflow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achadha235%2Frxflow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/achadha235","download_url":"https://codeload.github.com/achadha235/rxflow/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247086024,"owners_count":20881160,"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":[],"created_at":"2024-10-29T15:35:26.872Z","updated_at":"2025-10-26T13:18:29.240Z","avatar_url":"https://github.com/achadha235.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rxflow\n\n## Introduction\n\nrxflow is minimalistic library for reactive state management in Python. It is inspired by derivablejs\n\n## Features\n\n- **Small, no dependencies** - Only 16KB of bytes of pure Pythonic goodness.\n\n- **Push-pull change propagation** - Elements are observable and can send change notifications (push). Consumers can then lazily evaluate or dereference the changed element as needed (pull). This approach balances the amount of information in updates with the amount of computation triggered automatically on a variable changing.\n\n- **Glitch-free** - Python evaluates from left to right producing a determinstic and glitch-free execution.\n\n## Installation\n\nInstall rxflow by running:\n\n    pip install rxflow\n\n## Background and Motivation\n\n\u003e In computing, reactive programming is a declarative programming\n\u003e paradigm concerned with data streams and the propagation of change\n\u003e (Wikipedia)\n\nIn an imperative programming language like Python a variable assignment like `c = a * b` is instantaneous. `a` and `b` can be modified immediately after without affecting `c`\n\n```py\n\u003e\u003e\u003e a = 10\n\u003e\u003e\u003e b = 5\n\u003e\u003e\u003e c = a * b\n\u003e\u003e\u003e print(c)\n50\n\u003e\u003e\u003e b = 10\n\u003e\u003e\u003e print(c) ## This will still be 50\n50\n\u003e\u003e\u003e\n```\n\nProcedural programming is a sensible default because it allows us to make many simplifying assumptions about variable naming and reuse. However, there are other cases where we may prefer that `c` updates dynamically based on the latest values of `a` and `b`. In other words, we want `c` to be **\"reactive\"** to `a` and `b`.\n\nA spreadsheet is essentially a reactive programming interface because we can set some cell $X$ based on the value of one or more another cells $Y1..YN$ and any updates to $Y1..YN$ would automatically propagate to $X$. Both spreadsheets and reactive programming work well for use cases where we need to model lots of variables linked through a complex system of relationships. Solving such tasks procedurally is cumbersome and produces code that is difficult to reason about. rxflow is designed to brige this gap.\n\n### Basic Example\n\n```py\n\u003e\u003e\u003e from rxflow import Var, Fn, Val\n\u003e\u003e\u003e a = Var(10)\n\u003e\u003e\u003e b = Var(5)\n\u003e\u003e\u003e c = Fn(lambda a, b: a * b, a=a, b=b)\n\u003e\u003e\u003e print(Val(c))\n50\n\u003e\u003e\u003e b(10)\n\u003e\u003e\u003e print(Val(c))  ## This will be 100 because b has changed\n100\n\u003e\u003e\u003e\n```\n\n## Semantics\n\n- There are 3 basic types of elements `Var` (variable), `Fn` (function) and `Seq` (sequence)\n- A `Var` is the most basic type of element. A `Var` can be **created, updated** and **dereferenced**\n\n  ```py\n  from rxflow import Var, Val\n\n  ## Create a Var\n  pi = Var(3.1)\n  print(pi)\n  ## \u003e\u003e Var(3.1)\n\n  ## Dereference a Var\n  curr_pi = Val(pi)\n  print(curr_pi)\n  ## \u003e\u003e 3.1\n\n  ## Dereference a Var\n  pi(3.1415926535)\n  print(Val(pi))\n  ## \u003e\u003e 3.1415926535\n\n  ```\n\n- A `Fn` is a value that is derived from other elements. A `Fn` can be **created** and it's value can be **evaluated**\n\n  ```py\n  from rxflow import Var, Fn, Val\n\n  pi = Var(3.141592)\n  r = Var(42)\n\n  ## Create a Fn from 2 Vars\n  area = Fn(lambda pi, r: pi * pow(r, 2), pi=pi, r=r)\n\n  ## Evaluate a Fn\n  print(Val(area))\n  ## \u003e\u003e 5541.768288\n\n  ## Update one of the vars\n  r(2048)\n\n  print(Val(area))\n  ## \u003e\u003e 13176791.891968\n  ```\n\n- A `Seq` is a sequence of values that are derived from other elements. A `Seq` can be **created** and it's values can be **accessed** by evaluating the generator.\n\n  ```py\n  from rxflow import Var, Seq\n\n  def fibber(N, fib0, fib1):\n      def fibbr(n):\n          if n == 0:\n              return fib0\n          elif n == 1:\n              return fib1\n          else:\n              return N[n - 1] + N[n - 2]\n      return fibbr\n\n  f0 = Var(0)\n  f1 = Var(1)\n  fib = Seq(fibber, fib0=f0, fib1=f1)\n\n  print(fib[5])\n  ## \u003e\u003e 5\n\n  print(fib[8])\n  ## \u003e\u003e 21\n\n  print(fib[2])\n  ## \u003e\u003e 16\n\n  f0(15)\n\n  print(fib[2])\n  ## \u003e\u003e 16\n\n  ```\n\n  - **create** a `Seq` by calling `Seq(generator, **kwargs)`\n\n    - `generator` is a function that takes `N: Seq, **args` and returns another function that accepts a single int `n` and returns the nth value in the sequence\n    - `**kwargs` are the named arguments of type (`Union[Var,Fn,Seq]`) that will be passed to the generator\n\n  - **access the elements** of a `Seq` e.g. `my_seq[42]`\n\n## Contribute\n\n- Issue Tracker: https://github.com/achadha235/rxflow/issues\n- Source Code: https://github.com/achadha235/rxflow\n\n## Support\n\nIf you are having issues, please let us know.\nWe have a mailing list located at: reactivepython@google-groups.com\n\n## License\n\nThe project is licensed under the BSD license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fachadha235%2Frxflow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fachadha235%2Frxflow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fachadha235%2Frxflow/lists"}