Skip to content
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

Error messages do not include context to locate problematic parts in schema #69

Closed
FlorianLudwig opened this issue May 31, 2020 · 13 comments · Fixed by #70
Closed

Error messages do not include context to locate problematic parts in schema #69

FlorianLudwig opened this issue May 31, 2020 · 13 comments · Fixed by #70

Comments

@FlorianLudwig
Copy link

FlorianLudwig commented May 31, 2020

Expected Behaviour

Providing some context which part of my 113k line file failed.

Actual Behaviour

prance validate v1.16.4.json 
Processing "v1.16.4.json"...
 -> Resolving external references.
Traceback (most recent call last):
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/bin/prance", line 8, in <module>
    sys.exit(cli())
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/cli.py", line 108, in command_invoke
    original_invoke(ctx)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/click/decorators.py", line 21, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/cli.py", line 197, in validate
    __validate(parser, name)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/cli.py", line 59, in __validate
    parser.parse()
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/__init__.py", line 138, in parse
    self._validate()
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/__init__.py", line 294, in _validate
    resolver.resolve_references()
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/resolver.py", line 96, in resolve_references
    self.specs = self._resolve_partial(self.parsed_url, self.specs, ())
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/resolver.py", line 207, in _resolve_partial
    changes = dict(tuple(self._dereferencing_iterator(base_url, partial, (),
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/resolver.py", line 133, in _dereferencing_iterator
    ref_value = self._dereference(ref_url, obj_path, next_recursions)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/resolver.py", line 190, in _dereference
    value = self._resolve_partial(ref_url, value, recursions)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/resolver.py", line 207, in _resolve_partial
    changes = dict(tuple(self._dereferencing_iterator(base_url, partial, (),
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/resolver.py", line 133, in _dereferencing_iterator
    ref_value = self._dereference(ref_url, obj_path, next_recursions)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/resolver.py", line 190, in _dereference
    value = self._resolve_partial(ref_url, value, recursions)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/resolver.py", line 207, in _resolve_partial
    changes = dict(tuple(self._dereferencing_iterator(base_url, partial, (),
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/resolver.py", line 133, in _dereferencing_iterator
    ref_value = self._dereference(ref_url, obj_path, next_recursions)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/resolver.py", line 190, in _dereference
    value = self._resolve_partial(ref_url, value, recursions)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/resolver.py", line 207, in _resolve_partial
    changes = dict(tuple(self._dereferencing_iterator(base_url, partial, (),
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/resolver.py", line 133, in _dereferencing_iterator
    ref_value = self._dereference(ref_url, obj_path, next_recursions)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/resolver.py", line 190, in _dereference
    value = self._resolve_partial(ref_url, value, recursions)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/resolver.py", line 207, in _resolve_partial
    changes = dict(tuple(self._dereferencing_iterator(base_url, partial, (),
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/resolver.py", line 112, in _dereferencing_iterator
    ref_url, obj_path = _url.split_url_reference(base_url, refstring)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/url.py", line 120, in split_url_reference
    parsed_url = absurl(reference, base_url)
  File "/home/f.ludwig/.local/share/virtualenvs/pdk8s-oowwi4Ru/lib/python3.8/site-packages/prance/util/url.py", line 56, in absurl
    parsed = parse.urlparse(url)
  File "/usr/lib64/python3.8/urllib/parse.py", line 372, in urlparse
    url, scheme, _coerce_result = _coerce_args(url, scheme)
  File "/usr/lib64/python3.8/urllib/parse.py", line 124, in _coerce_args
    return _decode_args(args) + (_encode_result,)
  File "/usr/lib64/python3.8/urllib/parse.py", line 108, in _decode_args
    return tuple(x.decode(encoding, errors) if x else '' for x in args)
  File "/usr/lib64/python3.8/urllib/parse.py", line 108, in <genexpr>
    return tuple(x.decode(encoding, errors) if x else '' for x in args)
AttributeError: 'dict' object has no attribute 'decode'

Steps to Reproduce

wget https://raw.githubusercontent.com/kubernetes/kubernetes/v1.16.4/api/openapi-spec/swagger.json
prance validate swagger.json

Environment

  • OS: Linux
  • Python version: 3.8
  • Swagger/OpenAPI version used: 2.0
  • Backend: best

@jfinkhaeuser

@jfinkhaeuser
Copy link
Collaborator

It's very hard to provide context on every error not raised in your own code. Sorry about that.

That said, in this case I can easily provide some context. Looks like some URL you're using to refer to some object isn't parseable by urllib - which may mean it's invalid.

That is simple enough to catch and provide context on. Thanks for reporting this!

jfinkhaeuser added a commit that referenced this issue May 31, 2020
jfinkhaeuser added a commit that referenced this issue May 31, 2020
@jfinkhaeuser jfinkhaeuser reopened this May 31, 2020
@jfinkhaeuser
Copy link
Collaborator

Fixed in 0.18.3

@FlorianLudwig
Copy link
Author

Hi,

the error message now is:

ERROR in "v1.16.4.json" [ResolutionError]: 'dict' object has no attribute 'decode' -- Unable to parse url: {'type': 'string'}

which is an improvement for sure but maybe even more context would be possible? Maybe the name of the definition?

In my case "type": "string" is 5139 times in the json.

@jfinkhaeuser
Copy link
Collaborator

jfinkhaeuser commented Jun 1, 2020 via email

@FlorianLudwig
Copy link
Author

Thanks for the hint, did help to find it!

@FlorianLudwig
Copy link
Author

FlorianLudwig commented Jun 1, 2020

Actually, I believe the schema is correct.

It defines a property called $ref which is a string. Basically defining JSONSchema in JSONSchema:

    "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.JSONSchemaProps": {
      "description": "JSONSchemaProps is a JSON-Schema following Specification Draft 4 (http://json-schema.org/).",
      "properties": {
        "$ref": {
          "type": "string"
        },

Reading the specification I am not actually 100% sure if this is allowed or not.

@jfinkhaeuser
Copy link
Collaborator

jfinkhaeuser commented Jun 1, 2020 via email

@FlorianLudwig
Copy link
Author

A common misconception is that $ref is allowed anywhere in an OpenAPI specification file. Actually $ref is only allowed in places where the OpenAPI 3.0 Specification explicitly states that the value may be a reference.

-- https://swagger.io/docs/specification/using-ref/

So I guess it is not that simple that all $ref are references.

@jfinkhaeuser
Copy link
Collaborator

There's that. But OpenAPI is a conflicting spec. They also claim to be using JSON schema and JSON references, but violate those specs in places.

So OpenAPI implementations vary (hence the multiple backends, even if some of them are barely active). Most are based on JSON schema validators, because that's the easy way to implement things. Technically, those don't conform to OpenAPI precisely. You only notice it in these instances, though.

The TL;DR is, with conflicting specs, it's IMHO best to stick to the (very large) subset of things that are unambiguous. Treating $ref as references is kind of that, because it follows well-established specs over the somewhat more slapdash OpenAPI ones. But it's a decision, granted.

@jfinkhaeuser
Copy link
Collaborator

@jfinkhaeuser
Copy link
Collaborator

And in the README, also maybe see the less relevant note on strict mode.

@jfinkhaeuser
Copy link
Collaborator

And I figured I'd update the list and move it out of the README so the README doesn't become so cluttered. https://github.com/jfinkhaeuser/prance/blob/master/COMPATIBILITY.rst

@FlorianLudwig
Copy link
Author

Thank you for the clarifications! I probably have to read more of the specs to understand those edge cases.

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 a pull request may close this issue.

2 participants