CAVEconnectome / CAVEclient

This is the python client for accessing REST APIs within the Connectome Annotation Versioning Engine.
https://caveconnectome.github.io/CAVEclient/
MIT License
19 stars 12 forks source link

NoneType has no attribute `pop` #171

Open j6k4m8 opened 3 months ago

j6k4m8 commented 3 months ago

Here's a simple example after authenticating that doesn't seem to work:

from caveclient import CAVEclient
client = CAVEclient(datastack_name="minnie65_public_v117")
client.materialize.get_tables()

This results in the following error (re-formatted by me for readability). This appears for most of the public datastacks I've tried. Not sure how to debug the server-side trace, but looks like this is not a local config issue?

HTTPError                                 Traceback (most recent call last)
Cell In[116], line 3
      1 from caveclient import CAVEclient
      2 client = CAVEclient(datastack_name="minnie65_public_v117")
----> 3 client.materialize.get_tables()

File ###python3.11/site-packages/caveclient/frameworkclient.py:449, in CAVEclientFull.materialize(self)
    444 """
    445 A client for the materialization service. See [client.materialize](../client_api/materialize.md)
    446 for more information.
    447 """
    448 if self._materialize is None:
--> 449     self._materialize = MaterializationClient(
    450         server_address=self.local_server,
    451         auth_client=self.auth,
    452         datastack_name=self._datastack_name,
    453         synapse_table=self.info.get_datastack_info().get("synapse_table", None),
    454         max_retries=self._max_retries,
    455         pool_maxsize=self._pool_maxsize,
    456         pool_block=self._pool_block,
    457         over_client=self,
    458         desired_resolution=self.desired_resolution,
    459     )
    460 return self._materialize

File ###python3.11/site-packages/caveclient/materializationengine.py:200, in MaterializationClient(server_address, datastack_name, auth_client, cg_client, synapse_table, api_version, version, verify, max_retries, pool_maxsize, pool_block, desired_resolution, over_client)
    188 endpoints, api_version = _api_endpoints(
    189     api_version,
    190     SERVER_KEY,
   (...)
    196     verify=verify,
    197 )
    199 MatClient = client_mapping[api_version]
--> 200 return MatClient(
    201     server_address,
    202     auth_header,
    203     api_version,
    204     endpoints,
    205     SERVER_KEY,
    206     datastack_name,
    207     cg_client=cg_client,
    208     synapse_table=synapse_table,
    209     version=version,
    210     verify=verify,
    211     max_retries=max_retries,
    212     pool_maxsize=pool_maxsize,
    213     pool_block=pool_block,
    214     over_client=over_client,
    215     desired_resolution=desired_resolution,
    216 )

File ###python3.11/site-packages/caveclient/materializationengine.py:1914, in MaterializationClientV3.__init__(self, *args, **kwargs)
   1912 tables = None
   1913 if self.fc is not None:
-> 1914     if metadata[0].result() is not None and metadata[1].result() is not None:
   1915         tables = TableManager(self.fc, metadata[0].result(), metadata[1].result())
   1916 self._tables = tables

File ~/.pyenv/versions/3.11.7/lib/python3.11/concurrent/futures/_base.py:449, in Future.result(self, timeout)
    447     raise CancelledError()
    448 elif self._state == FINISHED:
--> 449     return self.__get_result()
    451 self._condition.wait(timeout)
    453 if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]:

File ~/.pyenv/versions/3.11.7/lib/python3.11/concurrent/futures/_base.py:401, in Future.__get_result(self)
    399 if self._exception:
    400     try:
--> 401         raise self._exception
    402     finally:
    403         # Break a reference cycle with the exception in self._exception
    404         self = None

File ~/.pyenv/versions/3.11.7/lib/python3.11/concurrent/futures/thread.py:58, in _WorkItem.run(self)
     55     return
     57 try:
---> 58     result = self.fn(*self.args, **self.kwargs)
     59 except BaseException as exc:
     60     self.future.set_exception(exc)

File ###python3.11/site-packages/cachetools/__init__.py:737, in cached.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
    735 except KeyError:
    736     pass  # key not found
--> 737 v = func(*args, **kwargs)
    738 try:
    739     cache[k] = v

File ###python3.11/site-packages/caveclient/materializationengine.py:1957, in MaterializationClientV3.get_tables_metadata(self, datastack_name, version, log_warning)
   1954 url = self._endpoints["all_tables_metadata"].format_map(endpoint_mapping)
   1956 response = self.session.get(url)
-> 1957 all_metadata = handle_response(response, log_warning=log_warning)
   1958 for metadata_d in all_metadata:
   1959     vx = metadata_d.pop("voxel_resolution_x", None)

File ###python3.11/site-packages/caveclient/base.py:88, in handle_response(response, as_json, log_warning)
     86 def handle_response(response, as_json=True, log_warning=True):
     87     """Deal with potential errors in endpoint response and return json for default case"""
---> 88     _raise_for_status(response, log_warning=log_warning)
     89     _check_authorization_redirect(response)
     90     if as_json:

File ###python3.11/site-packages/caveclient/base.py:79, in _raise_for_status(r, log_warning)
     71     http_error_msg = "%s Server Error: %s for url: %s content:%s" % (
     72         r.status_code,
     73         reason,
     74         r.url,
     75         r.content,
     76     )
     78 if http_error_msg:
---> 79     raise requests.HTTPError(http_error_msg, response=r)
     80 if log_warning:
     81     warning = r.headers.get("Warning")

Followed by this server response / traceback:

HTTPError: 500 Server Error: 'NoneType' object has no attribute 'pop' for url: https://minnie.microns-daf.com/materialize/api/v3/datastack/minnie65_public_v117/version/117/tables/metadata 
content:b'{"code": 500, "message": "\'NoneType\' object has no attribute \'pop\'", "traceback": [ ... ]}\n'

The traceback is this array:


Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1516, in full_dispatch_request
      rv = self.dispatch_request()
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1502, in dispatch_request
      return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File "/usr/local/lib/python3.9/site-packages/flask_restx/api.py", line 403, in wrapper
      resp = resource(*args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/flask/views.py", line 84, in view
      return current_app.ensure_sync(self.dispatch_request)(*args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/flask_restx/resource.py", line 49, in dispatch_request
      resp = meth(*args, **kwargs)
  File "/app/./materializationengine/blueprints/reset_auth.py", line 12, in decorated_function
      return f(*args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/middle_auth_client/decorators.py", line 265, in decorated_function
      return f(*args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/middle_auth_client/decorators.py", line 396, in decorated_function
      return f(*args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/flask_limiter/extension.py", line 1186, in __inner
      R, flask.current_app.ensure_sync(cast(Callable[P, R], obj))(*a, **k)
  File "/app/./materializationengine/blueprints/client/datastack.py", line 80, in wrapper
      return f(*args, **kwargs)
  File "/app/./materializationengine/blueprints/client/api2.py", line 758, in get
      ann_table = ann_md.pop("annotation_table", None)
AttributeError: 'NoneType' object has no attribute 'pop'
ceesem commented 3 months ago

As a workaround, there doesn't seem to be an issue on minnie65_public, which is what we suggest using these days and gives access to all the long term releases:

client = CAVEclient(datastack_name="minnie65_public")
client.materialize.version = 117
client.materialize.get_tables()
j6k4m8 commented 3 months ago

Perfect, thank you @ceesem!!

[edit] here's the notebook with the old datastack, btw!