-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement soft link and external link #87
base: dev
Are you sure you want to change the base?
Changes from all commits
afdd89f
a5742af
7eb782d
fe962eb
d9fbbdc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,7 +71,7 @@ class File(Group): | |
def __init__(self, directory, mode=None, allow_remove=False, | ||
name_validation=None, plugins=None): | ||
self._open_datasets = weakref.WeakValueDictionary({}) | ||
directory = pathlib.Path(directory) #.resolve() | ||
directory = pathlib.Path(directory).absolute() #.resolve() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this necessary? Not that I mind, just good to know why it was added. |
||
if directory.suffix != ".exdir": | ||
directory = directory.with_suffix(directory.suffix + ".exdir") | ||
self.user_mode = mode = mode or 'a' | ||
|
@@ -220,6 +220,12 @@ def __getitem__(self, name): | |
return self | ||
return super(File, self).__getitem__(path) | ||
|
||
def __setitem__(self, name, value): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this related to links or is it just something we have left out from before? Seems like this is something that has been missing on File regardless of links? |
||
path = utils.path.remove_root(name) | ||
if len(path.parts) < 1: | ||
return self | ||
return super(File, self).__setitem__(path, value) | ||
|
||
def __contains__(self, name): | ||
path = utils.path.remove_root(name) | ||
return super(File, self).__contains__(path) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,12 +19,15 @@ | |
import collections as abc | ||
|
||
from .exdir_object import Object | ||
from .links import Link, SoftLink, ExternalLink | ||
from .mode import assert_file_open, OpenMode, assert_file_writable | ||
from . import exdir_object as exob | ||
from . import exdir_file as exfile | ||
from . import dataset as ds | ||
from . import raw | ||
from .. import utils | ||
|
||
|
||
def _data_to_shape_and_dtype(data, shape, dtype): | ||
if data is not None: | ||
if shape is None: | ||
|
@@ -36,6 +39,7 @@ def _data_to_shape_and_dtype(data, shape, dtype): | |
dtype = np.float32 | ||
return shape, dtype | ||
|
||
|
||
def _assert_data_shape_dtype_match(data, shape, dtype): | ||
if data is not None: | ||
if shape is not None and np.product(shape) != np.product(data.shape): | ||
|
@@ -53,6 +57,7 @@ def _assert_data_shape_dtype_match(data, shape, dtype): | |
) | ||
return | ||
|
||
|
||
class Group(Object): | ||
""" | ||
Container of other groups and datasets. | ||
|
@@ -403,6 +408,8 @@ def __getitem__(self, name): | |
return self._dataset(name) | ||
elif meta_data[exob.EXDIR_METANAME][exob.TYPE_METANAME] == exob.GROUP_TYPENAME: | ||
return self._group(name) | ||
elif meta_data[exob.EXDIR_METANAME][exob.TYPE_METANAME] == exob.LINK_TYPENAME: | ||
return self._link(name) | ||
else: | ||
error_string = ( | ||
"Object {name} has data type {type}.\n" | ||
|
@@ -413,6 +420,25 @@ def __getitem__(self, name): | |
) | ||
raise NotImplementedError(error_string) | ||
|
||
def _link(self, name, get_link=False): | ||
link_meta = self._group(name).meta[exob.EXDIR_METANAME][exob.LINK_METANAME] | ||
print(link_meta) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be removed :) |
||
if link_meta[exob.TYPE_METANAME] == exob.LINK_SOFTNAME: | ||
if get_link: | ||
result = SoftLink(link_meta[exob.LINK_TARGETNAME]) | ||
else: | ||
result = self[link_meta[exob.LINK_TARGETNAME]] | ||
elif link_meta[exob.TYPE_METANAME] == exob.LINK_EXTERNALNAME: | ||
if get_link: | ||
result = ExternalLink( | ||
link_meta[exob.LINK_FILENAME], | ||
link_meta[exob.LINK_TARGETNAME]) | ||
else: | ||
external_file = exfile.File( | ||
link_meta[exob.LINK_FILENAME], 'r') | ||
result = external_file[link_meta[exob.LINK_TARGETNAME]] | ||
return result | ||
|
||
def _dataset(self, name): | ||
return ds.Dataset( | ||
root_directory=self.root_directory, | ||
|
@@ -439,6 +465,13 @@ def __setitem__(self, name, value): | |
self[path.parent][path.name] = value | ||
return | ||
|
||
if isinstance(value, Link): | ||
link_group = self.create_group(name) | ||
# if value.path not in self.file: | ||
# return # TODO works when merging with lepmik/close | ||
link_group.meta[exob.EXDIR_METANAME].update(value._link) | ||
return | ||
|
||
if name not in self: | ||
self.create_dataset(name, data=value) | ||
return | ||
|
@@ -509,20 +542,22 @@ def __len__(self): | |
assert_file_open(self.file) | ||
return len([a for a in self]) | ||
|
||
def get(self, key): | ||
def get(self, name, get_link=False): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the getter should first try to see if it is an object or a link, instead of forcing the user to tell it to expect a link or not. This is also how h5py works. |
||
""" | ||
Get an object in the group. | ||
Parameters | ||
---------- | ||
key : str | ||
The key of the desired object | ||
name : str | ||
The name of the desired object | ||
Returns | ||
------- | ||
Value or None if object does not exist. | ||
""" | ||
assert_file_open(self.file) | ||
if key in self: | ||
return self[key] | ||
if name in self: | ||
if get_link: | ||
return self._link(name, get_link) | ||
return self[name] | ||
else: | ||
return None | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
try: | ||
import pathlib | ||
except ImportError as e: | ||
try: | ||
import pathlib2 as pathlib | ||
except ImportError: | ||
raise e | ||
from . import exdir_file | ||
from .exdir_object import Object, is_nonraw_object_directory | ||
from .constants import * | ||
|
||
|
||
class Link(Object): | ||
""" | ||
Super class for link objects | ||
""" | ||
def __init__(self, path): | ||
self.path = path | ||
|
||
@property | ||
def _link(self): | ||
return {TYPE_METANAME: LINK_TYPENAME} | ||
|
||
def __eq__(self, other): | ||
return self._link.get(LINK_METANAME) == other._link.get(LINK_METANAME) | ||
|
||
|
||
class SoftLink(Link): | ||
def __init__(self, path): | ||
super(SoftLink, self).__init__( | ||
path=path | ||
) | ||
|
||
@property | ||
def _link(self): | ||
result = { | ||
TYPE_METANAME: LINK_TYPENAME, | ||
LINK_METANAME: { | ||
TYPE_METANAME: LINK_SOFTNAME, | ||
LINK_TARGETNAME: self.path | ||
} | ||
} | ||
return result | ||
|
||
def __repr__(self): | ||
return "Exdir SoftLink '{}' at {}".format(self.path, id(self)) | ||
|
||
|
||
class ExternalLink(Link): | ||
def __init__(self, filename, path): | ||
super(ExternalLink, self).__init__( | ||
path=path | ||
) | ||
self.filename = filename | ||
|
||
@property | ||
def _link(self): | ||
result = { | ||
TYPE_METANAME: LINK_TYPENAME, | ||
LINK_METANAME: { | ||
TYPE_METANAME: LINK_EXTERNALNAME, | ||
LINK_TARGETNAME: self.path, | ||
LINK_FILENAME: str(self.filename) | ||
} | ||
} | ||
return result | ||
|
||
def __repr__(self): | ||
return "Exdir SoftLink '{}' at {}".format(self.path, id(self)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I prefer if the type is
soft_link
,external_link
, etc. That reduces the level of conditional nesting - you can sayif type == "external_link"
instead ofif type == "link" and link_type == "external"
. And then have the meta-groups besoft_link
andexternal_link
as well. It just reduces the confusion of which variables can go together. (No-one will think that they can just change the target fromexternal
tosoft
and still keep thefile
, for instance.