Skip to content

Unambiguously quote and escape properties in JSON path rendering #1390

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

kurtmckee
Copy link

@kurtmckee kurtmckee commented Jul 16, 2025

This PR introduces the following change:

  • Unambiguously quote and escape properties in JSON path rendering

Using the script from #1389, this is the new output with the changes in this branch:

$ python demo.py 
property=''             json_path="$['']"
property='['            json_path="$['[']"
property='.'            json_path="$['.']"
property='\\'           json_path="$['\\\\']"
property="'"            json_path="$['\\'']"
property=' '            json_path="$[' ']"
property='"'            json_path='$[\'"\']'
property='a[0]'         json_path="$['a[0]']"

Fixes #1389


📚 Documentation preview 📚: https://python-jsonschema--1390.org.readthedocs.build/en/1390/

@Julian
Copy link
Member

Julian commented Jul 16, 2025

Thanks for the PR (and issue).

I think we should consider and look at jsonpath-ng at very least to start with for testing. It's possible in the future we should deprecate the attribute and replace it with one that returns an object from that library, but even before we do that we can at least use it in our test cases to:

  • ensure all the tests you're adding actually are guarded to be valid JSON Paths
  • ensure we have covered at least the cases that that library itself tests

Could you have a look at doing that? As I say I'm good with just adding it as a test dependency for the moment and evaluating the deprecation/changing the actual interface down the line.

@@ -23,6 +24,8 @@
WEAK_MATCHES: frozenset[str] = frozenset(["anyOf", "oneOf"])
STRONG_MATCHES: frozenset[str] = frozenset()

JSON_PATH_COMPATIBLE_PROPERTY_PATTERN = re.compile("^[a-zA-Z][a-zA-Z0-9_]*$")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make sure this is private even if we don't use jsonpath-ng in the real code yet. Though if it turns out that a regex isn't good enough for fully accurate generation of paths then I think we should think carefully about adding the dep even now perhaps.


class TestJsonPathRendering(TestCase):
def test_str(self):
e = exceptions.ValidationError(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a self.error_with_path(...) -> ValidationError test helper here so the duplication is removed when all we really care about is the one attribute essentially.

And as I said in the top-level comment I think adding an assertion that jsonpath-ng considers our output valid is a good immediate safeguard.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also dissatisfied with the repetitive code, so I'm glad you called this out.

I'm accustomed to using pytests test parametrization feature, and found something similar in unittest just now: subTest.

I can introduce an error_with_path() method, but would you be open to something like:

class TestJsonPathRendering(TestCase):
    def test_strange_properties(self):
        parameters = (
            ("", "$[' ']"),
            (".", "$['.']"),
            # ...
        )
        for property, expected_path in parameters:
            with self.subTest(property=property):
                e = exceptions.ValidationError(
                    path=[property],
                    message="1",
                    validator="foo",
                    instance="i1",
                )
                self.assertEqual(e.json_path, expected_path)

(Wrote that in this comment, so I don't know if it'll actually run as-is.)

Let me know if that's appealing, otherwise I'll go with the test helper you proposed.

Either way, I'll add an assertion that jsonpath-ng can parse the resulting JSON path. 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah using subTest is also fine with me.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super, I'll put together those changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

_Error.json_path produces invalid or questionable JSON paths
2 participants