{ "info": { "author": "Cameron Simpson", "author_email": "cs@cskk.id.au", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Topic :: Database" ], "description": "*Latest release 20190830.1*:\nHave the decorators set .__module__.\n\nAssorted utility functions to support working with SQLAlchemy.\n\n## Function `auto_session(func)`\n\nDecorator to run a function in a session if one is not presupplied.\nThe function `func` runs within a transaction,\nnested if the session already exists.\n\nSee `with_session` for details.\n\n## Function `find_json_field(column_value, field_name, *, infill=False)`\n\nDescend a JSONable Python object `column_value`\nto `field_name`.\nReturn `column_value` (possibly infilled), `final_field`, `final_field_name`.\n\nThis supports database row columns which are JSON columns.\n\nParameters:\n* `column_value`: the original value of the column\n* `field_name`: the field within the column to locate\n* `infill`: optional keyword parameter, default `False`.\n If true,\n `column_value` and its innards will be filled in as `dict`s\n to allow deferencing the `field_name`.\n\nThe `field_name` is a `str`\nconsisting of a period (`'.'`) separated sequence of field parts.\nEach field part becomes a key to index the column mapping.\nThese keys are split into the leading field parts\nand the final field part,\nwhich is returned as `final_field_name` above.\n\nThe `final_field` return value above\nis the mapping within which `final_field_value` may lie\nand where `final_field_value` may be set.\nNote: it may not be present.\n\nIf a leading key is missing and `infill` is true\nthe corresponding part of the `column_value` is set to an empty dictionary\nin order to allow deferencing the leading key.\nThis includes the case when `column_value` itself is `None`,\nwhich is why the `column_value` is part of the return.\n\nIf a leading key is missing and `infill` is false\nthis function will raise a `KeyError`\nfor the portion of the `field_name` which failed.\n\nExamples:\n\n >>> find_json_field({'a':{'b':{}}}, 'a.b')\n ({'a': {'b': {}}}, {'b': {}}, 'b')\n >>> find_json_field({'a':{}}, 'a.b')\n ({'a': {}}, {}, 'b')\n >>> find_json_field({'a':{'b':{}}}, 'a.b.c.d')\n Traceback (most recent call last):\n ...\n KeyError: 'a.b.c'\n >>> find_json_field({'a':{'b':{}}}, 'a.b.c.d', infill=True)\n ({'a': {'b': {'c': {}}}}, {}, 'd')\n >>> find_json_field(None, 'a.b.c.d')\n Traceback (most recent call last):\n ...\n KeyError: 'a'\n >>> find_json_field(None, 'a.b.c.d', infill=True)\n ({'a': {'b': {'c': {}}}}, {}, 'd')\n\n## Function `get_json_field(column_value, field_name, *, default=None)`\n\nReturn the value of `field_name` from `column_value`\nor a defaault if the field is not present.\n\nParameters:\n* `column_value`: the original value of the column\n* `field_name`: the field within the column to locate\n* `default`: default value to return if the field is not present,\n default: `None`\n\nExamples:\n\n >>> get_json_field({'a': 1}, 'a')\n 1\n >>> get_json_field({'b': 1}, 'a')\n >>> get_json_field({'a': {}}, 'a.b')\n >>> get_json_field({'a': {'b': 2}}, 'a.b')\n 2\n\n## Function `json_column(*da, **dkw)`\n\nClass decorator to declare a virtual column name on a table\nwhere the value resides inside a JSON column of the table.\n\nParameters:\n* `cls`: the class to annotate\n* `attr`: the virtual column name to present as a row attribute\n* `json_field_name`: the field within the JSON column\n used to store this value,\n default the same as `attr`\n* `json_column_name`: the name of the associated JSON column,\n default `'info'`\n* `default`: the default value returned by the getter\n if the field is not present,\n default `None`\n\nExample use:\n\n Base = declarative_base()\n ...\n @json_column('virtual_name', 'json.field.name')\n class TableClass(Base):\n ...\n\nThis annotates the class with a `.virtual_name` property\nwhich can be accessed or set,\naccessing or modifying the associated JSON column\n(in this instance, the column `info`,\naccessing `info['json']['field']['name']`).\n\n## Function `log_level(*da, **dkw)`\n\nDecorator to run `func` at the specified logging `level`, default `logging.DEBUG`.\n\n## Class `ORM`\n\nMRO: `cs.resources.MultiOpenMixin` \nA convenience base class for an ORM class.\n\nThis defines a `.Base` attribute which is a new `DeclarativeBase`\nand provides various Session related convenience methods.\nIt is also a `MultiOpenMixin` subclass\nsupporting nested open/close sequences and use as a context manager.\n\nSubclasses must define the following:\n* `.Session`: a factory in their own `__init__`, typically\n `self.Session=sessionmaker(bind=engine)`\n* `.startup` and `.shutdown` methods to support the `MultiOpenMixin`,\n even if these just `pass`\n\n## Function `orm_auto_session(method)`\n\nDecorator to run a method in a session derived from `self.orm`\nif a session is not presupplied.\nIntended to assist classes with a `.orm` attribute.\n\nSee `with_session` for details.\n\n## Function `push_log_level(level)`\n\nTemporarily set the level of the default SQLAlchemy logger to `level`.\nYields the logger.\n\n*NOTE*: this is not MT safe - competing Threads can mix log levels up.\n\n## Function `set_json_field(column_value, field_name, value, *, infill=False)`\n\nSet a new `value` for `field_name` of `column_value`.\nReturn the new `column_value`.\n\nParameters:\n* `column_value`: the original value of the column\n* `field_name`: the field within the column to locate\n* `value`: the value to store as `field_name`\n* `infill`: optional keyword parameter, default `False`.\n If true,\n `column_value` and its innards will be filled in as `dict`s\n to allow deferencing the `field_name`.\n\nAs with `find_json_field`,\na true `infill` may modify `column_value` to provide `field_name`\nwhich is why this function returns the new `column_value`.\n\nExamples:\n\n >>> set_json_field({'a': 2}, 'a', 3)\n {'a': 3}\n >>> set_json_field({'a': 2, 'b': {'c': 5}}, 'b.c', 4)\n {'a': 2, 'b': {'c': 4}}\n >>> set_json_field({'a': 2}, 'b.c', 4)\n Traceback (most recent call last):\n ...\n KeyError: 'b'\n >>> set_json_field({'a': 2}, 'b.c', 4, infill=True)\n {'a': 2, 'b': {'c': 4}}\n >>> set_json_field(None, 'b.c', 4, infill=True)\n {'b': {'c': 4}}\n\n## Function `with_session(func, *a, orm=None, session=None, **kw)`\n\nCall `func(*a,session=session,**kw)`, creating a session if required.\nThe function `func` runs within a transaction,\nnested if the session already exists.\n\nThis is the inner mechanism of `@auto_session` and\n`ORM.auto_session`.\n\nParameters:\n* `func`: the function to call\n* `a`: the positional parameters\n* `orm`: optional ORM class with a `.session()` context manager method\n such as the `ORM` base class supplied by this module.\n* `session`: optional existing ORM session\n* `kw`: other keyword arguments, passed to `func`\n\nOne of `orm` or `session` must be not `None`; if `session`\nis `None` then one is made from `orm.session()` and used as\na context manager.\n\nThe `session` is also passed to `func` as\nthe keyword parameter `session` to support nested calls.\n\n\n\n# Release Log\n\n*Release 20190830.1*:\nHave the decorators set .__module__.\n\n*Release 20190830*:\n@json_column: small docstring improvement.\n\n*Release 20190829*:\nBugfix @json_column setter: mark the column as modified for the ORM.\nNew push_log_level context manager and @log_level decorator to temporarily change the SQLAlchemy logging handler level.\n\n*Release 20190812*:\nMake ORM a MultiOpenMixin.\nget_json_field: use forgotten `default` parameter.\nOther minor changes.\n\n*Release 20190526*:\nSupport for virtual columns mapped to a JSON column interior value:\nNew functions find_json_field, get_json_field, set_json_field.\nNew decorator @json_column for declaritive_base tables.\n\n*Release 20190517*:\nMake ORM._Session private session factory the public ORM.Session factory for external use.\nwith_session: preexisting sessions still trigger a session.begin_nested, removes flush/commit tension elsewhere.\n\n*Release 20190403*:\nRename @ORM.orm_auto_session to @ORM.auto_session.\nNew @orm_auto_session decorator for methods of objects with a .orm attribute.\n\n*Release 20190319.1*:\nInitial release. ORM base class, @auto_session decorator.", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://bitbucket.org/cameron_simpson/css/commits/all", "keywords": "python2,python3", "license": "GNU General Public License v3 or later (GPLv3+)", "maintainer": "", "maintainer_email": "", "name": "cs.sqlalchemy-utils", "package_url": "https://pypi.org/project/cs.sqlalchemy-utils/", "platform": "", "project_url": "https://pypi.org/project/cs.sqlalchemy-utils/", "project_urls": { "Homepage": "https://bitbucket.org/cameron_simpson/css/commits/all" }, "release_url": "https://pypi.org/project/cs.sqlalchemy-utils/20190830.1/", "requires_dist": null, "requires_python": "", "summary": "Assorted utility functions to support working with SQLAlchemy.", "version": "20190830.1" }, "last_serial": 5757289, "releases": { "20190319.1": [ { "comment_text": "", "digests": { "md5": "36ebb8abbcb858e673c89ea2bde6c54f", "sha256": "5d5a2fde75397ff9fa26d78721f156eda4327f92802722d8d66e7fb0678858e9" }, "downloads": -1, "filename": "cs.sqlalchemy_utils-20190319.1.tar.gz", "has_sig": false, "md5_digest": "36ebb8abbcb858e673c89ea2bde6c54f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 2810, "upload_time": "2019-03-19T03:46:10", "url": "https://files.pythonhosted.org/packages/0f/68/bb95de4cec9f8d040dcdfb692a7136e6f9d0636d19df1f7bdf4e2e84e7bd/cs.sqlalchemy_utils-20190319.1.tar.gz" } ], "20190403": [ { "comment_text": "", "digests": { "md5": "2cb1f1ab684a1ecd06ff8a157f018271", "sha256": "8ccd3b7e1652254d76005af747f520cf7ba2a94427206950b73bd54b01f146bc" }, "downloads": -1, "filename": "cs.sqlalchemy_utils-20190403.tar.gz", "has_sig": false, "md5_digest": "2cb1f1ab684a1ecd06ff8a157f018271", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 2968, "upload_time": "2019-04-03T03:24:49", "url": "https://files.pythonhosted.org/packages/2e/63/bfd3e774dfb7bed4075104d2650f9a545898a14fec45f1fbe4d56a8a5a18/cs.sqlalchemy_utils-20190403.tar.gz" } ], "20190517": [ { "comment_text": "", "digests": { "md5": "52341c2de44426dcd1dd74e423331bd9", "sha256": "63ebffdca03bec39276bbad80545afc48f480440491413ca35fb9a7ee4626e14" }, "downloads": -1, "filename": "cs.sqlalchemy_utils-20190517.tar.gz", "has_sig": false, "md5_digest": "52341c2de44426dcd1dd74e423331bd9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 2990, "upload_time": "2019-05-17T03:07:07", "url": "https://files.pythonhosted.org/packages/6b/ef/e7645c8cdeda875a50c80edd2039d5174fcf405a4a14a87112bd2171d0ae/cs.sqlalchemy_utils-20190517.tar.gz" } ], "20190526": [ { "comment_text": "", "digests": { "md5": "4788629a15163e5babc461ba5acdbac6", "sha256": "995d9b648fb884edd75b4e0563a75fe5e08ff844911bff26e137482595aa5a45" }, "downloads": -1, "filename": "cs.sqlalchemy_utils-20190526.tar.gz", "has_sig": false, "md5_digest": "4788629a15163e5babc461ba5acdbac6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5690, "upload_time": "2019-05-26T10:17:54", "url": "https://files.pythonhosted.org/packages/83/b6/60ede2525dff5835587e9fa33e9fc202d24a82c6d40093414db454d8908f/cs.sqlalchemy_utils-20190526.tar.gz" } ], "20190812": [ { "comment_text": "", "digests": { "md5": "d2de45850e7cd1989cb89dd6387c951f", "sha256": "2012b790b505c111f01de81059ff5c8aeedd5afe0c5ae63378860449e800c326" }, "downloads": -1, "filename": "cs.sqlalchemy_utils-20190812.tar.gz", "has_sig": false, "md5_digest": "d2de45850e7cd1989cb89dd6387c951f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6542, "upload_time": "2019-08-11T23:31:19", "url": "https://files.pythonhosted.org/packages/e0/fe/a78fba33493e9ef763d94fdf9ac5911924f66615d84a1bb424d9b407e8f8/cs.sqlalchemy_utils-20190812.tar.gz" } ], "20190830": [ { "comment_text": "", "digests": { "md5": "144da6d3d582c9615a5f0844f038f10e", "sha256": "0eb8ac36a0284962a00aa2fc760d19e6036a2606121f5875551775c1d7ff8e76" }, "downloads": -1, "filename": "cs.sqlalchemy_utils-20190830.tar.gz", "has_sig": false, "md5_digest": "144da6d3d582c9615a5f0844f038f10e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8241, "upload_time": "2019-08-29T22:08:06", "url": "https://files.pythonhosted.org/packages/5b/ca/25d45cc1db917c4343ab3792e993010165c259e1570c0167b046597fc6b2/cs.sqlalchemy_utils-20190830.tar.gz" } ], "20190830.1": [ { "comment_text": "", "digests": { "md5": "9927a0343effb2043bc31f5ca59ac82e", "sha256": "469423e73b1d7395ac1b5c016ec041fc1975076ab8c9b39a8578e6236098a3f2" }, "downloads": -1, "filename": "cs.sqlalchemy_utils-20190830.1.tar.gz", "has_sig": false, "md5_digest": "9927a0343effb2043bc31f5ca59ac82e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8366, "upload_time": "2019-08-29T22:21:10", "url": "https://files.pythonhosted.org/packages/a3/cf/c20e01814211597bf95bf43b78d5ab21aed0c51aec7f77063882a772b4f8/cs.sqlalchemy_utils-20190830.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "9927a0343effb2043bc31f5ca59ac82e", "sha256": "469423e73b1d7395ac1b5c016ec041fc1975076ab8c9b39a8578e6236098a3f2" }, "downloads": -1, "filename": "cs.sqlalchemy_utils-20190830.1.tar.gz", "has_sig": false, "md5_digest": "9927a0343effb2043bc31f5ca59ac82e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8366, "upload_time": "2019-08-29T22:21:10", "url": "https://files.pythonhosted.org/packages/a3/cf/c20e01814211597bf95bf43b78d5ab21aed0c51aec7f77063882a772b4f8/cs.sqlalchemy_utils-20190830.1.tar.gz" } ] }