Skip to content
This repository has been archived by the owner on Oct 24, 2024. It is now read-only.

Dynamic filepath key completion #217

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 27 additions & 16 deletions datatree/datatree.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,28 +517,39 @@ def _item_sources(self) -> Iterable[Mapping[Any, Any]]:
# immediate child nodes
yield self.children

def _ipython_key_completions_(self) -> List[str]:
"""Provide method for the key-autocompletions in IPython.
See http://ipython.readthedocs.io/en/stable/config/integrating.html#tab-completion
For the details.
# Argument `prefix` requires changes to ipython's autocompleter, see https://github.com/ipython/ipython/issues/12420
# TODO should I overload this method with the old signature too? Is that even possible?
def _ipython_key_completions_(self, prefix: str) -> List[str]:
"""
Provide method for the key-autocompletions in IPython.
See http://ipython.readthedocs.io/en/stable/config/integrating.html#tab-completion
for the details.

# TODO allow auto-completing relative string paths, e.g. `dt['path/to/../ <tab> node'`
# Would require changes to ipython's autocompleter, see https://github.com/ipython/ipython/issues/12420
# Instead for now we only list direct paths to all node in subtree explicitly

items_on_this_node = self._item_sources
full_file_like_paths_to_all_nodes_in_subtree = {
node.path[1:]: node for node in self.subtree
}
Provides dynamic auto-completion based on path typed out so far, including
allowing auto-completing relative string paths, e.g. `dt['path/to/../ <tab> node'`
"""

all_item_sources = itertools.chain(
items_on_this_node, [full_file_like_paths_to_all_nodes_in_subtree]
)
# TODO allow for possiblity of error being raised here?
resolvable_path_prefix = NodePath(prefix).parent

try:
current_node = self[resolvable_path_prefix]
except KeyError:
# no matches
# TODO is it correct to return literally nothing here?
return []

# TODO ensure absolute paths are supported also
# suggest path-like syntax as autocompletion options too
path_syntax_sources = ["./"]
if current_node is not self.root:
# suggest pointing up to parent node
path_syntax_sources.append("../")

all_item_sources = itertools.chain(current_node._item_sources, path_syntax_sources)
items = {
item
for source in all_item_sources
for source in all_item_sources,
for item in source
if isinstance(item, str)
}
Expand Down
27 changes: 23 additions & 4 deletions datatree/tests/test_datatree.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,14 +577,33 @@ def test_attribute_access(self, create_test_datatree):

def test_ipython_key_completions(self, create_test_datatree):
dt = create_test_datatree()
key_completions = dt._ipython_key_completions_()

node_keys = [node.path[1:] for node in dt.subtree]
assert all(node_key in key_completions for node_key in node_keys)

# vars / coords
var_keys = list(dt.variables.keys())
assert all(var_key in key_completions for var_key in var_keys)

# dims
dim_keys = list(dt.dims.keys())

# immediate children
children_keys = dt.children.keys()
assert children_keys in dt._ipython_key_completions_(prefix='s')

# grandchildren
list_of_childrens_children = [list(gc.path for gc in c.children.values()) for c in dt.children.values()]
grandchild_keys = list(itertools.chain.from_iterable(list_of_childrens_children))
assert grandchild_keys in dt._ipython_key_completions_(prefix='set1/s')
assert grandchild_keys not in dt._ipython_key_completions_(prefix='set')

# relative paths
child = dt["set1"]
parent_keys = ["../set1", "../set2", ...]
assert parent_keys in child._ipython_key_completions_(prefix="../")

# TODO absolute paths

# TODO same directory (single dot)


class TestRestructuring:
def test_drop_nodes(self):
Expand Down