{"id":18604251,"url":"https://github.com/tgalal/microbus","last_synced_at":"2025-04-10T19:32:05.770Z","repository":{"id":57441421,"uuid":"119023721","full_name":"tgalal/microbus","owner":"tgalal","description":" A simple independent data carrying mechanism across different stages of a pipeline design or similar","archived":false,"fork":false,"pushed_at":"2018-01-31T20:44:03.000Z","size":22,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-25T03:41:30.116Z","etag":null,"topics":["bus","data","pipeline","transport","workflow"],"latest_commit_sha":null,"homepage":"","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/tgalal.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-01-26T08:05:36.000Z","updated_at":"2021-12-22T07:22:07.000Z","dependencies_parsed_at":"2022-09-06T02:21:25.121Z","dependency_job_id":null,"html_url":"https://github.com/tgalal/microbus","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tgalal%2Fmicrobus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tgalal%2Fmicrobus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tgalal%2Fmicrobus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tgalal%2Fmicrobus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tgalal","download_url":"https://codeload.github.com/tgalal/microbus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248281415,"owners_count":21077423,"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":["bus","data","pipeline","transport","workflow"],"created_at":"2024-11-07T02:17:11.755Z","updated_at":"2025-04-10T19:32:03.928Z","avatar_url":"https://github.com/tgalal.png","language":"Python","readme":"# microbus\n\nA bus transports passengers (data) across a route. A route consists of 1 or more stops.\nIn each stop, passengers unboard, and then waiting passengers board the bus.\n\n## Why\n\nFor cases where something like a [Pipeline](https://en.wikipedia.org/wiki/Pipeline_(computing)) design is in use, microbus could serve as an independent, detached data carrying mechanism across the different stages of the pipeline. A BusRoute maps to stages within a Pipeline, a processing stage is a BusStop, and the bus carries data from/to different stages/stops in pipeline route\n\nNote that this is not a pipeline creation framework. This is just a data carrying mechanism across stages of an existing pipeline model or similar.\n\n\n## Installation\n\n```bash\npip install microbus\n```\n\n## Definitions\n\n### BusStop\n\nPassengers wait at a bus stop. When a bus reaches the stop, passengers on the bus will exit, arriving at the stop.\nPassengers already waiting at stop will then board the bus.\n\nA stop can have a callback for handling arriving passengers, and a callback, triggered once there are passengers waiting for the bus.\n\n```python\nstop = BusStop(\n    arriving_passengers_handler=lambda stop, passengers: None,\n    waiting_passengers_callback=lambda stop: None\n)\nstop.wait_for_bus([1,2,3])\n```\n\n### BusRoute\n\nA BusRoute typically consists of 2 or more stops. A bus traversing a route will transit in order at each stop.\nExcept for the first and last stop, in each intermediate stop it will drop boarded passengers then board new ones.\nFor the first stop, it will only board waiting passengers, and in the last stop it will only unboard passengers.\n\n```python\nstop1 = BusStop()\nstop2 = BusStop()\nstop3 = BusStop()\nroute = BusRoute((stop1, stop2, stop3))\n```\n\n### Bus\n\nA Bus is what traverses a BusRoute, where once departed, it should transit at each stop and behave as described\nabove (see [BusRoute](#busroute)).\n\nA Bus cannot depart 2 routes at the same time. It has to either complete departing the route or cancel its trip\nbefore departing a new route.\n\nOnce a bus departs, control is given back to the invoker in form of a generator, where each call to ```next```\nwill traverse to next stop:\n\n```python\n\nbus = Bus()\ntrip = bus.depart(route)\ncurr_stop, remaining_route = next(trip)\ncurr_stop, remaining_route = next(trip)\n```\nYou can continue doing so until it raises StopIteration exception which you'll have to handle\n\n```python\ntry:\n    next(trip)\n    next(trip)\nexcept StopIteration:\n    '''route ended'''\n```\n\nor by manually checking the remaining route length\n\n```python\n_, remaining = next(trip)\nif len(remaining): _, remaining = next(trip)\nif len(remaining): _, remaining = next(trip)\n```\nor by simply iterating:\n```python\nfor stop, remaining_route in bus.depart(route):\n    print(\"Arrived at stop %s, remaining route: %s\" % (stop, remaining_route))\n```\nyou can cancel a trip midway by calling ```trip.close()```\n```python\ntrip = bus.depart(route)\nnext(trip)\ntrip.close()\nbus.depart(route2)\n```\n\n**You must either finish a started trip, or cancel (close) it before attempting to depart a new route, otherwise\nyou get a ```SimultaneousRoutesException```**\n\n\n### Schedulers\n\n#### BusScheduler\n\nThrough a ```BusScheduler``` you can safely schedule multiple routes for a bus as you wish. The scheduler will\ntake care of completing a scheduled route and jump to next scheduled one if/when scheduled.\n\n```python\nscheduler = BusScheduler(bus)\nscheduler.schedule(route1)\nscheduler.schedule(route2)\nscheduler.run()\n```\nThe bus will depart all scheduled routes in the same thread where the scheduler's ```run``` method has been called.\n\nSince running a scheduler will block the invoking thread, it might make sense\nto run it in background. Of course this depends on your use case, for example whether you have an existing event loop.\n\n\n```python\nimport threading\n\nscheduler = BusScheduler(bus)\nthreading.Thread(target=scheduler.run).start()\n\nscheduler.schedule(route1)\nscheduler.schedule(route2)\nscheduler.schedule(route3)\n```\n\n#### DisjointRoutesBusScheduler\n\nA ```DisjointRoutesBusScheduler``` has a similar API to BusScheduler. The only difference is that the disjoint scheduler\nwill not schedule routes that are either:\n- Already scheduled and not yet departed\n- A subset of the route the bus is currently traversing, where the bus hasn't reached yet the first stop of that subset.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftgalal%2Fmicrobus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftgalal%2Fmicrobus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftgalal%2Fmicrobus/lists"}