diff options
author | Stefan Kögl <stefan@skoegl.net> | 2011-07-31 21:52:03 +0200 |
---|---|---|
committer | Stefan Kögl <stefan@skoegl.net> | 2011-07-31 21:52:03 +0200 |
commit | b243faeee8a8db1a6813765fe1113acecff0d472 (patch) | |
tree | f45985f94f57f3dd009fb6b4d534f92285446cf9 | |
download | python-json-pointer-b243faeee8a8db1a6813765fe1113acecff0d472.tar.gz |
initial commit
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | COPYING | 26 | ||||
-rw-r--r-- | README | 11 | ||||
-rw-r--r-- | jsonpointer.py | 107 | ||||
-rw-r--r-- | setup.py | 33 | ||||
-rwxr-xr-x | tests.py | 44 |
7 files changed, 225 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ebc4254 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pyc +build +.coverage @@ -0,0 +1 @@ +Stefan Kögl <stefan@skoegl.net> @@ -0,0 +1,26 @@ +Copyright (c) 2011 Stefan Kögl <stefan@skoegl.net> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + @@ -0,0 +1,11 @@ + +python-json-pointer: Resolve JSON Pointers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Library to resolve JSON Pointers according to +http://tools.ietf.org/html/draft-pbryan-zyp-json-pointer-00 + +See Sourcecode for Examples + +Website: https://github.com/stefankoegl/python-json-pointer +Repository: https://github.com/stefankoegl/python-json-pointer.git diff --git a/jsonpointer.py b/jsonpointer.py new file mode 100644 index 0000000..b1f0d72 --- /dev/null +++ b/jsonpointer.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +# +# python-json-pointer - An implementation of the JSON Pointer syntax +# https://github.com/stefankoegl/python-json-pointer +# +# Copyright (c) 2011 Stefan Kögl <stefan@skoegl.net> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +""" Identify specific nodes in a JSON document according to +http://tools.ietf.org/html/draft-pbryan-zyp-json-pointer-00 """ + +# Will be parsed by setup.py to determine package metadata +__author__ = 'Stefan Kögl <stefan@skoegl.net>' +__version__ = '0.1' +__website__ = 'https://github.com/stefankoegl/python-json-pointer' +__license__ = 'Modified BSD License' + + +import urllib + + +class JsonPointerException(Exception): + pass + + +def resolve_pointer(doc, pointer): + """ + Resolves pointer against doc and returns the referenced object + + >>> obj = {"foo": {"anArray": [ {"prop": 44}], "another prop": {"baz": "A string" }}} + + >>> resolve_pointer(obj, '/') == obj + True + + >>> resolve_pointer(obj, '/foo') + {'another prop': {'baz': 'A string'}, 'anArray': [{'prop': 44}]} + + >>> resolve_pointer(obj, '/foo/another%20prop') + {'baz': 'A string'} + + >>> resolve_pointer(obj, '/foo/another%20prop/baz') + 'A string' + + >>> resolve_pointer(obj, '/foo/anArray/0') + {'prop': 44} + """ + + parts = pointer.split('/') + if parts.pop(0) != '': + raise JsonPointerException('location must starts with /') + + parts = map(urllib.unquote, parts) + + for part in parts: + doc = walk(doc, part) + + return doc + + +def walk(doc, part): + """ Walks one step in doc and returns the referenced part """ + + if not part: + return doc + + # Its not clear if a location "1" should be considered as 1 or "1" + # We prefer the integer-variant if possible + part_variants = _try_parse(part) + [part] + + for variant in part_variants: + try: + return doc[variant] + except: + continue + + raise JsonPointerException("'%s' not found in %s" % (part, doc)) + + +def _try_parse(val, cls=int): + try: + return [cls(val)] + except: + return [] diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..c9a3900 --- /dev/null +++ b/setup.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +from distutils.core import setup +import re + +src = open('jsonpatch.py').read() +metadata = dict(re.findall("__([a-z]+)__ = '([^']+)'", src)) +docstrings = re.findall('"""(.*)"""', src) + +PACKAGE = 'jsonpatch' + +MODULES = ( + 'jsonpatch', +) + +AUTHOR_EMAIL = metadata['author'] +VERSION = metadata['version'] +WEBSITE = metadata['website'] +LICENSE = metadata['license'] +DESCRIPTION = docstrings[0] + +# Extract name and e-mail ("Firstname Lastname <mail@example.org>") +AUTHOR, EMAIL = re.match(r'(.*) <(.*)>', AUTHOR_EMAIL).groups() + +setup(name=PACKAGE, + version=VERSION, + description=DESCRIPTION, + author=AUTHOR, + author_email=EMAIL, + license=LICENSE, + url=WEBSITE, + py_modules=MODULES, +) diff --git a/tests.py b/tests.py new file mode 100755 index 0000000..3a4b6a2 --- /dev/null +++ b/tests.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import print_function +import doctest +import unittest +import sys + +modules = ['jsonpointer'] +coverage_modules = [] + +suite = unittest.TestSuite() + +for module in modules: + m = __import__(module, fromlist=[module]) + coverage_modules.append(m) + suite.addTest(doctest.DocTestSuite(m)) + +runner = unittest.TextTestRunner(verbosity=2) + +try: + import coverage +except ImportError: + coverage = None + +if coverage is not None: + coverage.erase() + coverage.start() + +result = runner.run(suite) + +if not result.wasSuccessful(): + sys.exit(1) + +if coverage is not None: + coverage.stop() + coverage.report(coverage_modules) + coverage.erase() + +if coverage is None: + print(""" + No coverage reporting done (Python module "coverage" is missing) + Please install the python-coverage package to get coverage reporting. + """, file=sys.stderr) |