{ "info": { "author": "Paul Logston", "author_email": "paul@15five.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 1 - Planning", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Internet", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "SCIM 2.0 Filter Parser\n======================\n\n|travis| |codecov| |docs|\n\n.. |travis| image:: https://travis-ci.com/15five/scim2-filter-parser.svg?branch=master\n :target: https://travis-ci.com/15five/scim2-filter-parser\n\n.. |codecov| image:: https://codecov.io/gh/15five/scim2-filter-parser/branch/master/graph/badge.svg\n :target: https://codecov.io/gh/15five/scim2-filter-parser\n\n.. |docs| image:: https://readthedocs.org/projects/scim2-filter-parser/badge/?version=latest\n :target: https://scim2-filter-parser.readthedocs.io/en/latest/?badge=latest\n :alt: Documentation Status\n\nDescription\n-----------\n\nSCIM 2.0 defines queries that look like this::\n\n 'emails[type eq \"work\" and value co \"@example.com\"] or ims[type eq \"xmpp\" and value co \"@foo.com\"]'\n\nThese can be hard to work with and covert into SQL to run against a database.\n\nThat's where SCIM 2.0 Filter Parser (SFP) can help.\n\nSFP is broken up into four modules, each handling a different part of\ntranslating a SCIM call into a SQL query.\n\nThe first step is tokenization or lexical analysis where the filter query\nis broken down into many tokens that make it up.\n\n::\n\n sfp-lexer 'emails[type eq \"work\" and value co \"@example.com\"] or ims[type eq \"xmpp\" and value co \"@foo.com\"]'\n\n Token(type='ATTRNAME', value='emails', lineno=1, index=0)\n Token(type='LBRACKET', value='[', lineno=1, index=6)\n Token(type='ATTRNAME', value='type', lineno=1, index=7)\n Token(type='EQ', value='eq', lineno=1, index=12)\n Token(type='COMP_VALUE', value='work', lineno=1, index=15)\n Token(type='AND', value='and', lineno=1, index=22)\n Token(type='ATTRNAME', value='value', lineno=1, index=26)\n Token(type='CO', value='co', lineno=1, index=32)\n Token(type='COMP_VALUE', value='@example.com', lineno=1, index=35)\n Token(type='RBRACKET', value=']', lineno=1, index=49)\n Token(type='OR', value='or', lineno=1, index=51)\n Token(type='ATTRNAME', value='ims', lineno=1, index=54)\n Token(type='LBRACKET', value='[', lineno=1, index=57)\n Token(type='ATTRNAME', value='type', lineno=1, index=58)\n Token(type='EQ', value='eq', lineno=1, index=63)\n Token(type='COMP_VALUE', value='xmpp', lineno=1, index=66)\n Token(type='AND', value='and', lineno=1, index=73)\n Token(type='ATTRNAME', value='value', lineno=1, index=77)\n Token(type='CO', value='co', lineno=1, index=83)\n Token(type='COMP_VALUE', value='@foo.com', lineno=1, index=86)\n Token(type='RBRACKET', value=']', lineno=1, index=96)\n\n\nThe second step is to convert that series of tokens into a abstract syntax tree.\n\n::\n\n sfp-parser 'emails[type eq \"work\" and value co \"@example.com\"] or ims[type eq \"xmpp\" and value co \"@foo.com\"]'\n\n Filter(expr=LogExpr, negated=False, namespace=None)\n LogExpr(op='or', expr1=Filter, expr2=Filter)\n Filter(expr=Filter, negated=False, namespace=None)\n Filter(expr=Filter, negated=False, namespace=AttrPath)\n Filter(expr=LogExpr, negated=False, namespace=None)\n LogExpr(op='and', expr1=Filter, expr2=Filter)\n Filter(expr=AttrExpr, negated=False, namespace=None)\n AttrExpr(value='eq', attr_path=AttrPath, comp_value=CompValue)\n AttrPath(attr_name='type', sub_attr=None, uri=None)\n CompValue(value='work')\n Filter(expr=AttrExpr, negated=False, namespace=None)\n AttrExpr(value='co', attr_path=AttrPath, comp_value=CompValue)\n AttrPath(attr_name='value', sub_attr=None, uri=None)\n CompValue(value='@example.com')\n AttrPath(attr_name='emails', sub_attr=None, uri=None)\n Filter(expr=Filter, negated=False, namespace=None)\n Filter(expr=Filter, negated=False, namespace=AttrPath)\n Filter(expr=LogExpr, negated=False, namespace=None)\n LogExpr(op='and', expr1=Filter, expr2=Filter)\n Filter(expr=AttrExpr, negated=False, namespace=None)\n AttrExpr(value='eq', attr_path=AttrPath, comp_value=CompValue)\n AttrPath(attr_name='type', sub_attr=None, uri=None)\n CompValue(value='xmpp')\n Filter(expr=AttrExpr, negated=False, namespace=None)\n AttrExpr(value='co', attr_path=AttrPath, comp_value=CompValue)\n AttrPath(attr_name='value', sub_attr=None, uri=None)\n CompValue(value='@foo.com')\n AttrPath(attr_name='ims', sub_attr=None, uri=None)\n\nThe third step is to transpile this AST into a language of our choice.\nThe above query is transpiled to SQL below.\n\n::\n\n sfp-transpiler 'emails[type eq \"work\" and value co \"@example.com\"] or ims[type eq \"xmpp\" and value co \"@foo.com\"]'\n\n ((emails.type = {0}) AND (emails.value LIKE {1})) OR ((ims.type = {2}) AND (ims.value LIKE {3}))\n {0: 'work', 1: '%@example.com%', 2: 'xmpp', 3: '%@foo.com%'}\n\nThe fourth step is to take what is a segment of a SQL WHERE clause and complete\nthe rest of the SQL query.\n\n::\n\n sfp-query 'emails[type eq \"work\" and value co \"@example.com\"] or ims[type eq \"xmpp\" and value co \"@foo.com\"]'\n\n >>> DO NOT USE THIS OUTPUT DIRECTLY\n >>> SQL INJECTION ATTACK RISK\n >>> SQL PREVIEW:\n SELECT DISTINCT users.*\n FROM users\n LEFT JOIN emails ON emails.user_id = users.id\n LEFT JOIN schemas ON schemas.user_id = users.id\n WHERE ((emails.type = work) AND (emails.value LIKE %@example.com%)) OR ((ims.type = xmpp) AND (ims.value LIKE %@foo.com%));\n\nPlease note that SFP does not build SQL queries with parameters pre-injected. \nThat would create a SQL injection attack vulnerability. Instead a ``Query`` \nobject is created and can be forced to display itself as seen above\nby ``print`` ing the query object.\n\nUse\n---\n\nAlthough command line shims are provided, the library is intended to be used\nprogrammatically. Users of the library should instantiate the\n``scim2_filter_parser.query.Query`` class with an attribute map and optionally\nany joins necessary to make all required fields accessible in the query.\n\nFor example, if user information is stored in the ``users`` table and email\ninformation is stored in a different table ``emails``, then the attribute map\nand the joins might be defined as so::\n\n attr_map = {\n ('userName', None, None): 'users.username',\n ('name', 'familyName', None): 'users.family_name',\n ('meta', 'lastModified', None): 'users.update_ts',\n ('emails', None, None): 'emails.address',\n ('emails', 'value', None): 'emails.address',\n }\n\n joins = (\n 'LEFT JOIN emails ON emails.user_id = users.id',\n )\n\n q = Query(filter, 'users', attr_map, joins)\n\n q.sql # Will be equal to 'SELECT * FROM users ...\n q.params # Will be equal to the paramters specific to the filter query.\n\n\nThe attribute_map (``attr_map``) is a mapping of SCIM attribute, subattribute,\nand schema uri to a table field. You will need to customize this to your\nparticular database schema.\n\nThe ``Query.sql`` method returns SQL that can be used as the first\nargument in a call to ``cursor.execute()`` with your favorite DB engine.\nIf you are using a database that requires a replacement character other than '%s',\nthen you can subclass the ``Query`` class and override the ``placeholder`` class\nlevel variable. See the query module and unit tests for an example of this subclassing\nwith SQLite.\n\nThe ``Query.params`` method returns a list of items that can be used as the\nsecond argument in a call to ``cursor.execute()``.\n\nSpeed\n-----\n\nSFP is pretty fast. Check out the speed_test.py script for details on the long and short\nfilter queries tested. SFP transpiled a short filter query into SQL in under 54 microseconds.\nFor a longer query, SFP only took 273 microseconds.\n\n::\n\n \u279c scim2-filter-parser git:(master) \u2717 python -m timeit -s \"import speed_test\" \"speed_test.short()\"\n 10000 loops, best of 3: 53.8 usec per loop\n \u279c scim2-filter-parser git:(master) \u2717 python -m timeit -s \"import speed_test\" \"speed_test.long()\"\n 1000 loops, best of 3: 273 usec per loop\n\n---\n\nThis project is still in its alpha stage of life and should be used accordingly.", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/15five/scim2-filter-parser", "keywords": "scim 2.0 filter", "license": "MIT", "maintainer": "Paul Logston", "maintainer_email": "paul@15five.com", "name": "scim2-filter-parser", "package_url": "https://pypi.org/project/scim2-filter-parser/", "platform": "", "project_url": "https://pypi.org/project/scim2-filter-parser/", "project_urls": { "Homepage": "https://github.com/15five/scim2-filter-parser" }, "release_url": "https://pypi.org/project/scim2-filter-parser/0.3.3/", "requires_dist": null, "requires_python": "", "summary": "A customizable parser/transpiler for SCIM2.0 filters", "version": "0.3.3" }, "last_serial": 5962987, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "8fc8a1e63aa036b98ad2809d10c861b8", "sha256": "4f4f59c1bbe8194c2b83016714d8206d44099a7a9cbfce319d1cc3e4e02704f2" }, "downloads": -1, "filename": "scim2-filter-parser-0.0.1.tar.gz", "has_sig": false, "md5_digest": "8fc8a1e63aa036b98ad2809d10c861b8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 2436, "upload_time": "2019-04-02T23:45:20", "url": "https://files.pythonhosted.org/packages/23/5f/2844cfe2137f59fb97052d1985242a277f2a59a0bef1ae9b85f54e1f31f2/scim2-filter-parser-0.0.1.tar.gz" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "0ae8feee3100bb9da16d0d3a55b3ec58", "sha256": "1585acd5d2b622ef1b25c0b8453839736cb1f983933bdd649c30670491531e15" }, "downloads": -1, "filename": "scim2-filter-parser-0.0.2.tar.gz", "has_sig": false, "md5_digest": "0ae8feee3100bb9da16d0d3a55b3ec58", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14935, "upload_time": "2019-04-22T23:11:42", "url": "https://files.pythonhosted.org/packages/23/c4/1946d8c087f95fe483a0b52038e6b69d8ad39232223e4e09725db83fa1e9/scim2-filter-parser-0.0.2.tar.gz" } ], "0.1.0": [ { "comment_text": "", "digests": { "md5": "e79ce31de911a5bac7e7f8ab1b6eb8e9", "sha256": "42de6d3261e85b715076d75c309751d7884b2e271350d27dad38caf3e64f5732" }, "downloads": -1, "filename": "scim2-filter-parser-0.1.0.tar.gz", "has_sig": false, "md5_digest": "e79ce31de911a5bac7e7f8ab1b6eb8e9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15516, "upload_time": "2019-04-27T03:48:02", "url": "https://files.pythonhosted.org/packages/a8/ae/e8adea2b205896e531c6be7955819eb5a648945a6ae7e45ccbff3c90c0c8/scim2-filter-parser-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "a3f1f806d08870c4fbff66e9cb975256", "sha256": "0cf1fb39451546c74134776f96a7d978aeee623208bb082053406778b9bb2bfc" }, "downloads": -1, "filename": "scim2-filter-parser-0.1.1.tar.gz", "has_sig": false, "md5_digest": "a3f1f806d08870c4fbff66e9cb975256", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16081, "upload_time": "2019-07-09T20:02:30", "url": "https://files.pythonhosted.org/packages/17/f6/e5679d37941be6faa08385987fb8462d2a53fb4b04520fdd96cab207d497/scim2-filter-parser-0.1.1.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "59bd7667e51cd82836d7bab4bb9b2774", "sha256": "9efcf9a3b47ffda4e6288819d596473bbc17e2d4fc5a79f6b8495279e8d7c43f" }, "downloads": -1, "filename": "scim2-filter-parser-0.2.0.tar.gz", "has_sig": false, "md5_digest": "59bd7667e51cd82836d7bab4bb9b2774", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16371, "upload_time": "2019-07-09T22:58:07", "url": "https://files.pythonhosted.org/packages/c4/3a/ec1f0d28fcfaca9aa0d1597a0ccb7acc98006564eb0892f6aa6974b03bb8/scim2-filter-parser-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "0605e64baac377bda2816f0db51ea0f9", "sha256": "3bc137e208ae8a24a290a120ab71f73dff55ea598e46c004b186e63be6c1ba58" }, "downloads": -1, "filename": "scim2-filter-parser-0.2.1.tar.gz", "has_sig": false, "md5_digest": "0605e64baac377bda2816f0db51ea0f9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16376, "upload_time": "2019-07-10T00:12:47", "url": "https://files.pythonhosted.org/packages/b3/d1/d187da5c5689741bd13198787d40fb6a8b88382ec50933414d9b46e7293e/scim2-filter-parser-0.2.1.tar.gz" } ], "0.2.2": [ { "comment_text": "", "digests": { "md5": "7061d38665c6315e659afb6592879f2d", "sha256": "d030a1382663426b6b7d79966990bed0054c1c11ab9d6599c5923bcb2c593b9f" }, "downloads": -1, "filename": "scim2-filter-parser-0.2.2.tar.gz", "has_sig": false, "md5_digest": "7061d38665c6315e659afb6592879f2d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14096, "upload_time": "2019-07-10T20:00:57", "url": "https://files.pythonhosted.org/packages/57/46/99171adb38958ab1231f53e6b461f175d0c81f9f898f852b2361b0d62e73/scim2-filter-parser-0.2.2.tar.gz" } ], "0.2.3": [ { "comment_text": "", "digests": { "md5": "1fb01522f37b4905939840c1775f4461", "sha256": "e6b592462b549dc0c628a3d683d67d9e5e95aa2d45be4708367a76826c720d6f" }, "downloads": -1, "filename": "scim2-filter-parser-0.2.3.tar.gz", "has_sig": false, "md5_digest": "1fb01522f37b4905939840c1775f4461", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16675, "upload_time": "2019-08-01T22:08:18", "url": "https://files.pythonhosted.org/packages/f1/4d/c64f902d1e79c0b6bd7094ceca9dd4d1b6e90e7fc6261fe695a7a49c1a19/scim2-filter-parser-0.2.3.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "7a37e3773683531bc5f4da7721b95555", "sha256": "e5fb55de29edfe7131cf5a8ebe111d12a15111b3aac606e2cb1e621099923b37" }, "downloads": -1, "filename": "scim2-filter-parser-0.3.0.tar.gz", "has_sig": false, "md5_digest": "7a37e3773683531bc5f4da7721b95555", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14547, "upload_time": "2019-10-11T17:20:09", "url": "https://files.pythonhosted.org/packages/20/b3/ddc6d3df4fe09c0505435285a7a0e0dcc9e861a67a066090e122e5ed1b7a/scim2-filter-parser-0.3.0.tar.gz" } ], "0.3.2": [ { "comment_text": "", "digests": { "md5": "0539701b66db54457f06213343536e90", "sha256": "cc63b427b98f91ccf46457fd5a1241d513bafa666f0159c2e9c38c347ea69d86" }, "downloads": -1, "filename": "scim2-filter-parser-0.3.2.tar.gz", "has_sig": false, "md5_digest": "0539701b66db54457f06213343536e90", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14999, "upload_time": "2019-10-11T20:19:11", "url": "https://files.pythonhosted.org/packages/4d/ec/759b2db3aae71878de569c258249ce7d21caf9003a7652edb7e163a28a7e/scim2-filter-parser-0.3.2.tar.gz" } ], "0.3.3": [ { "comment_text": "", "digests": { "md5": "d9679c311b954f04d56cfdec89eb0e73", "sha256": "736f05e3dbd813047960d45d0aaf0501e333d5f7bae3c80231b7c9ec029f4c2c" }, "downloads": -1, "filename": "scim2-filter-parser-0.3.3.tar.gz", "has_sig": false, "md5_digest": "d9679c311b954f04d56cfdec89eb0e73", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14994, "upload_time": "2019-10-12T04:58:42", "url": "https://files.pythonhosted.org/packages/fb/d3/8044b9046ac8c465120bd8aabb7b923d6638d5f7a5b4588e12472befd94a/scim2-filter-parser-0.3.3.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "d9679c311b954f04d56cfdec89eb0e73", "sha256": "736f05e3dbd813047960d45d0aaf0501e333d5f7bae3c80231b7c9ec029f4c2c" }, "downloads": -1, "filename": "scim2-filter-parser-0.3.3.tar.gz", "has_sig": false, "md5_digest": "d9679c311b954f04d56cfdec89eb0e73", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14994, "upload_time": "2019-10-12T04:58:42", "url": "https://files.pythonhosted.org/packages/fb/d3/8044b9046ac8c465120bd8aabb7b923d6638d5f7a5b4588e12472befd94a/scim2-filter-parser-0.3.3.tar.gz" } ] }