{ "info": { "author": "Eliot Berriot", "author_email": "contact@eliotberriot.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 2 - Pre-Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Natural Language :: English", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5" ], "description": "===============================\nWhat is lifter?\n===============================\n\n.. image:: https://img.shields.io/pypi/v/lifter.svg\n :target: https://pypi.python.org/pypi/lifter\n\n.. image:: https://readthedocs.org/projects/lifter/badge/?version=latest\n :target: http://lifter.readthedocs.org/en/latest/?badge=latest\n\n.. image:: https://travis-ci.org/EliotBerriot/lifter.svg?branch=master\n :target: https://travis-ci.org/EliotBerriot/lifter\n\n.. image:: https://travis-ci.org/EliotBerriot/lifter.svg?branch=develop\n :target: https://travis-ci.org/EliotBerriot/lifter\n\n\nLifter is a generic query engine, inspired by Django ORM and SQLAlchemy.\n\nIts goal is to provide a unique interface to query any type of data, regardless of the underlying query language or data backend (SQL, REST, Python objects...).\n\n**Warning**: This package is still in alpha state and a lot of work is still needed to make queries faster and efficient.\nContributions are welcome :)\n\nUseful links:\n\n- Documentation is available at http://lifter.readthedocs.org\n- Ask your programming questions on Stack Overflow using the tag `python-lifter `_\n\nFeatures\n--------\n\n* Queryset API similar to Django_ and SQLAlchemy_\n* Lazy querysets\n* Composable queries\n* Lightweight: very little dependencies\n* Tested and working on Python 2.7 to Python 3.5\n\n.. _Django: https://docs.djangoproject.com/en/1.9/ref/models/querysets/\n.. _SQLAlchemy: http://docs.sqlalchemy.org/en/rel_1_0/orm/tutorial.html#common-filter-operators\n\nExample usage\n-------------\n\nConsider the following list of users, returned from a REST API endpoint:\n\n.. code-block:: python\n\n users = [\n {\n \"is_active\": True,\n \"age\": 35,\n \"eye_color\": \"brown\",\n \"name\": \"Bernard\",\n \"gender\": \"male\",\n \"email\": \"bernard@blackbooks.com\",\n },\n {\n \"is_active\": True,\n \"age\": 34,\n \"eye_color\": \"brown\",\n \"name\": \"Manny\",\n \"gender\": \"male\",\n \"email\": \"manny@blackbooks.com\",\n },\n {\n \"is_active\": True,\n \"age\": 35,\n \"eye_color\": \"brown\",\n \"name\": \"Fran\",\n \"gender\": \"female\",\n \"email\": \"fran@blackbooks.com\",\n },\n # And so on ...\n ]\n\nNow, imagine you have to extract data from this list. Let's compare how you can do this using regular Python\nand lifter.\n\nTo use lifter in your project, you'll only need the following instructions:\n\n.. code-block:: python\n\n import lifter.models\n from lifter.backends.python import IterableStore\n\n class User(lifter.models.Model):\n pass\n\n store = IterableStore(users)\n manager = store.query(User)\n\nGetting all active 26 years old users:\n\n.. code-block:: python\n\n # vanilla Python\n results = [\n user for user in users\n if user['age'] == 26 and user['is_active']\n ]\n\n # lifter\n results = manager.filter(User.age == 26, User.is_active == True)\n\nGetting names and emails of inactive users under 56:\n\n.. code-block:: python\n\n # vanilla Python\n results = [\n (user['name'], user['email']) for user in users\n if not user['is_active'] and user['age'] < 56\n ]\n\n # lifter\n results = manager.filter(User.is_active == False, User.age < 56)\\\n .values_list('name', 'email')\n\nGetting all active users except the one with brown eyes and sort them by age:\n\n.. code-block:: python\n\n # vanilla Python\n raw_results = [\n user for user in users\n if user['is_active'] and not user['eye_color'] == 'brown'\n ]\n results = sorted(raw_results, key=lambda v: v['age'])\n\n # lifter\n results = manager.filter(User.is_active == True)\\\n .exclude(User.eye_color == 'brown')\\\n .order_by('age')\n\nGetting minimum and average women age:\n\n.. code-block:: python\n\n # vanilla Python\n from statistics import mean # Only in Python >=3.4\n women_ages = [\n user['age'] for user in users\n if user['gender'] == 'female'\n ]\n women_average_age = mean(women_ages)\n minimum_woman_age = min(women_ages)\n\n # lifter\n results = manager.filter(User.gender == 'female')\\\n .aggregate((User.age, mean), (User.age, min))\n\nAs you can see, lifter's version is shorter and more readable than vanilla Python.\nIt's also less error prone, especially if you're writing really complex queries,\nand quite familiar if you've already used an ORM.\n\nWanna know more? Have a look at the documentation_!\n\n.. _documentation: http://lifter.readthedocs.org\n\n\n=======\nHistory\n=======\n\n0.4.1 (2016-8-2)\n------------------\n\nThis release fix issue #42: some files were not included in lifter distribution,\nmainly the ``backends`` and ``contrib`` directories, causing various imports to fail.\n\n\n0.4 (2016-7-20)\n---------------\n\nThis release introduces the django contrib module to enable filtering with lifter's python backend\non a django queryset, effectively reducing number of queries sent to the database.\n\nWork is also in progress regarding caching (see #39) but this is not over yet.\n\n0.3 (2016-7-12)\n---------------\n\nThis is a big release, that breaks backward-compatibility with previous ones.\n\nThis release implements a new flow to help implementing #33. The general idea\nis to make lifter generic and be able to query any data source with it.\n\nThe 0.3 release sets the foundation for that by moving all python-iterable related code to a dedicated backend,\nand by implementing the Store -> Adapter > Model layout to deal with queries and result parsing.\n\nAn additional, very simple, ``filesystem`` backend is provided to demonstrate how you can implement your own datasource in lifter.\n\nThe work, though, is still incomplete, because the `filesystem` store internally uses the `IterableStore` from the python backend.\n\nA real store (such as REST or SQL) would be able to understand queries and pass them to a real backend (PostgreSQL).\n\nAnyway, we're in the good direction here :)\n\n0.2.1 (2016-3-4)\n----------------\n\nThis is a small release, with a few improvements on ordering API and on the overall documentation:\n\n* Can now order using multiple fields, fix #30\n* [Backward incompatible] Can now invert ordering in explicit engine using path and ~ operator. Passing a `reverse` argument to `order_by` is not possible anymore\n* Can now query for field existences, fix #26\n\n\n0.2 (2016-2-23)\n---------------\n\nThis is quite an important release:\n\n* A whole new API is now available to make queries, see #15 for more information [angru, eliotberriot]\n* Querysets are now lazy\n* A brand new documentation is now available at http://lifter.readthedocs.org\n* Splitted some huge files into submodules for more clarity\n\nConsidering the new query API, we basically switched from django's ORM-style (keyword engine)\nto SQLAlchemy style (explicit engine).\n\nThe keyword engine is still available and will continue to work as before.\nIt is neither under depreciation at the moment, but using the new engine is recommended.\n\n0.1.1 (2016-2-21)\n------------------\n\n* Can now pass arguments to underlying manager via lifter.load\n* Random order_by for queryset [Pentusha]\n* Improve code examples readability in readme\n* Removed duplicate method on queryset [Mec-iS]\n* Can now run some lookups within iterables (WIP) [Ogreman].\n* Lots of improvements and corrections (typos, examples, etc.) in README [johnfraney, youtux]\n* Can now return flat lists as results for aggregates [Ogreman]\n\n\n0.1.0 (2016-2-17)\n------------------\n\n* First release on PyPI.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/eliotberriot/lifter", "keywords": "lifter", "license": "BSD", "maintainer": null, "maintainer_email": null, "name": "lifter", "package_url": "https://pypi.org/project/lifter/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/lifter/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/eliotberriot/lifter" }, "release_url": "https://pypi.org/project/lifter/0.4.1/", "requires_dist": null, "requires_python": null, "summary": "A lightweight query engine for Python iterables, inspired by Django ORM", "version": "0.4.1" }, "last_serial": 2258033, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "9d3ef306d4c9b5f7e4ae1a83aa2a9b5c", "sha256": "b6f9183a9470d5abe0cff5b194b8c98e6b6e0bde29b42968b4707121eb6286ef" }, "downloads": -1, "filename": "lifter-0.1.0.tar.gz", "has_sig": false, "md5_digest": "9d3ef306d4c9b5f7e4ae1a83aa2a9b5c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18019, "upload_time": "2016-02-17T22:57:48", "url": "https://files.pythonhosted.org/packages/f2/28/c2a446efc523df37310c2905ce62088ea32b814baa55e0e52a9d8292cf1e/lifter-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "fa4021d598f63f54e7964bf212f558f3", "sha256": "38bba9586376690380733e506296f1f2c642da0588217d8064a5619da60fea0c" }, "downloads": -1, "filename": "lifter-0.1.1.tar.gz", "has_sig": false, "md5_digest": "fa4021d598f63f54e7964bf212f558f3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 19520, "upload_time": "2016-02-20T23:59:21", "url": "https://files.pythonhosted.org/packages/14/49/16e73bce4c96f870c3178655bef452dd00aff398395549ea061a14f94dd9/lifter-0.1.1.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "98e821dca1131229c4925a1e898574e8", "sha256": "a72d148f6da67ff2b0ae93442ec3cc81df5532687308b3e53a122fb8ad9c850b" }, "downloads": -1, "filename": "lifter-0.2.tar.gz", "has_sig": false, "md5_digest": "98e821dca1131229c4925a1e898574e8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29747, "upload_time": "2016-02-23T22:04:24", "url": "https://files.pythonhosted.org/packages/e1/2f/703e6a73af277ad3a0287e80268c27a839be3a44be574901aac09da4362c/lifter-0.2.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "0bb7793ea2378f30cfea369ccbab569c", "sha256": "a068f79dd38ec2bd4f4afdac8af2cfcf7bc8b9f5c188831d13e0e98aebb0fe4b" }, "downloads": -1, "filename": "lifter-0.2.1.tar.gz", "has_sig": false, "md5_digest": "0bb7793ea2378f30cfea369ccbab569c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 32635, "upload_time": "2016-03-04T19:02:24", "url": "https://files.pythonhosted.org/packages/4f/6b/8cbd9c0895d1533c74178158e6f2af094d8170571c4bb84b0793d05b5bae/lifter-0.2.1.tar.gz" } ], "0.3": [ { "comment_text": "", "digests": { "md5": "082677535f998e9766f5dcb3d9d93cbd", "sha256": "ba68f09c9bf1c6ec8894c4d9a29f4fbc4318e80950ab49ec640d1944efd47db8" }, "downloads": -1, "filename": "lifter-0.3.tar.gz", "has_sig": false, "md5_digest": "082677535f998e9766f5dcb3d9d93cbd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 45446, "upload_time": "2016-07-12T12:50:36", "url": "https://files.pythonhosted.org/packages/70/25/f775bac45728abf716687ebeeace51a3ca027b6763baaeae18ce4a205093/lifter-0.3.tar.gz" } ], "0.4": [ { "comment_text": "", "digests": { "md5": "458d82ab4ec61a1f57c1a9e92580020f", "sha256": "696611b6e5e24437d5ea5bae3d216e69f8b3f5e076239a388ac4871352d0f294" }, "downloads": -1, "filename": "lifter-0.4.tar.gz", "has_sig": false, "md5_digest": "458d82ab4ec61a1f57c1a9e92580020f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 57522, "upload_time": "2016-07-20T11:21:59", "url": "https://files.pythonhosted.org/packages/f0/23/b2cd718986fd0fb4e90c4331fbf71de7b74c21af9abe2706f37ba3a419d0/lifter-0.4.tar.gz" } ], "0.4.1": [ { "comment_text": "", "digests": { "md5": "65e14216bf3b048e6e3dbefda9b571f5", "sha256": "09c12c8c80e9c1f08ab234c8f12edd0a1449da32684c3f63c499482f42f97cf1" }, "downloads": -1, "filename": "lifter-0.4.1.tar.gz", "has_sig": false, "md5_digest": "65e14216bf3b048e6e3dbefda9b571f5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 62105, "upload_time": "2016-08-02T15:53:23", "url": "https://files.pythonhosted.org/packages/05/84/d16e4ff3b7c14292cac27cdbcca6b2e753416ae5da5ea53473553bfd5c94/lifter-0.4.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "65e14216bf3b048e6e3dbefda9b571f5", "sha256": "09c12c8c80e9c1f08ab234c8f12edd0a1449da32684c3f63c499482f42f97cf1" }, "downloads": -1, "filename": "lifter-0.4.1.tar.gz", "has_sig": false, "md5_digest": "65e14216bf3b048e6e3dbefda9b571f5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 62105, "upload_time": "2016-08-02T15:53:23", "url": "https://files.pythonhosted.org/packages/05/84/d16e4ff3b7c14292cac27cdbcca6b2e753416ae5da5ea53473553bfd5c94/lifter-0.4.1.tar.gz" } ] }