marcoceppi / python-spacetraders

A Python SpaceTraders library for interacting with the API
13 stars 2 forks source link

extract_resource gives a TypeError #5

Closed ipaulo closed 1 year ago

ipaulo commented 1 year ago

Sample code:

from spacetraders import AuthenticatedClient

API_BASE_URL="https://api.spacetraders.io/v2"

mytoken = ""

client = AuthenticatedClient(
    base_url=API_BASE_URL,
    token=mytoken,
)

shipsymbol = 'NAMEME-1'

print(client.fleet.extract_resources(shipsymbol))

Partial traceback:

File "C:\code\mysp\Lib\site-packages\httpx\_content.py", line 177, in encode_json
    body = json_dumps(json).encode("utf-8")
           ^^^^^^^^^^^^^^^^
  File "C:\Users\phil_\AppData\Local\Programs\Python\Python311\Lib\json\__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\phil_\AppData\Local\Programs\Python\Python311\Lib\json\encoder.py", line 200, in encode
    chunks = self.iterencode(o, _one_shot=True)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\phil_\AppData\Local\Programs\Python\Python311\Lib\json\encoder.py", line 258, in iterencode
    return _iterencode(o, 0)
           ^^^^^^^^^^^^^^^^^
  File "C:\Users\phil_\AppData\Local\Programs\Python\Python311\Lib\json\encoder.py", line 180, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type Unset is not JSON serializable
marcoceppi commented 1 year ago

Thanks for the report! This is very similar to #4 as it's because of the UNSET functionality to denote "optional" fields from the openapi-python-client library I use to generate the code. I'll patch that today to make sure proper empty fields from Pydantic are used instead

marcoceppi commented 1 year ago

This should be resolved as of 0.2.3

ipaulo commented 1 year ago

Still happening for me.

One odd additional thing. When I setup my venv's previously, I've installed jupyter-lab as well before running code using spacetraders. I didn't this time because I wanted to keep it as clean as possible before reporting this might not be fixed. I need to install attrs, and python-dateutil separately. Can those be listed in the module as dependencies?

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[1], line 15
      8 client = AuthenticatedClient(
      9     base_url=API_BASE_URL,
     10     token=mytoken,
     11 )
     13 shipsymbol = 'BlowupDoll111-2'
---> 15 print(client.fleet.extract_resources(shipsymbol))

File C:\code\mysp\Lib\site-packages\spacetraders\api\fleet\extract_resources.py:94, in sync_detailed(ship_symbol, _client, **json_body)
     86 json_body = ExtractResourcesJsonBody.parse_obj(json_body)
     88 kwargs = _get_kwargs(
     89     ship_symbol=ship_symbol,
     90     _client=_client,
     91     json_body=json_body,
     92 )
---> 94 response = httpx.request(
     95     verify=_client.verify_ssl,
     96     **kwargs,
     97 )
     99 return _build_response(client=_client, response=response)

File C:\code\mysp\Lib\site-packages\httpx\_api.py:100, in request(method, url, params, content, data, files, json, headers, cookies, auth, proxies, timeout, follow_redirects, verify, cert, trust_env)
     42 """
     43 Sends an HTTP request.
     44 
   (...)
     90 ```
     91 """
     92 with Client(
     93     cookies=cookies,
     94     proxies=proxies,
   (...)
     98     trust_env=trust_env,
     99 ) as client:
--> 100     return client.request(
    101         method=method,
    102         url=url,
    103         content=content,
    104         data=data,
    105         files=files,
    106         json=json,
    107         params=params,
    108         headers=headers,
    109         auth=auth,
    110         follow_redirects=follow_redirects,
    111     )

File C:\code\mysp\Lib\site-packages\httpx\_client.py:801, in Client.request(self, method, url, content, data, files, json, params, headers, cookies, auth, follow_redirects, timeout, extensions)
    794     message = (
    795         "Setting per-request cookies=<...> is being deprecated, because "
    796         "the expected behaviour on cookie persistence is ambiguous. Set "
    797         "cookies directly on the client instance instead."
    798     )
    799     warnings.warn(message, DeprecationWarning)
