stefankoegl / python-json-pointer

Resolve JSON Pointers in Python
https://python-json-pointer.readthedocs.org/
Other
140 stars 43 forks source link

Add support for uri fragments #32

Open Enaero opened 6 years ago

Enaero commented 6 years ago

Json pointers which start with '#' are currently not supported. This adds support for them.

Note: I am adding a dependency on requests, but I am not sure if that comes with standard python now.

Enaero commented 6 years ago

@stefankoegl Could you please review this PR?

stefankoegl commented 6 years ago

Hi! Thanks for your contribution!

As requests is not part of the standard library, I am hesitant of adding a dependency for a single call. Can you change that to unquote from the stdlib?

Also I am not sure if it makes sense to use the same call to detect and process both kinds of json pointer representations. Can you please elaborate a bit on your use case?

Enaero commented 6 years ago

I can use the stdlib version. I think there's some quirks between python2 and python3 so I'll be sure to keep that in mind.

The use case is that I have json schemas which have internal refs, e.g.

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "foo": { "$ref": "#/definitions/bar" }
  },
  "definitions": {
    "bar": {
      "type": "object",
      "properties": {
        "a": { "type": "string" },
        "b": { "type": "string" }
      }
    }
  }
}

I am manipulating these schemas and have a need to fetch the object pointed by the refs. rfc6901 says that it supports this type of pointer so I think it makes sense to process both kinds in the init. I am not sure I understand what you mean by using a different call.

twm commented 4 years ago

I don't think this is correct in its current form as it causes the JsonPointer class to accept syntax that isn't JSON Pointer.

RFC 6901 section 6 talks about how to layer the URI syntax with JSON Pointer syntax:

6.  URI Fragment Identifier Representation

   A JSON Pointer can be represented in a URI fragment identifier by
   encoding it into octets using UTF-8 [RFC3629], while percent-encoding
   those characters not allowed by the fragment rule in [RFC3986].

   Note that a given media type needs to specify JSON Pointer as its
   fragment identifier syntax explicitly (usually, in its registration
   [RFC6838]).  That is, just because a document is JSON does not imply
   that JSON Pointer can be used as its fragment identifier syntax.  In
   particular, the fragment identifier syntax for application/json is
   not JSON Pointer.

   Given the same example document as above, the following URI fragment
   identifiers evaluate to the accompanying values:

    #            // the whole document
    #/foo        ["bar", "baz"]
    #/foo/0      "bar"
    #/           0
    #/a~1b       1
    #/c%25d      2
    #/e%5Ef      3
    #/g%7Ch      4
    #/i%5Cj      5
    #/k%22l      6
    #/%20        7
    #/m~0n       8

This isn't the same thing as saying that "#" is part of the JSON Pointer syntax. Rather, you should use a URL parser such as hyperlink to parse the URL, then use the pointer from the fragment normally. For example:

from hyperlink import URL
from jsonpointer import JsonPointer

url = URL.from_text(u'#/definitions/bar')
pointer = JsonPointer(url.fragment)

Note that JSON Schema's $ref is defined to be a URI. It isn't limited to just a fragment (it may be a full URI). I don't think that you can skip the URI parser in the general case.