pyopenapi/pyswagger

ValueError: Can't resolve type from:(number, int32)

Kyria opened this issue · 5 comments

Kyria commented
>>> from pyswagger import App
>>> app = App.create('https://esi.tech.ccp.is/latest/swagger.json?datasource=tranquility')
>>> app.op['get_markets_region_id_orders']( region_id=1002, type_id=34, order_type='all')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/Kyria/dev/LazyBlacksmith/env/local/lib/python2.7/site-packages/pyswagger/spec/v2_0/objects.py", line 283, in __call__
    _convert_parameter(final(p))
  File "/home/Kyria/dev/LazyBlacksmith/env/local/lib/python2.7/site-packages/pyswagger/spec/v2_0/objects.py", line 264, in _convert_parameter
    c = p._prim_(v, self._prim_factory, ctx=dict(read=False))
  File "/home/Kyria/dev/LazyBlacksmith/env/local/lib/python2.7/site-packages/pyswagger/spec/v2_0/objects.py", line 184, in _prim_
    return prim_factory.produce(self.schema, v, ctx) if i == 'body' else prim_factory.produce(self, v, ctx)
  File "/home/Kyria/dev/LazyBlacksmith/env/local/lib/python2.7/site-packages/pyswagger/primitives/__init__.py", line 178, in produce
    raise ValueError('Can\'t resolve type from:(' + str(obj.type) + ', ' + str(obj.format) + ')')
ValueError: Can't resolve type from:(number, int32)

>>> app.op['get_markets_structures_structure_id'](structure_id=12345)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/Kyria/dev/LazyBlacksmith/env/local/lib/python2.7/site-packages/pyswagger/spec/v2_0/objects.py", line 283, in __call__
    _convert_parameter(final(p))
  File "/home/Kyria/dev/LazyBlacksmith/env/local/lib/python2.7/site-packages/pyswagger/spec/v2_0/objects.py", line 264, in _convert_parameter
    c = p._prim_(v, self._prim_factory, ctx=dict(read=False))
  File "/home/Kyria/dev/LazyBlacksmith/env/local/lib/python2.7/site-packages/pyswagger/spec/v2_0/objects.py", line 184, in _prim_
    return prim_factory.produce(self.schema, v, ctx) if i == 'body' else prim_factory.produce(self, v, ctx)
  File "/home/Kyria/dev/LazyBlacksmith/env/local/lib/python2.7/site-packages/pyswagger/primitives/__init__.py", line 178, in produce
    raise ValueError('Can\'t resolve type from:(' + str(obj.type) + ', ' + str(obj.format) + ')')
ValueError: Can't resolve type from:(number, int32)

Link the the swagger.json used: https://esi.tech.ccp.is/latest/swagger.json?datasource=tranquility

It looks like every endpoints that have this issue use a referenced parameters which is a "number" / "int32" format.

    "page": {
      "default": 1,
      "description": "Which page of results to return",
      "format": "int32",
      "in": "query",
      "name": "page",
      "type": "number"
    },

If I understand correctly types defined in the JSON-Schema Draft 4. Models, used by swagger,

   integer  A JSON number without a fraction or exponent part.
   number  Any JSON number.  Number includes integer.

number also contains integer by definition, so integer/int32 should work (which is not the case currently).
(also swagger validator do not report any issues with number/int32 and number/int64. )

Can you correct this ?

Thanks in advance !

You can extend the supported primitives by following this tutorial. If it doesn't work or not fit your needs, please feel free to let me know.

Kyria commented

Is that the correct way to do it ?

>>> from pyswagger import App
>>> from pyswagger.primitives import Primitive
>>> from pyswagger.primitives._int import create_int, validate_int
>>> factory = Primitive()
>>> factory.register('number', 'int64', create_int, validate_int)
>>> factory.register('number', 'int32', create_int, validate_int)
>>> app = App.load('https://esi.tech.ccp.is/latest/swagger.json?datasource=tranquility', prim=factory)
>>> app.prepare(True)
>>> app.op['get_markets_structures_structure_id'](structure_id=12345)
(<pyswagger.io.Request object at 0x700383b36c10>, <pyswagger.io.Response object at 0x700382d9fc50>)

FYI: your doc is missing app.prepare(strict=True) at the end (just in case people don't know that)


About the issue itself: i don't mind having to implement myself primitive builder for custom types.
But I still feel sad that pyswagger do not support swagger defined primitives itself, because they are a bit edgy (number/int32 and number/int64 which are defined in the spec by the fact that number includes integer).

Imho, you should support these: because swagger-codegen didn't throw any errors with that type/format, neither does other libs like bravado for example... and swagger validators do not yell at these either.

But well, it's up to you at the end.
At least I have a solution for this :)

Thanks !

@Kyria Really? Do swagger 2.0 support number/int32 and number/int64?

The primitive part of pyswagger is based on here and both of them are not listed on that table.

But if swagger-codegen support them, I think I can add them to pyswagger now. Thanks for point this out.

Kyria commented

Do you know this one is outdated https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/2.0.md#data-types ?
(no update since early 2016, and https://swagger.io/specification/ redirects to https://github.com/OAI/OpenAPI-Specification/blob/master//versions/2.0.md ) (branch master)

To quote the spec (from swagger.io):

Primitive data types in the Swagger Specification are based on the types supported by the JSON-Schema Draft 4. Models are described using the Schema Object which is a subset of JSON Schema Draft 4.

And if you follow the JSON-Schema Draft 4 link, you get what I quoted before :

integer A JSON number without a fraction or exponent part.
number Any JSON number. Number includes integer.

FYI, from my test, this is how is defined the "number/int32" using swagger-codegen in the API class comments:

        :param float page: Which page of results to return

But tbh, since there are no validation in the client, I don't believe that having it as float is the right solution (especially since it's an int32, it's supposed to be an integer, not a float).
Also testing the endpoint with a float (the server have a validator integrated) it returns an error because it waits for an integer (number/int32) and not a float (number/float).

Hopes this helps / explains better everything :)

And thanks for your work ! 👍

number/int32, number/int64 are added as supported primitives in v0.8.31