{ "info": { "author": "Brian Hammond", "author_email": "brian@fictorial.com", "bugtrack_url": null, "classifiers": [], "description": "Python Object Persistence\n=========================\n\nHere, a persistent object is one that persists or lives beyond the life of\na program by being stored in a database in a serialized form. The object\ncan be loaded which deserializes its stored form back into its original class\ntype with all attributes restored\n\nConcepts\n--------\n\n- Your regular Python objects are serialized with\n `jsonpickle `_\n- Serialized objects are stored in a `SQLite3 `_ database\n- Each object must have a globally (across all class types) unique identifier\n in its ``id`` property.\n- *References* between persistent objects are supported. See below for details.\n\nInstallation\n------------\n\n.. code:: bash\n\n pip install python-object-persistence\n\nSystem Requirements\n-------------------\n\nSQLite 3.9.0 or later is required for the JSON functionality which was added\nabout 2 months prior to this writing.\n\n**Python's standard library version is older than the required minimum SQLite3 version.**\n\nHowever, *Python will use whatever SQLite3 version you have installed*. Thus, if\nyou update SQLite3 to the latest stable version you are good to go.\n\nEventually, Python will bundle SQLite 3.9.0+ and none of this will be required.\n\nOS X\n~~~~\n\nInstall `Homebrew `_ if you haven't already.\n\n.. code:: bash\n\n $ brew update\n $ brew install sqlite3 --with-json1\n\n $ python\n >>> import sqlite3\n >>> sqlite3.sqlite_version\n '3.11.0'\n\nLinux\n~~~~~\n\nInstall latest SQLite3 from source to home directory:\n\n.. code:: bash\n\n $ LOCAL=$HOME/local\n $ sqlite_version=3110000 # or whatever\n $ wget http://sqlite.org/2016/sqlite-autoconf-${sqlite_version}.tar.gz -O- | tar xzv\n $ cd sqlite-autoconf-${sqlite_version}\n $ ./configure --enable-json1 --prefix=$LOCAL\n $ make\n $ make install\n\nI use `pyenv `_ to manage install Python versions.\n\n.. code:: bash\n\n $ curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash\n $ echo 'export PATH=\"$HOME/.pyenv/bin:$PATH\"' >> ~/.bash_profile\n $ echo 'eval \"$(pyenv init -)\"' >> ~/.bash_profile\n $ echo 'eval \"$(pyenv virtualenv-init -)\"' >> ~/.bash_profile\n $ echo 'export PYENV_VERSION=3.5.1' >> ~/.bash_profile\n $ source ~/.bash_profile\n $ LD_RUN_PATH=$HOME/local/lib pyenv install $PYENV_VERSION\n $ pyenv version\n 3.5.1\n\n $ python\n >>> import sqlite3\n >>> sqlite3.sqlite_version\n '3.11.0'\n\nUsage\n-----\n\nConnect to the database to use via:\n\n.. code:: python\n\n import persistent\n\n persistent.connect(db_path=':memory:', debug=True)\n\nSubclass ``Persistent``. Create objects of your class type. Call ``save`` on them.\n\n.. code:: python\n\n class Foo(persistent.Persistent):\n pass\n\n f = Foo()\n f.bar = 'hello'\n f.save()\n\nLoad an object by ``id``:\n\n.. code:: python\n\n x = persistent.get(f.id)\n assert x.id == f.id\n assert x.bar == f.bar\n\nMake updates and save the object.\n\n.. code:: python\n\n x.bar = 'monkey'\n assert x.save()\n\nInter-Object References\n-----------------------\n\nA persistent object may refer to another persistent object by setting an\nattribute to the referenced object as in any other Python program. By default,\nwhen the source object is saved, a *copy* of referenced objects is saved with\nit.\n\nIf you would prefer to save an explicit reference, add the source object\nattributes that contain references to the source class's ``references``. On\nsave, the attributes on the source object are stored as the referenced object's\n``id``. On load, the source object's ``references`` are scanned and the referenced\nobjects loaded, replacing the corresponding attribute on the source object.\n\n.. code:: python\n\n class Bar(persistent.Persistent):\n references = [ 'a_ref' ]\n\n b = Bar()\n c = Bar()\n c.baz = 'yes'\n b.a_ref = c\n b.save()\n x = persistent.get(b.id)\n assert x.id == b.id\n assert type(x.a_ref) is Bar\n assert x.a_ref.id == c.id\n assert x.a_ref.baz == c.baz\n\nTimestamps\n----------\n\nThe system automatically adds ``created_at`` and ``updated_at`` which are\n``datetime`` objects in UTC.\n\n.. code:: python\n\n class Baz(persistent.Persistent): pass\n x = Baz()\n x.save()\n from datetime import datetime\n assert type(x.created_at) is datetime\n assert not hasattr(x, 'updated_at')\n x.quux = 'doo'\n x.save()\n assert type(x.updated_at) is datetime\n\nCaching\n-------\n\nA least-recently-used (LRU) cache is used to hold the latest copy of each object by\nobject ``id``. On a cache miss, the desired object is loaded from the database\nand placed into the cache. If more than N objects (by default, N=1000) objects\nare stored in the cache, the least-recently-used object is evicted from the\ncache.\n\nTo change the default size of the cache, use the ``cache_size`` parameter when\ncalling ``persistent.connect``. To disable caching entirely, set the\n``cache_size`` to ``0``.\n\nIndexing\n--------\n\nTo enforce that only a single object may contain some value for a set of \"key\npaths\", create a \"unique index\":\n\n.. code:: python\n\n persistent.add_index(['a', 'b.c'], unique=True)\n\n x = Bar()\n x.a = 1\n x.b = dict(c=1)\n x.save() # OK\n\n y = Bar()\n y.a = 1\n y.b = dict(c=1)\n try: y.save()\n except persistent.UniquenessError as err: assert True\n # Fails as y is non-unique for ['a', 'b.c']\n\nNote that such an index is scoped to the same object class. If you wish to\nmake the index span all persistent objects stored, pass ``global_scope=True``\nto ``add_index``.\n\nBy default, an index has a generated name which is returned by ``add_index``.\n\nA non-unique index can be created to speed up queries.\n\nQuerying\n--------\n\nTo query or find objects, create a ``persist.Query`` object, passing the class of\nobject. Only objects of the given class will be returned.\n\n.. code:: python\n\n q = persist.Query(Bar)\n q.equal_to(key_path, value)\n objects = q.find()\n\nKey Paths\n~~~~~~~~~\n\nA *key path* is a string with elements separated by a period (.).\nFollowing a key path in an object leads to a particular value.\nThe value at a key path is what is used as the test value.\n\nConsider key path \"a.b.c\":\n\n.. code:: python\n\n o = Persistent()\n o.a = dict(b=dict(c=1))\n\nThe value at the key path \"a.b.c\" is ``1``\n\nSee `keypath `_ for more details.\n\nFilters\n~~~~~~~\n\n.. code:: python\n\n q.equal_to(key_path, value)\n q.not_equal_to(key_path, value)\n\n q.exists(key_path)\n q.does_not_exist(key_path)\n\n q.contained_in(key_path, values)\n q.not_contained_in(key_path, values)\n\n q.starts_with(key_path, substr, case_insensitive=False)\n q.contains(key_path, substr, case_insensitive=False)\n q.ends_with(key_path, substr, case_insensitive=False)\n\n q.greater_than(key_path, n, is_list=False)\n q.greater_than_or_equal_to(key_path, n, is_list=False)\n\n q.less_than(key_path, n, is_list=False)\n q.less_than_or_equal_to(key_path, n, is_list=False)\n\n q.matches(key_path, regex_pattern, case_insensitive=False)\n\nNote: when ``is_list`` is ``True`` the test/comparison is between the *length* of\nthe list at ``key_path`` and the operand ``n``.\n\nSorting\n~~~~~~~\n\n.. code:: python\n\n q.ascending(key_path)\n q.descending(key_path)\n\nThese can be called multiple times to sort on multiple key paths.\n\nPagination\n~~~~~~~~~~\n\n.. code:: python\n\n q.limit(n)\n q.skip(n)\n\nRunning the Query\n~~~~~~~~~~~~~~~~~\n\n.. code:: python\n\n objs = q.find()\n obj = q.first()\n n = q.count()\n\n``find`` and ``first`` return ``None`` if no object(s) were found.\n\nAND or OR Queries\n~~~~~~~~~~~~~~~~~\n\nA ``Query`` is in effect an *AND* query in that all conditions specified\nmust be met by an object for that object to be included in the result set.\n\nTo create an *OR* query, use ``OrQuery``:\n\n.. code:: python\n\n q = OrQuery(\n Query(A).equal_to('foo', 'bar'),\n Query(B).equal_to('baz', 'buz'),\n Query(C).equal_to('buz', 'quux'))\n\n objs = q.find()\n\nYou may pass an arbitrary number of queries to an ``OrQuery``.\n\nDebugging\n---------\n\nPass ``debug=True`` to ``persistent.connect`` and submitted SQL statements will be\nlogged using Python's built-in ``logging`` module at the ``debug`` level.\n\nDevelopment\n-----------\n\nRun ``make init`` to install Python package dependencies with `pip `_.\n\nTesting\n-------\n\nRun ``make test`` to run the test suite with `pytest `_ including coverage reporting.\n\nI aim for 100% code coverage in tests. See tests.py.\n\nWhen Python's standard library version of SQLite3 is updated, I will include Tox reports here.\n", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/fictorial/python-object-persistence", "keywords": "", "license": "The MIT License (MIT)", "maintainer": "", "maintainer_email": "", "name": "python-object-persistence", "package_url": "https://pypi.org/project/python-object-persistence/", "platform": null, "project_url": "https://pypi.org/project/python-object-persistence/", "project_urls": { "Homepage": "https://github.com/fictorial/python-object-persistence" }, "release_url": "https://pypi.org/project/python-object-persistence/0.9.5/", "requires_dist": null, "requires_python": "", "summary": "Easily save, load, query your Python objects with SQLite3.", "version": "0.9.5" }, "last_serial": 1980155, "releases": { "0.9.0": [], "0.9.1": [ { "comment_text": "", "digests": { "md5": "525f695852d01464b15b84e08c9505ad", "sha256": "310138ab2cb4170a1e33ab322c5cc6a39fefba4f5b52a4cb3e138d31d1eaac0c" }, "downloads": -1, "filename": "python-object-persistence-0.9.1.tar.gz", "has_sig": false, "md5_digest": "525f695852d01464b15b84e08c9505ad", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9570, "upload_time": "2016-02-26T17:02:16", "url": "https://files.pythonhosted.org/packages/8c/c5/6931bf89758c984ba5ff418bc84e11c9396fb0a79d31a259a6b4f3394f04/python-object-persistence-0.9.1.tar.gz" } ], "0.9.2": [ { "comment_text": "", "digests": { "md5": "4ad81382d01b7d35665f571fe733a2bb", "sha256": "c5544a519edde14e64691cc5de09574476f573fd64f23e90cd77241fdbc9741d" }, "downloads": -1, "filename": "python-object-persistence-0.9.2.tar.gz", "has_sig": false, "md5_digest": "4ad81382d01b7d35665f571fe733a2bb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9706, "upload_time": "2016-02-26T17:15:35", "url": "https://files.pythonhosted.org/packages/ad/b3/1978576bd0cb3b049ebdc2df2f5fcad7398d69565906d0acde072ee93b6b/python-object-persistence-0.9.2.tar.gz" } ], "0.9.3": [ { "comment_text": "", "digests": { "md5": "34996004a6b34e8704cb76fb4e558045", "sha256": "e7f692d36a2dd868a54fc7e0c05a29990bca2e5a437c35f98e848566ae694de8" }, "downloads": -1, "filename": "python-object-persistence-0.9.3.tar.gz", "has_sig": false, "md5_digest": "34996004a6b34e8704cb76fb4e558045", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9710, "upload_time": "2016-02-26T17:18:45", "url": "https://files.pythonhosted.org/packages/5e/64/73f6918bb1bfd20948531ed84af8091085b99eff388ea2606374e8c07f12/python-object-persistence-0.9.3.tar.gz" } ], "0.9.4": [ { "comment_text": "", "digests": { "md5": "7fb8510596c9ca17ac5513e8052fe4ef", "sha256": "e9d40d565788abcdf6304a13dcbdc59db3bf7b1c82925e10d3422223ad0183f8" }, "downloads": -1, "filename": "python-object-persistence-0.9.4.tar.gz", "has_sig": false, "md5_digest": "7fb8510596c9ca17ac5513e8052fe4ef", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9855, "upload_time": "2016-02-26T18:30:09", "url": "https://files.pythonhosted.org/packages/c3/bb/58a80313289f4ad45bbe5cafcc33d3be2262c6ff4eac6ce2e2d21f9313fd/python-object-persistence-0.9.4.tar.gz" } ], "0.9.5": [ { "comment_text": "", "digests": { "md5": "4027234cd123451f8e10b64f2b99c343", "sha256": "0da70d8408550497505d4214916a226bfcaf4bb78f7a634bd6dbe4a2f6aabae7" }, "downloads": -1, "filename": "python-object-persistence-0.9.5.tar.gz", "has_sig": false, "md5_digest": "4027234cd123451f8e10b64f2b99c343", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9926, "upload_time": "2016-02-28T01:35:46", "url": "https://files.pythonhosted.org/packages/fe/91/244b3d8244477a71d7c8fc1da1058718865b508cc0105b99a8d623974847/python-object-persistence-0.9.5.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "4027234cd123451f8e10b64f2b99c343", "sha256": "0da70d8408550497505d4214916a226bfcaf4bb78f7a634bd6dbe4a2f6aabae7" }, "downloads": -1, "filename": "python-object-persistence-0.9.5.tar.gz", "has_sig": false, "md5_digest": "4027234cd123451f8e10b64f2b99c343", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9926, "upload_time": "2016-02-28T01:35:46", "url": "https://files.pythonhosted.org/packages/fe/91/244b3d8244477a71d7c8fc1da1058718865b508cc0105b99a8d623974847/python-object-persistence-0.9.5.tar.gz" } ] }