{ "info": { "author": "Erik Cederstrand", "author_email": "erik@cederstrand.dk", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "License :: OSI Approved :: BSD License", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries" ], "description": "Python SyncSet\n==============\nWhen synchronizing two collections of objects, you quickly end up with code like this:\n\n.. code-block:: python\n\n old_coll = get_some_items()\n new_coll = get_some_other_items()\n old_coll_map = {get_the_id(i): i for i in old_coll}\n new_coll_map = {get_the_id(i): i for i in new_coll}\n only_in_old, only_in_new, outdated, updated = [], [], [], []\n for k, old_item in old_coll_map.items():\n if k in new_coll_map:\n new_item = new_coll_map[k]\n old_changekey = get_the_changekey(old_item)\n new_changekey = get_the_changekey(new_item)\n if old_changekey > new_changekey:\n outdated.append(old_item)\n updated.append(new_item)\n elif new_changekey > old_changekey:\n outdated.append(new_item)\n updated.append(old_item)\n else:\n only_in_old.append(old_item)\n # And we still haven't built the 'only_in_new' list...\n\n``SyncSet`` is an extension of the standard Python ``set()`` which supports this pattern with a one-liner:\n\n.. code-block:: python\n\n only_in_old, only_in_new, outdated, updated = old_coll.diff(new_coll)\n\nWith ``SyncSet``, you can easily do set operations on sets of mutable and immutable objects that, in addition to the \nnormal unique ID of set members, have a changekey attribute (a timestamp, autoincrement value, revision ID, hash \netc.). Via set operations and a custom ``diff()`` method, you can do one- or two-way synchronization of comparable \nobject sets via the ``OneWaySyncSet`` and ``TwoWaySyncSet`` classes, respectively. Examples are syncing files, \nweb pages, contacts or calendar items.\n\nAll standard ``set()`` and ``dict()`` methods are supported, except for a handful which raise ``UndefinedBehaviorError``\nbecause the method doesn't make sense (``>`` operator, for example). Items in the set are required to implement the very \nsimple interface ``SyncSetMember``.\n\n.. image:: https://badge.fury.io/py/syncset.svg\n :target: https://badge.fury.io/py/syncset\n\n.. image:: https://api.codacy.com/project/badge/Grade/a35900e707cc4b71b40745d7553c26df\n :target: https://www.codacy.com/project/ecederstrand/py-syncset/dashboard?utm_source=github.com&utm_medium=referral&utm_content=ecederstrand/py-syncset&utm_campaign=Badge_Grade_Dashboard\n\n.. image:: https://secure.travis-ci.org/ecederstrand/py-syncset.png\n :target: http://travis-ci.org/ecederstrand/py-syncset\n\n.. image:: https://coveralls.io/repos/github/ecederstrand/py-syncset/badge.svg?branch=\n :target: https://coveralls.io/github/ecederstrand/py-syncset?branch=\n\nUsage\n~~~~~\nLet's say we want to maintain a local copy of some web pages. We let the ``Last-Modified`` HTTP header decide when a page\nhas changed. We'll use ``date`` values in the following, for the sake of brevity.\n\nOur URL caching code could have lots of extra functionality. Let's assume here that our main class is ``WebPage``.\n\nFirst, we want to tell ``syncset`` what we consider a unique ID and a revision (changekey). We create a minimal wrapper\nclass that inherits ``SyncSetMember`` and makes ``url`` the unique ID and ``last_modified`` the changekey.\n\n.. code-block:: python\n\n import syncset\n from datetime import date\n\n\n class WebPage:\n def __init__(self, url, last_modified):\n self.url = url\n self.last_modified = last_modified\n self.body = ''\n\n def __repr__(self):\n return self.__class__.__name__ + repr((self.url, self.last_modified))\n\n\n class SyncableWebPage(WebPage, syncset.SyncSetMember):\n def get_id(self):\n return self.url\n\n def get_changekey(self):\n return self.last_modified\n\nWe want to sync these URLs:\n\n.. code-block:: python\n\n foo = \"http://example.com/foo.html\"\n bar = \"http://example.com/bar.html\"\n baz = \"http://example.com/baz.html\"\n\nThis is our outdated copy:\n\n.. code-block:: python\n\n old_urls = syncset.OneWaySyncSet()\n old_urls.add(SyncableWebPage(foo, date(2012, 1, 1)))\n old_urls.add(SyncableWebPage(bar, date(2011, 12, 8)))\n\n\nThis is the server version, after fetching the latest ``Last-Modified`` header in an HTTP HEAD request:\n\n.. code-block:: python\n\n new_urls = syncset.OneWaySyncSet()\n new_urls.add(SyncableWebPage(foo, date(2016, 2, 1)))\n new_urls.add(SyncableWebPage(bar, date(2011, 12, 8)))\n new_urls.add(SyncableWebPage(baz, date(2012, 2, 15)))\n\nNow, let's find the difference between the two. ``diff()`` returns four ``SyncSet`` objects:\n\n.. code-block:: python\n\n only_in_old, only_in_new, outdated_in_old, updated_in_new = old_urls.diff(new_urls)\n print(only_in_old)\n OneWaySyncSet([])\n print(only_in_new)\n\n OneWaySyncSet(\n [SyncableWebPage('http://mysrv/baz.html', datetime.date(2012, 2, 15))]\n )\n\n print(outdated_in_old)\n\n OneWaySyncSet(\n [SyncableWebPage('http://mysrv/foo.html', datetime.date(2012, 1, 1))]\n )\n\n print(updated_in_new)\n\n OneWaySyncSet(\n [SyncableWebPage('http://mysrv/foo.html', datetime.date(2012, 2, 1))]\n )\n\nAs you can see, ``foo`` needs to be updated, ``bar`` is unchanged and ``baz`` is new on the server. After issuing HTTP\nGET requests on ``foo`` and ``baz`` to get the updated content, let's update the local copy:\n\n.. code-block:: python\n\n old_urls.update(new_urls)\n print(old_urls)\n\n OneWaySyncSet([\n SyncableWebPage('http://example.com/foo.html', datetime.date(2016, 2, 1)),\n SyncableWebPage('http://example.com/bar.html', datetime.date(2011, 12, 8)),\n SyncableWebPage('http://example.com/baz.html', datetime.date(2012, 2, 15))\n ])\n\nThis updates ``foo`` and adds ``baz``.\n\nSimilarly, a ``TwoWaySyncSet`` class exists that implements two-way synchronization. Both versions implement all the\nnormal ``set()`` operations, using either one-way or two-way synchronization logic.\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/ecederstrand/py-syncset", "keywords": "set dict sync synchronize synchronization", "license": "BSD", "maintainer": "", "maintainer_email": "", "name": "syncset", "package_url": "https://pypi.org/project/syncset/", "platform": "", "project_url": "https://pypi.org/project/syncset/", "project_urls": { "Homepage": "https://github.com/ecederstrand/py-syncset" }, "release_url": "https://pypi.org/project/syncset/2.0.0/", "requires_dist": null, "requires_python": "", "summary": "Extension of Python set() which is able to synchronize sets of comparable objects", "version": "2.0.0" }, "last_serial": 4148687, "releases": { "1.2": [], "1.2.1": [ { "comment_text": "", "digests": { "md5": "44b720fd5f523741227e7b982642c7e1", "sha256": "eb9e8b27ffecc2ade85b6f30c951784a168c5aa4afa85d25e06e751511f9bcbc" }, "downloads": -1, "filename": "syncset-1.2.1.tar.gz", "has_sig": false, "md5_digest": "44b720fd5f523741227e7b982642c7e1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5914, "upload_time": "2016-05-10T10:29:03", "url": "https://files.pythonhosted.org/packages/02/27/0c5ed941734c4248cf8d7a7348a29fdb7ab8e52b219e162e1d724c2fd81e/syncset-1.2.1.tar.gz" } ], "1.2.2": [ { "comment_text": "", "digests": { "md5": "ddae7171e2ad7fce44f54cecaca6729e", "sha256": "6ebc657913f054e0acfa92b6be65add40f703f47ffbc47aea182c3f7a9669956" }, "downloads": -1, "filename": "syncset-1.2.2.tar.gz", "has_sig": false, "md5_digest": "ddae7171e2ad7fce44f54cecaca6729e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5929, "upload_time": "2016-05-12T22:09:00", "url": "https://files.pythonhosted.org/packages/a9/d5/94696c5a6464a7eddd0f157bb3266f904935063ffd88eb04e9e0834aba00/syncset-1.2.2.tar.gz" } ], "1.2.3": [ { "comment_text": "", "digests": { "md5": "f9297cf3dc6434ff3225daaa8c8c95c9", "sha256": "1e508ee786ee66713b9dc7f2a5b3d50194bf5212b6d384a50eeacd38d6b098e2" }, "downloads": -1, "filename": "syncset-1.2.3.tar.gz", "has_sig": false, "md5_digest": "f9297cf3dc6434ff3225daaa8c8c95c9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6663, "upload_time": "2016-08-29T20:35:59", "url": "https://files.pythonhosted.org/packages/fb/3b/cab0012e2aaf4d17fb0a1a23e00ac936827df96aa458d2127851e54268fd/syncset-1.2.3.tar.gz" } ], "2.0.0": [ { "comment_text": "", "digests": { "md5": "530cd5aeaea2771af64294603f3f9505", "sha256": "0964e0d3486792138af5d0415c8c4d8f2a9df0c685496faf89191aac93be9c0f" }, "downloads": -1, "filename": "syncset-2.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "530cd5aeaea2771af64294603f3f9505", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 6611, "upload_time": "2018-08-08T11:39:27", "url": "https://files.pythonhosted.org/packages/f9/c6/c7a5efaf0696ca0754c479dcc2f39d03c247690fe3ee9dc95722bfa9309b/syncset-2.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9031fb5d1d5d2dc7607e13c9ddcff27a", "sha256": "24fe3028714cafa414bb357d5b502a2625dabef53ec5eacb784cf1dc156763ea" }, "downloads": -1, "filename": "syncset-2.0.0.tar.gz", "has_sig": false, "md5_digest": "9031fb5d1d5d2dc7607e13c9ddcff27a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6925, "upload_time": "2018-08-08T11:39:28", "url": "https://files.pythonhosted.org/packages/df/3d/9b9c0e72e56557cf591da709ac82109cdf8f7b91fca8b059b4dec2a42fbf/syncset-2.0.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "530cd5aeaea2771af64294603f3f9505", "sha256": "0964e0d3486792138af5d0415c8c4d8f2a9df0c685496faf89191aac93be9c0f" }, "downloads": -1, "filename": "syncset-2.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "530cd5aeaea2771af64294603f3f9505", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 6611, "upload_time": "2018-08-08T11:39:27", "url": "https://files.pythonhosted.org/packages/f9/c6/c7a5efaf0696ca0754c479dcc2f39d03c247690fe3ee9dc95722bfa9309b/syncset-2.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9031fb5d1d5d2dc7607e13c9ddcff27a", "sha256": "24fe3028714cafa414bb357d5b502a2625dabef53ec5eacb784cf1dc156763ea" }, "downloads": -1, "filename": "syncset-2.0.0.tar.gz", "has_sig": false, "md5_digest": "9031fb5d1d5d2dc7607e13c9ddcff27a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6925, "upload_time": "2018-08-08T11:39:28", "url": "https://files.pythonhosted.org/packages/df/3d/9b9c0e72e56557cf591da709ac82109cdf8f7b91fca8b059b4dec2a42fbf/syncset-2.0.0.tar.gz" } ] }