{ "info": { "author": "Daniel Gonz\u00e1lez Lopes", "author_email": "danielgonzalezlopes@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Networking", "Topic :: System :: Systems Administration" ], "description": "# python-liftbridge\n[![PyPI](https://img.shields.io/pypi/v/python-liftbridge.svg)](https://pypi.org/project/python-liftbridge/)\n[![GitHub](https://img.shields.io/github/license/dgzlopes/python-liftbridge)](https://github.com/dgzlopes/python-liftbridge/blob/master/LICENSE.md)\n\nPython client for [Liftbridge](https://github.com/liftbridge-io/liftbridge), a system that provides lightweight, fault-tolerant message streams for [NATS](https://nats.io).\n\nLiftbridge provides the following high-level features:\n\n- Log-based API for NATS\n- Replicated for fault-tolerance\n- Horizontally scalable\n- Wildcard subscription support\n- At-least-once delivery support and message replay\n- Message key-value support\n- Log compaction by key\n\n## Installation\n\n```\n$ pip install python-liftbridge\n```\n\n## Basic Usage\n\n```python\nfrom python_liftbridge import Lift, Message, Stream, ErrStreamExists\n\n# Create a Liftbridge client.\nclient = Lift(ip_address='localhost:9292', timeout=5)\n\n# Create a stream attached to the NATS subject \"foo\".\ntry:\n client.create_stream(Stream(subject='foo', name='foo-stream'))\nexcept ErrStreamExists:\n print('This stream already exists!')\n\n# Publish a message to \"foo\".\nclient.publish(Message(value='hello', subject='foo'))\n\n# Subscribe to the stream starting from the beginning.\nfor message in client.subscribe(\n Stream(\n subject='foo',\n name='foo-stream',\n ).start_at_earliest_received(),\n):\n print(\"Received: '{}'\".format(message.value))\n\n```\n\n### Create Stream\n\n[Streams](https://github.com/liftbridge-io/liftbridge/blob/master/documentation/concepts.md#stream) are a durable message log attached to a NATS subject. They record messages published to the subject for consumption.\n\nStreams have a few key properties: a subject, which is the corresponding NATS subject, a name, which is a human-readable identifier for the stream, and a replication factor, which is the number of nodes the stream should be replicated to for redundancy. Optionally, there is a group which is the name of a load-balance group for the stream to join. When there are multiple streams in the same group, messages will be balanced among them.\n\n```python\n\"\"\"\n Create a stream attached to the NATS subject \"foo.*\" that is replicated to\n all the brokers in the cluster. ErrStreamExists is returned if a stream with\n the given name already exists for the subject.\n\"\"\"\nclient.create_stream(Stream(subject='foo.*', name='my-stream', max_replication=True))\n```\n\n### Subscription Start/Replay Options\n\n[Subscriptions](https://github.com/liftbridge-io/liftbridge/blob/master/documentation/concepts.md#subscription) are how Liftbridge streams are consumed. Clients can choose where to start consuming messages from in a stream. This is controlled using options passed to Subscribe.\n\n```python\n# Subscribe starting with new messages only.\nclient.subscribe(\n Stream(subject='foo', name='foo-stream')\n)\n# Subscribe starting with the most recently published value.\nclient.subscribe(\n Stream(subject='foo', name='foo-stream').start_at_earliest_received()\n)\n# Subscribe starting with the oldest published value.\nclient.subscribe(\n Stream(subject='foo', name='foo-stream').start_at_latest_received()\n)\n# Subscribe starting at a specific offset.\nclient.subscribe(\n Stream(subject='foo', name='foo-stream').start_at_offset(4)\n)\n# Subscribe starting at a specific time.\nclient.subscribe(\n Stream(subject='foo', name='foo-stream').start_at_time(datetime.now())\n)\n# Subscribe starting at a specific amount of time in the past.\nclient.subscribe(\n Stream(subject='foo', name='foo-stream').start_at_time_delta(timedelta(days=1))\n)\n```\n\n### Publishing\n\nA publish API is provided to make it easy to write messages to streams. This includes a number of options for decorating messages with metadata like a message key.\n\nKeys are used by Liftbridge's log compaction. When enabled, Liftbridge streams will retain only the last message for a given key.\n\n```python\n# Publish a message with a key\nclient.publish(Message(subject='foo', value='Hello', key='key'))\n```\n\n#### Publishing Directly with NATS\n\nSince Liftbridge is an extension of [NATS](https://github.com/nats-io/gnatsd), a [NATS client](https://github.com/nats-io/nats.py) can also be used to publish messages. This means existing NATS publishers do not need any changes for messages to be consumed in Liftbridge.\n\n## How to contribute\n1. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug.\n2. Fork [the repository](https://github.com/dgzlopes/python-liftbridge) on GitHub to start making your changes to the master branch (or branch off of it).\n3. Write a test which shows that the bug was fixed or that the feature works as expected.\n4. Send a [pull request](https://help.github.com/en/articles/creating-a-pull-request-from-a-fork) and bug [me](https://github.com/dgzlopes) until it gets merged and published.\n\nSome things on the backlog:\n\n- [ ] Add documentation (Sphynx)\n- [ ] Add CI (CircleCI or TravisCI)\n- [ ] Add tests\n- [ ] Add code coverage\n- [ ] Add TLS support for gRPC\n- [ ] Add message headers support\n- [ ] Add message ACK support (scaffolding is already done)\n- [x] Add method to close connection\n- [ ] Add async client\n- [ ] Add gRPC connection pool\n- [x] Add logging (and remove all the random prints)\n- [ ] Add proper docstrings\n- [x] Add version file\n- [ ] Add Contributing.md and explanation of the workflow (pyenv,tox,make,pre-commit...)\n- [ ] Improve fetch metadata\n- [ ] Improve error handling\n- [x] Add to the makefile run-liftbridge using Docker [container](https://github.com/dgzlopes/liftbridge-docker)\n- [ ] Better instrumentation/observability (OpenCensus support?)\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/dgzlopes/python-liftbridge", "keywords": "", "license": "Apache Software License (Apache License, Version 2.0)", "maintainer": "", "maintainer_email": "", "name": "python-liftbridge", "package_url": "https://pypi.org/project/python-liftbridge/", "platform": "", "project_url": "https://pypi.org/project/python-liftbridge/", "project_urls": { "Homepage": "https://github.com/dgzlopes/python-liftbridge" }, "release_url": "https://pypi.org/project/python-liftbridge/0.0.5/", "requires_dist": [ "grpcio (<2,>=1.23.0)" ], "requires_python": "", "summary": "Python client for Liftbridge.", "version": "0.0.5" }, "last_serial": 5723934, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "748610665f884264f342d1562162dd9a", "sha256": "5fd8c8414657e8e56208f0dded4ade1bf4a6343bd99ec78fcac444a7845ed33c" }, "downloads": -1, "filename": "python_liftbridge-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "748610665f884264f342d1562162dd9a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7541, "upload_time": "2019-08-20T14:27:52", "url": "https://files.pythonhosted.org/packages/51/89/16a975f05e2457db5721c510904f9f1c46fe6d9df366d27defda49a66609/python_liftbridge-0.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3c0d58e9629aa34b8fc7e5e7b6c715f8", "sha256": "febd6f87ffcfb0990a34929906f9bdf2fc58ba3758cccd4dc37217c863ee0489" }, "downloads": -1, "filename": "python-liftbridge-0.0.1.tar.gz", "has_sig": false, "md5_digest": "3c0d58e9629aa34b8fc7e5e7b6c715f8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3664, "upload_time": "2019-08-20T14:27:55", "url": "https://files.pythonhosted.org/packages/82/47/91d27feabb418fccabe16afe808850010db83d4408737dcad703eafedf93/python-liftbridge-0.0.1.tar.gz" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "26a8ce3689fc1514962b94aef7a9f5e7", "sha256": "f42e43dc72e576846de50e9a3f7223af558a548c41af2f5d54bdce9f3255f42f" }, "downloads": -1, "filename": "python_liftbridge-0.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "26a8ce3689fc1514962b94aef7a9f5e7", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7546, "upload_time": "2019-08-20T14:34:55", "url": "https://files.pythonhosted.org/packages/43/bc/ea7df9bcbf622e2fe09176497a8de25bb5980aa341ff43850f108d35ab40/python_liftbridge-0.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "239263a6ce5f42cde13f95bccb08a843", "sha256": "851600043e7176ed5345d1b65043edd8e284083d0e5abde1e04e9f4604f6ab13" }, "downloads": -1, "filename": "python-liftbridge-0.0.2.tar.gz", "has_sig": false, "md5_digest": "239263a6ce5f42cde13f95bccb08a843", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3663, "upload_time": "2019-08-20T14:34:57", "url": "https://files.pythonhosted.org/packages/9f/86/372c316a44a9d1fd7397916488d2d0ed0ee508c4cc59b93ce00926347c80/python-liftbridge-0.0.2.tar.gz" } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "c3aeba89a30b341c8adcbfca4b0e14a4", "sha256": "dbaeb93671fae085f924c52c7d801a0873bda3d67a68396ff6b68820f25eb1b8" }, "downloads": -1, "filename": "python_liftbridge-0.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "c3aeba89a30b341c8adcbfca4b0e14a4", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7552, "upload_time": "2019-08-20T14:40:37", "url": "https://files.pythonhosted.org/packages/a0/6e/c460b883b0b38f20a612a1c1df8bcca5095d42bbdffa5f3167661f286ed8/python_liftbridge-0.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c419b737ed0aa65d0cc9ada0952f1d78", "sha256": "44c837d0d97156deda311302618ba786f3c1a0206350968043adc405a75ce5ae" }, "downloads": -1, "filename": "python-liftbridge-0.0.3.tar.gz", "has_sig": false, "md5_digest": "c419b737ed0aa65d0cc9ada0952f1d78", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3674, "upload_time": "2019-08-20T14:40:39", "url": "https://files.pythonhosted.org/packages/04/fa/3b42dd0db18e9907b03fccc261037790c7507cca427e1a865967a962a6e7/python-liftbridge-0.0.3.tar.gz" } ], "0.0.4": [ { "comment_text": "", "digests": { "md5": "23ff2100f8c46e39e716672cb53051d3", "sha256": "b9c0f0e063f8a3417bae8bad7e2b5698faaae3ca28726fa2c7194d9dc1a9872a" }, "downloads": -1, "filename": "python_liftbridge-0.0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "23ff2100f8c46e39e716672cb53051d3", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7562, "upload_time": "2019-08-23T09:06:38", "url": "https://files.pythonhosted.org/packages/8e/f7/cf33b5ddae2a83504822809da2fffd43acb4d5b97ef38c5d1a23067a2dfd/python_liftbridge-0.0.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f3f82ae1561516473e1e30fd43122510", "sha256": "f369f28c2f988cca08f0b94338b289fab0ab191f1dbffe1bb135f09f53ea3bfe" }, "downloads": -1, "filename": "python-liftbridge-0.0.4.tar.gz", "has_sig": false, "md5_digest": "f3f82ae1561516473e1e30fd43122510", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3688, "upload_time": "2019-08-23T09:06:39", "url": "https://files.pythonhosted.org/packages/c2/b7/ed118d17564de76d34112bd1fd1cf8dae1ae134d415218d06631199b129d/python-liftbridge-0.0.4.tar.gz" } ], "0.0.5": [ { "comment_text": "", "digests": { "md5": "e5fd80241be9c6c0a78be64dbfdf338f", "sha256": "b33253267c29af69522e0d6e7dd1b70b5d05ec9494b75aff3b07e01ee7f24981" }, "downloads": -1, "filename": "python_liftbridge-0.0.5-py3-none-any.whl", "has_sig": false, "md5_digest": "e5fd80241be9c6c0a78be64dbfdf338f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 17904, "upload_time": "2019-08-24T07:54:16", "url": "https://files.pythonhosted.org/packages/e2/99/20177a2fbfcfd2f2dd88900834203f3d1c57684310808c398d9c2d54b8ed/python_liftbridge-0.0.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "92a4929fe704e6571002bba7373b1957", "sha256": "ad07c40a7f6ea0f8daa0ca8f0b2553c353c343c59da348219f23fdaf9eca24f9" }, "downloads": -1, "filename": "python-liftbridge-0.0.5.tar.gz", "has_sig": false, "md5_digest": "92a4929fe704e6571002bba7373b1957", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13812, "upload_time": "2019-08-24T07:54:18", "url": "https://files.pythonhosted.org/packages/17/15/4a6bdff748f23b9d0046fc240d613707eaec3984173317fd9146a4a906e2/python-liftbridge-0.0.5.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "e5fd80241be9c6c0a78be64dbfdf338f", "sha256": "b33253267c29af69522e0d6e7dd1b70b5d05ec9494b75aff3b07e01ee7f24981" }, "downloads": -1, "filename": "python_liftbridge-0.0.5-py3-none-any.whl", "has_sig": false, "md5_digest": "e5fd80241be9c6c0a78be64dbfdf338f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 17904, "upload_time": "2019-08-24T07:54:16", "url": "https://files.pythonhosted.org/packages/e2/99/20177a2fbfcfd2f2dd88900834203f3d1c57684310808c398d9c2d54b8ed/python_liftbridge-0.0.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "92a4929fe704e6571002bba7373b1957", "sha256": "ad07c40a7f6ea0f8daa0ca8f0b2553c353c343c59da348219f23fdaf9eca24f9" }, "downloads": -1, "filename": "python-liftbridge-0.0.5.tar.gz", "has_sig": false, "md5_digest": "92a4929fe704e6571002bba7373b1957", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13812, "upload_time": "2019-08-24T07:54:18", "url": "https://files.pythonhosted.org/packages/17/15/4a6bdff748f23b9d0046fc240d613707eaec3984173317fd9146a4a906e2/python-liftbridge-0.0.5.tar.gz" } ] }