Skip to content

Commit

Permalink
Add segment props (#176)
Browse files Browse the repository at this point in the history
* WIP

* fix formatting

* add version reqs

* improve server version handling for no server version

* fix error

* Bump version: 5.18.0 → 5.18.1

* fix: non-kwarg error for nglstate feature

* Bump version: 5.18.1 → 5.19.0
  • Loading branch information
fcollman authored Apr 8, 2024
1 parent 4200850 commit 465d47e
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 5.18.0
current_version = 5.19.0
commit = True
tag = True

Expand Down
2 changes: 1 addition & 1 deletion caveclient/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "5.18.0"
__version__ = "5.19.0"

from .frameworkclient import CAVEclient

Expand Down
36 changes: 22 additions & 14 deletions caveclient/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ def __init__(
self._api_version = api_version
self._endpoints = endpoints
self._fc = over_client
self._server_version = self._get_version()

@property
def fc(self):
Expand All @@ -234,7 +235,11 @@ def api_version(self):

def _get_version(self) -> Optional[Version]:
endpoint_mapping = self.default_url_mapping
url = self._endpoints.get("get_version", None).format_map(endpoint_mapping)
endpoint = self._endpoints.get("get_version", None)
if endpoint is None:
return None

url = endpoint.format_map(endpoint_mapping)
response = self.session.get(url)
if response.status_code == 404: # server doesn't have this endpoint yet
return None
Expand Down Expand Up @@ -349,8 +354,11 @@ def _version_fails_constraint(version: Version, constraint: str = None):
if constraint is None:
return False
else:
specifier = SpecifierSet(constraint)
return version not in specifier
if version is None:
return True
else:
specifier = SpecifierSet(constraint)
return version not in specifier


@parametrized
Expand Down Expand Up @@ -399,17 +407,17 @@ def wrapper(*args, **kwargs):
)

raise ServerIncompatibilityError(msg)

for kwarg, kwarg_constraint in kwarg_use_constraints.items():
if _version_fails_constraint(self.server_version, kwarg_constraint):
msg = (
f"Use of keyword argument `{kwarg}` in `{method.__name__}` "
"is only permitted "
f"for server version {kwarg_constraint}, your server "
f"version is {self.server_version}. Contact your system "
"administrator to update the server version."
)
raise ServerIncompatibilityError(msg)
if kwarg_use_constraints is not None:
for kwarg, kwarg_constraint in kwarg_use_constraints.items():
if _version_fails_constraint(self.server_version, kwarg_constraint):
msg = (
f"Use of keyword argument `{kwarg}` in `{method.__name__}` "
"is only permitted "
f"for server version {kwarg_constraint}, your server "
f"version is {self.server_version}. Contact your system "
"administrator to update the server version."
)
raise ServerIncompatibilityError(msg)

out = method(*args, **kwargs)
return out
Expand Down
1 change: 0 additions & 1 deletion caveclient/chunkedgraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ def __init__(
self._default_timestamp = timestamp
self._table_name = table_name
self._segmentation_info = None
self._server_version = self._get_version()

@property
def default_url_mapping(self):
Expand Down
5 changes: 5 additions & 0 deletions caveclient/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@
"upload_state_w_id": json_v1 + "/post/{state_id}",
"get_state": json_v1 + "/{state_id}",
"get_state_raw": json_v1 + "/raw/{state_id}",
"get_properties": json_v1 + "/property/{state_id}/info",
"upload_properties": json_v1 + "/property/post",
"get_properties_raw": json_v1 + "/property/raw/{state_id}",
"upload_properties_w_id": json_v1 + "/property/post/{state_id}",
"get_version": json_v1 + "/version",
}

json_legacy = "{json_server_address}/nglstate"
Expand Down
73 changes: 72 additions & 1 deletion caveclient/jsonservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from .base import (
ClientBase,
_api_endpoints,
_check_version_compatibility,
handle_response,
)
from .endpoints import (
Expand Down Expand Up @@ -186,6 +187,27 @@ def get_state_json(self, state_id):
handle_response(response, as_json=False)
return json.loads(response.content)

@_check_version_compatibility(method_constraint=">=0.4.0")
def get_property_json(self, state_id):
"""Download a Neuroglancer JSON state
Parameters
----------
state_id : int
ID of a JSON state uploaded to the state service.
Returns
-------
dict
JSON specifying a Neuroglancer state.
"""
url_mapping = self.default_url_mapping
url_mapping["state_id"] = state_id
url = self._endpoints["get_property"].format_map(url_mapping)
response = self.session.get(url)
handle_response(response, as_json=False)
return json.loads(response.content)

def upload_state_json(self, json_state, state_id=None, timestamp=None):
"""Upload a Neuroglancer JSON state
Expand Down Expand Up @@ -224,6 +246,45 @@ def upload_state_json(self, json_state, state_id=None, timestamp=None):
response_re = re.search(".*\/(\d+)", str(response.content))
return int(response_re.groups()[0])

@_check_version_compatibility(">=0.4.0")
def upload_property_json(self, property_json, state_id=None, timestamp=None):
"""Upload a Neuroglancer JSON state
Parameters
----------
propery_json : dict
Dict representation of a neuroglancer segment properties json
state_id : int
ID of a JSON state uploaded to the state service.
Using a state_id is an admin feature.
timestamp: time.time
Timestamp for json state date. Requires state_id.
Returns
-------
int
state_id of the uploaded JSON state
"""
url_mapping = self.default_url_mapping

if state_id is None:
url = self._endpoints["upload_properties"].format_map(url_mapping)
else:
url_mapping = self.default_url_mapping
url_mapping["state_id"] = state_id
url = self._endpoints["upload_properties_w_id"].format_map(url_mapping)

response = self.session.post(
url,
data=json.dumps(
property_json,
default=neuroglancer_json_encoder,
),
)
handle_response(response, as_json=False)
response_re = re.search(".*\/(\d+)", str(response.content))
return int(response_re.groups()[0])

def save_state_json_local(self, json_state, filename, overwrite=False):
"""Save a Neuroglancer JSON state to a JSON file locally.
Expand Down Expand Up @@ -251,6 +312,7 @@ def build_neuroglancer_url(
ngl_url=None,
target_site=None,
static_url=False,
format_propeties=False,
):
"""Build a URL for a Neuroglancer deployment that will automatically retrieve specified state.
If the datastack is specified, this is prepopulated from the info file field "viewer_site".
Expand All @@ -269,7 +331,8 @@ def build_neuroglancer_url(
Default is None.
static_url : bool
If True, treats "state_id" as a static URL directly to the JSON and does not use the state service.
format_propeties : bool
If True, formats the url as a segment_properties info file
Returns
-------
str
Expand Down Expand Up @@ -304,6 +367,14 @@ def build_neuroglancer_url(
target_site_error = "A specified target_site must be one of 'seunglab', 'cave-explorer' or 'mainline'"
raise ValueError(target_site_error)

if format_propeties:
url_mapping = self.default_url_mapping
url_mapping["state_id"] = state_id
get_state_url = self._endpoints["get_properties"][:-5].format_map(
url_mapping
)
url = "precomputed://" + auth_text + get_state_url
return url
if static_url:
url = ngl_url + parameter_text + state_id
else:
Expand Down

0 comments on commit 465d47e

Please sign in to comment.