Skip to content

Commit

Permalink
Merge pull request #41 from jupyterlab/n-dim-support-w-parsing
Browse files Browse the repository at this point in the history
n-dimensional support via parse_index
  • Loading branch information
telamonian authored Nov 20, 2020
2 parents 130d17b + bde7a61 commit 7a278a9
Show file tree
Hide file tree
Showing 21 changed files with 758 additions and 351 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.autoversion
lib/
node_modules/

Expand All @@ -18,6 +19,7 @@ MANIFEST
/scratch/*.cutie
/scratch/*.h5
/scratch/*.hdf5
/scratch/Untitled*

# temp/system files
*~
Expand All @@ -35,3 +37,7 @@ MANIFEST
*.code-workspace
.history
.vscode

# tmp dev stuff
json.py
json.ts
74 changes: 44 additions & 30 deletions jupyterlab_hdf/baseHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
# Distributed under the terms of the Modified BSD License.

import h5py
import json
import os
import simplejson
import traceback
from tornado import gen
from tornado.httpclient import HTTPError
Expand All @@ -14,6 +14,7 @@
from notebook.utils import url_path_join

# from .config import HdfConfig
from .exception import JhdfError

__all__ = ['HdfBaseManager', 'HdfFileManager', 'HdfBaseHandler']

Expand All @@ -22,31 +23,38 @@
class HdfBaseManager:
"""Base class for implementing HDF5 handling
"""
def __init__(self, notebook_dir):
def __init__(self, log, notebook_dir):
self.log = log
self.notebook_dir = notebook_dir

def _get(self, f, uri, row, col):
def _get(self, f, uri, **kwargs):
raise NotImplementedError

def get(self, relfpath, uri, row, col):
def get(self, relfpath, uri, **kwargs):
def _handleErr(code, msg):
raise HTTPError(code, '\n'.join((
msg,
f'relfpath: {relfpath}, uri: {uri}, row: {row}, col: {col}'
)))
extra = dict((
('relfpath', relfpath),
('uri', uri),
*kwargs.items(),
))

if isinstance(msg, dict):
# encode msg as json
msg['debugVars'] = {**msg.get('debugVars', {}), **extra}
msg = simplejson.dumps(msg, ignore_nan=True)
else:
msg = '\n'.join((
msg,
', '.join(f'{key}: {val}' for key,val in extra.items())
))

self.log.error(msg)
raise HTTPError(code, msg)

if not relfpath:
msg = f'The request was malformed; fpath should not be empty.'
_handleErr(400, msg)

if row and not col:
msg = f'The request was malformed; row slice was specified, but col slice was empty.'
_handleErr(400, msg)

if col and not row:
msg = f'The request was malformed; col slice was specified, but row slice was empty.'
_handleErr(400, msg)

fpath = url_path_join(self.notebook_dir, relfpath)

if not os.path.exists(fpath):
Expand All @@ -61,7 +69,12 @@ def _handleErr(code, msg):
f'Error: {traceback.format_exc()}')
_handleErr(401, msg)
try:
out = self._get(fpath, uri, row, col)
out = self._get(fpath, uri, **kwargs)
except JhdfError as e:
msg = e.args[0]
msg['traceback'] = traceback.format_exc()
msg['type'] = 'JhdfError'
_handleErr(400, msg)
except Exception as e:
msg = (f'Found and opened file, error getting contents from object specified by the uri.\n'
f'Error: {traceback.format_exc()}')
Expand All @@ -72,11 +85,11 @@ def _handleErr(code, msg):
class HdfFileManager(HdfBaseManager):
"""Implements base HDF5 file handling
"""
def _get(self, fpath, uri, row, col):
def _get(self, fpath, uri, **kwargs):
with h5py.File(fpath, 'r') as f:
return self._getFromFile(f, uri, row, col)
return self._getFromFile(f, uri, **kwargs)

def _getFromFile(self, f, uri, row, col):
def _getFromFile(self, f, uri, **kwargs):
raise NotImplementedError

## handler
Expand All @@ -90,20 +103,21 @@ def initialize(self, notebook_dir):
raise NotImplementedError

self.notebook_dir = notebook_dir
self.manager = self.managerClass(notebook_dir=notebook_dir)
self.manager = self.managerClass(log=self.log, notebook_dir=notebook_dir)

@gen.coroutine
def get(self, path):
"""Based on an api request, get either the contents of a group or a
slice of a dataset and return it as serialized JSON.
"""
uri = '/' + self.get_query_argument('uri').lstrip('/')
row = self.getQueryArguments('row', int)
col = self.getQueryArguments('col', int)

try:
self.finish(json.dumps(self.manager.get(path, uri, row, col)))
_kws = ('atleast_2d', 'ixstr', 'subixstr')
_vals = (self.get_query_argument(kw, default=None) for kw in _kws)
kwargs = {kw:(val if val else None) for kw,val in zip(_kws, _vals)}

try:
self.finish(simplejson.dumps(self.manager.get(path, uri, **kwargs), ignore_nan=True))
except HTTPError as err:
self.set_status(err.code)
response = err.response.body if err.response else str(err.code)
Expand All @@ -112,8 +126,8 @@ def get(self, path):
err.message
)))

def getQueryArguments(self, key, func=None):
if func is not None:
return [func(x) for x in self.get_query_argument(key).split(',')] if key in self.request.query_arguments else None
else:
return [x for x in self.get_query_argument(key).split(',')] if key in self.request.query_arguments else None
# def getQueryArguments(self, key, func=None):
# if func is not None:
# return [func(x) for x in self.get_query_argument(key).split(',')] if key in self.request.query_arguments else None
# else:
# return [x for x in self.get_query_argument(key).split(',')] if key in self.request.query_arguments else None
10 changes: 6 additions & 4 deletions jupyterlab_hdf/contents.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,29 @@
import h5py

from .baseHandler import HdfFileManager, HdfBaseHandler
from .util import dsetContentDict, dsetDict, groupDict, uriJoin, uriName
from .util import dsetContentDict, dsetDict, groupDict, jsonize, uriJoin, uriName

__all__ = ['HdfContentsManager', 'HdfContentsHandler']

## manager
class HdfContentsManager(HdfFileManager):
"""Implements HDF5 contents handling
"""
def _getFromFile(self, f, uri, row, col):
def _getFromFile(self, f, uri, ixstr, **kwargs):
obj = f[uri]

if isinstance(obj, h5py.Group):
return [(groupDict if isinstance(val, h5py.Group) else dsetDict)
(name=name, uri=uriJoin(uri, name))
for name,val in obj.items()]
else:
elif isinstance(obj, h5py.Dataset):
return dsetDict(
name=uriName(uri),
uri=uri,
content=dsetContentDict(obj, row, col),
content=jsonize(dsetContentDict(obj, ixstr)),
)
else:
raise ValueError("unknown h5py obj: %s" % obj)


## handler
Expand Down
14 changes: 10 additions & 4 deletions jupyterlab_hdf/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.

import h5py

from .baseHandler import HdfFileManager, HdfBaseHandler
from .util import dsetChunk

Expand All @@ -15,8 +13,16 @@
class HdfDataManager(HdfFileManager):
"""Implements HDF5 data handling
"""
def _getFromFile(self, f, uri, row, col):
return dsetChunk(f[uri], row, col)
def _getFromFile(self, f, uri, ixstr, subixstr=None, atleast_2d=False, **kwargs):
# # DEBUG: uncomment for logging
# from .util import dsetContentDict, parseSubindex
# logd = dsetContentDict(f[uri], ixstr=ixstr)
# logd['subixstr'] = subixstr
# if subixstr is not None:
# logd['ixcompound'] = parseSubindex(ixstr, subixstr, f[uri].shape)
# self.log.info('{}'.format(logd))

return dsetChunk(f[uri], ixstr, subixstr=subixstr, atleast_2d=atleast_2d).tolist()


## handler
Expand Down
9 changes: 9 additions & 0 deletions jupyterlab_hdf/exception.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-

# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.

__all__ = ['JhdfError']

class JhdfError(Exception):
pass
2 changes: 1 addition & 1 deletion jupyterlab_hdf/snippet.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
class HdfSnippetManager(HdfBaseManager):
"""Implements HDF5 contents handling
"""
def _get(self, fpath, uri, row, col):
def _get(self, fpath, uri, ixstr, **kwargs):
return dsetTemp.format(fpath=fpath, uri=uri)


Expand Down
Loading

0 comments on commit 7a278a9

Please sign in to comment.