--> 801 request = self.build_request(
    802     method=method,
    803     url=url,
    804     content=content,
    805     data=data,
    806     files=files,
    807     json=json,
    808     params=params,
    809     headers=headers,
    810     cookies=cookies,
    811     timeout=timeout,
    812     extensions=extensions,
    813 )
    814 return self.send(request, auth=auth, follow_redirects=follow_redirects)

File C:\code\mysp\Lib\site-packages\httpx\_client.py:358, in BaseClient.build_request(self, method, url, content, data, files, json, params, headers, cookies, timeout, extensions)
    352     timeout = (
    353         self.timeout
    354         if isinstance(timeout, UseClientDefault)
    355         else Timeout(timeout)
    356     )
    357     extensions = dict(**extensions, timeout=timeout.as_dict())
--> 358 return Request(
    359     method,
    360     url,
    361     content=content,
    362     data=data,
    363     files=files,
    364     json=json,
    365     params=params,
    366     headers=headers,
    367     cookies=cookies,
    368     extensions=extensions,
    369 )

File C:\code\mysp\Lib\site-packages\httpx\_models.py:339, in Request.__init__(self, method, url, params, headers, cookies, content, data, files, json, stream, extensions)
    337 if stream is None:
    338     content_type: typing.Optional[str] = self.headers.get("content-type")
--> 339     headers, stream = encode_request(
    340         content=content,
    341         data=data,
    342         files=files,
    343         json=json,
    344         boundary=get_multipart_boundary_from_content_type(
    345             content_type=content_type.encode(self.headers.encoding)
    346             if content_type
    347             else None
    348         ),
    349     )
    350     self._prepare(headers)
    351     self.stream = stream

File C:\code\mysp\Lib\site-packages\httpx\_content.py:214, in encode_request(content, data, files, json, boundary)
    212     return encode_urlencoded_data(data)
    213 elif json is not None:
--> 214     return encode_json(json)
    216 return {}, ByteStream(b"")

File C:\code\mysp\Lib\site-packages\httpx\_content.py:177, in encode_json(json)
    176 def encode_json(json: Any) -> Tuple[Dict[str, str], ByteStream]:
--> 177     body = json_dumps(json).encode("utf-8")
    178     content_length = str(len(body))
    179     content_type = "application/json"

File ~\AppData\Local\Programs\Python\Python311\Lib\json\__init__.py:231, in dumps(obj, skipkeys, ensure_ascii, check_circular, allow_nan, cls, indent, separators, default, sort_keys, **kw)
    226 # cached encoder
    227 if (not skipkeys and ensure_ascii and
    228     check_circular and allow_nan and
    229     cls is None and indent is None and separators is None and
    230     default is None and not sort_keys and not kw):
--> 231     return _default_encoder.encode(obj)
    232 if cls is None:
    233     cls = JSONEncoder

File ~\AppData\Local\Programs\Python\Python311\Lib\json\encoder.py:200, in JSONEncoder.encode(self, o)
    196         return encode_basestring(o)
    197 # This doesn't pass the iterator directly to ''.join() because the
    198 # exceptions aren't as detailed.  The list call should be roughly
    199 # equivalent to the PySequence_Fast that ''.join() would do.
--> 200 chunks = self.iterencode(o, _one_shot=True)
    201 if not isinstance(chunks, (list, tuple)):
    202     chunks = list(chunks)

File ~\AppData\Local\Programs\Python\Python311\Lib\json\encoder.py:258, in JSONEncoder.iterencode(self, o, _one_shot)
    253 else:
    254     _iterencode = _make_iterencode(
    255         markers, self.default, _encoder, self.indent, floatstr,
    256         self.key_separator, self.item_separator, self.sort_keys,
    257         self.skipkeys, _one_shot)
--> 258 return _iterencode(o, 0)

File ~\AppData\Local\Programs\Python\Python311\Lib\json\encoder.py:180, in JSONEncoder.default(self, o)
    161 def default(self, o):
    162     """Implement this method in a subclass such that it returns
    163     a serializable object for ``o``, or calls the base implementation
    164     (to raise a ``TypeError``).
   (...)
    178 
    179     """
--> 180     raise TypeError(f'Object of type {o.__class__.__name__} '
    181                     f'is not JSON serializable')

TypeError: Object of type Unset is not JSON serializable
marcoceppi commented 1 year ago

This is now fixed in 0.2.4 and up!