{ "info": { "author": "Tomaz Solc", "author_email": "tomaz.solc@tablix.org", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 3" ], "description": "Merge a series of JSON documents\n================================\n\nThis Python module allows you to merge a series of JSON documents into a\nsingle one.\n\nThis problem often occurs for example when different authors fill in\ndifferent parts of a common document and you need to construct a document\nthat includes contributions from all the authors. It also helps when\ndealing with consecutive versions of a document where different fields get\nupdated over time.\n\nConsider a trivial example with two documents::\n\n >>> base = {\n ... \"foo\": 1,\n ... \"bar\": [ \"one\" ],\n ... }\n\n >>> head = {\n ... \"bar\": [ \"two\" ],\n ... \"baz\": \"Hello, world!\"\n ... }\n\nWe call the document we are merging changes into *base* and the changed\ndocument *head*. To merge these two documents using *jsonmerge*::\n\n >>> from pprint import pprint\n\n >>> from jsonmerge import merge\n >>> result = merge(base, head)\n\n >>> pprint(result, width=40)\n {'bar': ['two'],\n 'baz': 'Hello, world!',\n 'foo': 1}\n\nAs you can see, when encountering an JSON object, *jsonmerge* by default\nreturns fields that appear in either *base* or *head* document. For other\nJSON types, it simply replaces the older value. These principles are also\napplied in case of multiple nested JSON objects.\n\nIn a more realistic use case however, you might want to apply different\n*merge strategies* to different parts of the document. You can tell\n*jsonmerge* how to do that using a syntax based on `JSON schema`_.\n\nIf you already have schemas for your document, you can simply expand them\nwith some additional keywords. Apart from the custom keywords described\nbelow, *jsonmerge* by default uses the schema syntax defined in the `Draft\n4`_ of the JSON schema specification.\n\nYou use the *mergeStrategy* schema keyword to specify the strategy. The\ndefault two strategies mentioned above are called *objectMerge* for objects\nand *overwrite* for all other types.\n\nLet's say you want to specify that the merged *bar* field in the example\ndocument above should contain elements from all documents, not just the\nlatest one. You can do this with a schema like this::\n\n >>> schema = {\n ... \"properties\": {\n ... \"bar\": {\n ... \"mergeStrategy\": \"append\"\n ... }\n ... }\n ... }\n\n >>> from jsonmerge import Merger\n >>> merger = Merger(schema)\n >>> result = merger.merge(base, head)\n\n >>> pprint(result, width=40)\n {'bar': ['one', 'two'],\n 'baz': 'Hello, world!',\n 'foo': 1}\n\nAnother common example is when you need to keep a versioned list of values\nthat appeared in the series of documents::\n\n >>> schema = {\n ... \"properties\": {\n ... \"foo\": {\n ... \"type\": \"object\",\n ... \"mergeStrategy\": \"version\",\n ... \"mergeOptions\": { \"limit\": 5 }\n ... }\n ... }\n ... }\n >>> from jsonmerge import Merger\n >>> merger = Merger(schema)\n\n >>> rev1 = {\n ... 'foo': {\n ... 'greeting': 'Hello, World!'\n ... }\n ... }\n\n >>> rev2 = {\n ... 'foo': {\n ... 'greeting': 'Howdy, World!'\n ... }\n ... }\n\n >>> base = None\n >>> base = merger.merge(base, rev1, merge_options={\n ... 'version': {\n ... 'metadata': {\n ... 'revision': 1\n ... }\n ... }\n ... })\n >>> base = merger.merge(base, rev2, merge_options={\n ... 'version': {\n ... 'metadata': {\n ... 'revision': 2\n ... }\n ... }\n ... })\n >>> pprint(base, width=55)\n {'foo': [{'revision': 1,\n 'value': {'greeting': 'Hello, World!'}},\n {'revision': 2,\n 'value': {'greeting': 'Howdy, World!'}}]}\n\nNote that we use the *mergeOptions* keyword in the schema to supply\nadditional options to the merge strategy. In this case, we tell the\n*version* strategy to retain only 5 most recent versions of this field.\n\nWe also used the *merge_options* argument to supply some options that are\nspecific to each call of the *merge* method. Options specified this\nway are applied to all invocations of a specific strategy in a schema (in\ncontrast to *mergeOptions*, which applies only to the strategy invocation\nin that specific location in the schema). Options specified in\n*mergeOptions* schema keyword override the options specified in the\n*merge_options* argument.\n\nThe *metadata* option for the *version* strategy can contain some document\nmeta-data that is included for each version of the field. *metadata* can\ncontain an arbitrary JSON object.\n\nExample above also demonstrates how *jsonmerge* is typically used when\nmerging more than two documents. Typically you start with an empty *base*\nand then consecutively merge different *heads* into it.\n\nIf you care about well-formedness of your documents, you might also want to\nobtain a schema for the documents that the *merge* method creates.\n*jsonmerge* provides a way to automatically generate it from a schema for\nthe input document::\n\n >>> result_schema = merger.get_schema()\n\n >>> pprint(result_schema, width=80)\n {'properties': {'foo': {'items': {'properties': {'value': {'type': 'object'}}},\n 'maxItems': 5,\n 'type': 'array'}}}\n\nNote that because of the *version* strategy, the type of the *foo* field\nchanged from *object* to *array*.\n\n\nMerge strategies\n----------------\n\nThese are the currently implemented merge strategies.\n\noverwrite\n Overwrite with the value in *base* with value in *head*. Works with any\n type.\n\ndiscard\n Keep the value in *base*, even if *head* contains a different value.\n Works with any type.\n\n By default, if *base* does not contain any value (i.e. that part of the\n document is undefined), the value after merge is kept undefined. This can\n be changed with the *keepIfUndef* option. If this option is *true*, then\n the value from *head* will be retained in this case. This is useful if\n you are merging a series of documents and want to keep the value that\n first appears in the series, but want to discard further modifications.\n\nappend\n Append arrays. Works only with arrays.\n\narrayMergeById\n Merge arrays, identifying items to be merged by an ID field. Resulting\n arrays have items from both *base* and *head* arrays. Any items that\n have identical an ID are merged based on the strategy specified further\n down in the hierarchy.\n\n By default, array items are expected to be objects and ID of the item is\n obtained from the *id* property of the object.\n\n You can specify an arbitrary *JSON pointer* to point to the ID of the\n item using the *idRef* merge option. When resolving the pointer, document\n root is placed at the root of the array item (e.g. by default, *idRef* is\n '/id'). You can also set *idRef* to '/' to treat an array of integers or\n strings as a set of unique values.\n\n Array items in *head* for which the ID cannot be identified (e.g. *idRef*\n pointer is invalid) are ignored.\n\n You can specify an additional item ID to be ignored using the *ignoreId*\n merge option.\n\narrayMergeByIndex\n Merge array items by their index in the array. Similarly to\n *arrayMergeById* strategy, the resulting arrays have items from both\n *base* and *head* arrays. Items that occur at identical positions in both\n arrays will be merged based on the strategy specified further down in the\n hierarchy.\n\nobjectMerge\n Merge objects. Resulting objects have properties from both *base* and\n *head*. Any properties that are present both in *base* and *head* are\n merged based on the strategy specified further down in the hierarchy\n (e.g. in *properties*, *patternProperties* or *additionalProperties*\n schema keywords).\n\n The *objClass* option allows one to request a different dictionary class\n to be used to hold the JSON object. The possible values are names that\n correspond to specific Python classes. Built-in names include\n *OrderedDict*, to use the collections.OrderedDict class, or *dict*,\n which uses the Python's dict built-in. If not specified, *dict* is\n used by default.\n\n Note that additional classes or a different default can be configured via\n the Merger() constructor (see below).\n\nversion\n Changes the type of the value to an array. New values are appended to the\n array in the form of an object with a *value* property. This way all\n values seen during the merge are preserved.\n\n You can add additional properties to the appended object using the\n *metadata* option. Additionally, you can use *metadataSchema* option to\n specify the schema for the object in the *metadata* option.\n\n You can limit the length of the list using the *limit* option in the\n *mergeOptions* keyword.\n\n By default, if a *head* document contains the same value as the *base*,\n document, no new version will be appended. You can change this by setting\n *ignoreDups* option to *false*.\n\nIf a merge strategy is not specified in the schema, *objectMerge* is used\nfor objects and *overwrite* for all other values (but see also the section\nbelow regarding keywords that apply subschemas).\n\nYou can implement your own strategies by making subclasses of\njsonmerge.strategies.Strategy and passing them to Merger() constructor\n(see below).\n\n\nThe Merger Class\n----------------\n\nThe Merger class allows you to further customize the merging of JSON\ndata by allowing you to:\n\n- set the schema containing the merge stategy configuration,\n- provide additional strategy implementations,\n- set a default class to use for holding JSON object data and\n- configure additional JSON object classes selectable via the *objClass*\n merge option.\n\nThe Merger constructor takes the following arguments (all optional, except\nschema):\n\nschema\n The JSON Schema that contains the merge strategy directives\n provided as a JSON object. An empty dictionary should be provided\n if no strategy configuration is needed.\n\nstrategies\n A dictionary mapping strategy names to instances of Strategy\n classes. These will be combined with the built-in strategies\n (overriding them with the instances having the same name).\n\nobjclass_def\n The name of a supported dictionary-like class to hold JSON data by\n default in the merged result. The name must match a built-in name or one\n provided in the *objclass_menu* parameter.\n\nobjclass_menu\n A dictionary providing additional classes to use as JSON object\n containers. The keys are names that can be used as values for the\n *objectMerge* strategy's *objClass* option or the *objclass_def*\n argument. Each value is a function or class that produces an instance of\n the JSON object container. It must support an optional dictionary-like\n object as a parameter which initializes its contents.\n\nvalidatorclass\n A *jsonschema.Validator* subclass. This can be used to specify which\n JSON Schema draft version will be used during merge. Some details such\n as reference resolution are different between versions. By default, the\n Draft 4 validator is used.\n\n\nSupport for keywords that apply subschemas\n------------------------------------------\n\nComplex merging of documents with schemas that use keywords *allOf*,\n*anyOf* and *oneOf* can be problematic. Such documents do not have a\nwell-defined type and might require merging of two values of different\ntypes, which will fail for some strategies. In such cases *get_schema()*\nmight also return schemas that never validate.\n\nThe *overwrite* strategy is usually the safest choice for such schemas.\n\nIf you explicitly define a merge strategy at the same level as *allOf*,\n*anyOf* or *oneOf* keyword, then *jsonmerge* will use the defined strategy\nand not further process any subschemas under those keywords. The\nstrategy however will descend as usual (e.g. *objectMerge* will take into\naccount subschemas under the *properties* keyword at the same level as\n*allOf*).\n\nIf a merge strategy is not explicitly defined and an *allOf* or *anyOf*\nkeyword is present, *jsonmerge* will raise an error.\n\nIf a merge stragegy is not explicitly defined and an *oneOf* keyword is\npresent, *jsonmerge* will continue on the branch of *oneOf* that validates\nboth *base* and *head*. If no branch validates, it will raise an error.\n\nYou can define more complex behaviors by defining for your own strategy\nthat defines what to do in such cases. See docstring documentation for the\n*Strategy* class on how to do that.\n\n\nSecurity considerations\n-----------------------\n\nA JSON schema document can contain *$ref* references to external schemas.\n*jsonmerge* resolves URIs in these references using the mechanisms provided\nby the *jsonschema* module. External references can cause HTTP or similar\nnetwork requests to be performed.\n\nIf *jsonmerge* is used on untrusted input, this may lead to vulnerabilities\nsimilar to the XML External Entity (XXE) attack.\n\n\nRequirements\n------------\n\n*jsonmerge* supports Python 2 (2.7) and Python 3 (3.2 and newer).\n\nYou need *jsonschema* (https://pypi.python.org/pypi/jsonschema) module\ninstalled.\n\n\nInstallation\n------------\n\nTo install the latest *jsonmerge* release from the Python package index::\n\n pip install jsonmerge\n\n\nSource\n------\n\nThe latest development version is available on GitHub:\nhttps://github.com/avian2/jsonmerge\n\nTo install from source, run the following from the top of the source\ndistribution::\n\n pip install .\n\n*jsonmerge* uses `Tox`_ for testing. To run the test suite run::\n\n tox\n\n\nLicense\n-------\n\nCopyright 2019, Tomaz Solc \n\nThe MIT License (MIT)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n.. _JSON schema: http://json-schema.org\n.. _Draft 4: http://json-schema.org/specification-links.html#draft-4\n.. _Tox: https://tox.readthedocs.io/en/latest/\n\n..\n vim: tw=75 ts=4 sw=4 expandtab softtabstop=4\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "jsonmerge", "package_url": "https://pypi.org/project/jsonmerge/", "platform": "", "project_url": "https://pypi.org/project/jsonmerge/", "project_urls": null, "release_url": "https://pypi.org/project/jsonmerge/1.7.0/", "requires_dist": null, "requires_python": "", "summary": "Merge a series of JSON documents.", "version": "1.7.0" }, "last_serial": 5767513, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "69cc288cb0ac387b0db87db8cfa7e2fc", "sha256": "9d608a53def816705e63108d3545c2531ebec218a6eac9464f08fb2dfaf71c4b" }, "downloads": -1, "filename": "jsonmerge-1.0.0.tar.gz", "has_sig": false, "md5_digest": "69cc288cb0ac387b0db87db8cfa7e2fc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9298, "upload_time": "2014-08-19T18:14:15", "url": "https://files.pythonhosted.org/packages/11/14/7709d0e0e669c40f3ba299584295aadb49db8f160d02b6f98cc578998a54/jsonmerge-1.0.0.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "1690b26f6da5e303004767a75830b9dd", "sha256": "2ae73a058474e75f27d4ac2595d9da28084ae42be506f04d077ccea3a853b921" }, "downloads": -1, "filename": "jsonmerge-1.1.0.tar.gz", "has_sig": false, "md5_digest": "1690b26f6da5e303004767a75830b9dd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12556, "upload_time": "2014-09-20T10:50:47", "url": "https://files.pythonhosted.org/packages/a8/a3/08f0e2fb0588c3d7f89ea3f7d6dfb77d0eb766de45e1c2dca08728b21fd6/jsonmerge-1.1.0.tar.gz" } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "d2b281d31eb37e85491e0b420dbe136b", "sha256": "88455c0aa3ca859029c4879c591fc4b7b152738a30a93c4fb50a091e71a8c728" }, "downloads": -1, "filename": "jsonmerge-1.2.0.tar.gz", "has_sig": false, "md5_digest": "d2b281d31eb37e85491e0b420dbe136b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14031, "upload_time": "2016-05-13T08:57:01", "url": "https://files.pythonhosted.org/packages/56/bb/b858011bd63c025415710d85ebd8e4b8a64efc7fbda621786c3935a8e6c7/jsonmerge-1.2.0.tar.gz" } ], "1.2.1": [ { "comment_text": "", "digests": { "md5": "fc7a8eed177c09d703a9b841be311fc7", "sha256": "ac6121696e88e9f61263767d7912d6ef16535a0901566eb1181a9fc39ca37dca" }, "downloads": -1, "filename": "jsonmerge-1.2.1.tar.gz", "has_sig": false, "md5_digest": "fc7a8eed177c09d703a9b841be311fc7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14340, "upload_time": "2016-07-18T10:11:57", "url": "https://files.pythonhosted.org/packages/24/61/6113b90f9753a068d9ca5557a0fb8bd038e7b4613c5dcb690aea1230754f/jsonmerge-1.2.1.tar.gz" } ], "1.3.0": [ { "comment_text": "", "digests": { "md5": "e35ee2c636efaf4e3525ad0fd368b046", "sha256": "422d3373905270d4ad53530e1bc184c8b8ab1934853b9108b14ec71c69c2e484" }, "downloads": -1, "filename": "jsonmerge-1.3.0.tar.gz", "has_sig": false, "md5_digest": "e35ee2c636efaf4e3525ad0fd368b046", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16569, "upload_time": "2017-04-02T12:58:48", "url": "https://files.pythonhosted.org/packages/af/ff/b33dc94feb742007c09bf9c3897011e09d7742e40f2ad6e94542fa80e4ba/jsonmerge-1.3.0.tar.gz" } ], "1.4.0": [ { "comment_text": "", "digests": { "md5": "93d8580f28fd3243a01c54c1b848a206", "sha256": "b4513d8361496508fa642feb8097a60e9fd692a0c10c7370fea592c1f64fe4f3" }, "downloads": -1, "filename": "jsonmerge-1.4.0.tar.gz", "has_sig": false, "md5_digest": "93d8580f28fd3243a01c54c1b848a206", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17953, "upload_time": "2017-06-05T18:58:10", "url": "https://files.pythonhosted.org/packages/6a/71/87b1d42aaff68f8f9d435297840cc9c5349e75135fba0f5dd7c7a66b558a/jsonmerge-1.4.0.tar.gz" } ], "1.5.0": [ { "comment_text": "", "digests": { "md5": "7a3a7463f79212ad72eb2540dbba73c2", "sha256": "8c0967f9492fe110dcfd5da96506839d2f425d0987679e5cf68cf2d6ff553b1d" }, "downloads": -1, "filename": "jsonmerge-1.5.0.tar.gz", "has_sig": false, "md5_digest": "7a3a7463f79212ad72eb2540dbba73c2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21622, "upload_time": "2018-03-23T12:47:47", "url": "https://files.pythonhosted.org/packages/02/8e/9f52e9c99c82a584d1979ae604f02c07cdf887760eec6a1a44ce798771f1/jsonmerge-1.5.0.tar.gz" } ], "1.5.1": [ { "comment_text": "", "digests": { "md5": "b365235503826aacc247ade5943cefcc", "sha256": "0f90dfe3961cad61145895f1fd0ebc2a278a5f7c0ebba6e27e0b28cf2275f017" }, "downloads": -1, "filename": "jsonmerge-1.5.1.tar.gz", "has_sig": false, "md5_digest": "b365235503826aacc247ade5943cefcc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20531, "upload_time": "2018-05-01T13:10:30", "url": "https://files.pythonhosted.org/packages/4d/cb/a3e18a2b13570e782c983bad2072d9d3c9576b5c79a3ddcab390d364c682/jsonmerge-1.5.1.tar.gz" } ], "1.5.2": [ { "comment_text": "", "digests": { "md5": "adf870b2464d40e1db280946236a9083", "sha256": "c05229545d55c1bbfdb3fa11c7f8a1c9868c713af209059ac48e7d86fa9c6a1f" }, "downloads": -1, "filename": "jsonmerge-1.5.2.tar.gz", "has_sig": false, "md5_digest": "adf870b2464d40e1db280946236a9083", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20826, "upload_time": "2018-11-05T17:43:25", "url": "https://files.pythonhosted.org/packages/e5/d8/f06bd65469b25010ff4b924fbd09a8f2a849325cbce947f56516858df17e/jsonmerge-1.5.2.tar.gz" } ], "1.6.0": [ { "comment_text": "", "digests": { "md5": "ea2896e288740347b04f5bdc7e662153", "sha256": "b71a2bec01e3abd9c62a5cfa77253d52cd3a01c959b523e9d2006f5c02245299" }, "downloads": -1, "filename": "jsonmerge-1.6.0.tar.gz", "has_sig": false, "md5_digest": "ea2896e288740347b04f5bdc7e662153", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22735, "upload_time": "2019-03-14T09:01:18", "url": "https://files.pythonhosted.org/packages/e7/62/fd61413785762ba311da5636a9e56ef26ecafaafdd0e7614c570857882b0/jsonmerge-1.6.0.tar.gz" } ], "1.6.1": [ { "comment_text": "", "digests": { "md5": "a322eeb3e7added00b5a63223a8c9842", "sha256": "83abc05d5fcf4c5b4f7cc2c295ddf2cd8215a7ed4fa14e9c3a9771966990820e" }, "downloads": -1, "filename": "jsonmerge-1.6.1.tar.gz", "has_sig": false, "md5_digest": "a322eeb3e7added00b5a63223a8c9842", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23029, "upload_time": "2019-05-15T08:24:06", "url": "https://files.pythonhosted.org/packages/47/d7/f2b1fede3f139babad5461808e01488672cda99feadb646639ca23e6aab2/jsonmerge-1.6.1.tar.gz" } ], "1.7.0": [ { "comment_text": "", "digests": { "md5": "9dc9eb9bf28fb6b42c6370ffcc5c6a76", "sha256": "2004a421890311176136fb911c339c4bab45984808814feaed6a328c6e211ba2" }, "downloads": -1, "filename": "jsonmerge-1.7.0.tar.gz", "has_sig": false, "md5_digest": "9dc9eb9bf28fb6b42c6370ffcc5c6a76", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24615, "upload_time": "2019-09-01T16:57:43", "url": "https://files.pythonhosted.org/packages/3f/85/c73f8fd74a2d920935cacfb3aaf99089a22f7291f7906150e63de086a5c2/jsonmerge-1.7.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "9dc9eb9bf28fb6b42c6370ffcc5c6a76", "sha256": "2004a421890311176136fb911c339c4bab45984808814feaed6a328c6e211ba2" }, "downloads": -1, "filename": "jsonmerge-1.7.0.tar.gz", "has_sig": false, "md5_digest": "9dc9eb9bf28fb6b42c6370ffcc5c6a76", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24615, "upload_time": "2019-09-01T16:57:43", "url": "https://files.pythonhosted.org/packages/3f/85/c73f8fd74a2d920935cacfb3aaf99089a22f7291f7906150e63de086a5c2/jsonmerge-1.7.0.tar.gz" } ] }