Skip to content

Commit 18d6aeb

Browse files
committed
Get rid of ActionFinder (in favor of NodeTreeRoot methods)
1 parent 2ecdac5 commit 18d6aeb

16 files changed

+167
-233
lines changed

.idea/fileColors.xml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contextshell/Action.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55

66
class Action(ABC):
77
def __init__(self, name: NodePath):
8+
assert isinstance(name, NodePath)
89
assert name.is_relative
9-
self.name = name
10+
self.name: NodePath = name
1011

1112
@abstractmethod
12-
def __call__(self, target: NodePath, action: NodePath, arguments: Dict[Union[NodePath, int], Any]):
13+
def invoke(self, target: NodePath, action: NodePath, arguments: Dict[Union[NodePath, int], Any]):
1314
raise NotImplementedError()

contextshell/ActionFinder.py

Lines changed: 0 additions & 34 deletions
This file was deleted.

contextshell/CallableAction.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66

77

88
class CallableAction(Action):
9-
def __init__(self, implementation: Callable):
9+
def __init__(self, implementation: Callable, name: NodePath):
10+
super().__init__(name)
1011
self.implementation = implementation
1112

12-
def __call__(self, target: NodePath, action: NodePath, arguments: Dict[Union[NodePath, int], Any]):
13+
def invoke(self, target: NodePath, action: NodePath, arguments: Dict[Union[NodePath, int], Any]):
14+
#print("Invoked with:", *args)
1315
args, kwargs = CallableAction.unpack_argument_tree(arguments)
14-
return self.implementation(target, action, *args, **kwargs)
16+
return self.implementation(target, *args, **kwargs)
1517

1618
@staticmethod
1719
def unpack_argument_tree(arguments: Dict[Union[NodePath, int], Any]) -> Tuple[List[Any], Dict[NodePath, Any]]:
@@ -23,3 +25,11 @@ def unpack_argument_tree(arguments: Dict[Union[NodePath, int], Any]) -> Tuple[Li
2325
else:
2426
kwargs[key] = value
2527
return args, kwargs
28+
29+
30+
def action_from_function(method_to_wrap: Callable) -> Action:
31+
action_name: str = method_to_wrap.__name__
32+
if action_name.endswith('_action'):
33+
action_name = action_name[:-len('_action')]
34+
action_name = action_name.replace('_', '.')
35+
return CallableAction(method_to_wrap, NodePath(action_name))

contextshell/CommandInterpreter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def execute(self, command: Command):
1616
target_path = NodePath.cast(target_path)
1717
action_path = NodePath.cast(self._evaluate(command.name))
1818
arguments = map(self._evaluate, command.arguments)
19-
19+
# TODO: parse arguments into OrderedDict[Union[int, NodePath], Any] as in Action.invoke interface
2020
return self.tree.execute(target_path, action_path, *arguments)
2121

2222
def _evaluate(self, part):

contextshell/NodeTreeRoot.py

Lines changed: 41 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,68 +2,59 @@
22
from contextshell.NodePath import NodePath
33
from contextshell.TreeRoot import TreeRoot
44
from contextshell.Action import Action
5-
from typing import Callable, List, Optional
5+
from contextshell.CallableAction import action_from_function
6+
from typing import Callable, List, Optional, Dict, Union, Any
67

78

89
# CHECK: how to implement TemporaryTreeRoot (based on NodeTreeRoot)
910
class NodeTreeRoot(TreeRoot):
1011
"""Frontend to the (passive) node-based data storage"""
1112
def __init__(self):
1213
self.root = self.create_node(None)
13-
from contextshell.ActionFinder import ActionFinder
14-
self.action_finder = ActionFinder(self)
1514
self.install_default_actions()
1615

17-
def install_default_actions(self):
18-
def create(tree: NodeTreeRoot, target: NodePath, action: NodePath, name, value=None):
19-
tree.create(NodePath.join(target, name), value)
20-
21-
self.action_finder.install_action(".", "create", create)
22-
23-
def exists(tree: NodeTreeRoot, target: NodePath, action: NodePath, name):
24-
return tree.exists(NodePath.join(target, name))
25-
26-
self.action_finder.install_action(".", "exists", exists)
27-
28-
def get(tree: NodeTreeRoot, target: NodePath, action: NodePath):
29-
return tree.get(target)
16+
def create_action(self, target: NodePath, path: str, value=None):
17+
self.create(NodePath.join(target, path), value)
3018

31-
self.action_finder.install_action(".", "get", get)
19+
def exists_action(self, target: NodePath, path: str) -> bool:
20+
return self.exists(NodePath.join(target, path))
3221

33-
def set_action(tree: NodeTreeRoot, target: NodePath, action: NodePath, new_value):
34-
return tree.set(target, new_value)
22+
def get_action(self, target: NodePath):
23+
return self.get(target)
3524

36-
self.action_finder.install_action(".", "set", set_action)
25+
def set_action(self, target: NodePath, new_value):
26+
return self.set(target, new_value)
3727

38-
def list_action(tree: NodeTreeRoot, target: NodePath, action: NodePath):
39-
all_list = tree.list(target)
40-
return list(filter(lambda p: not self.is_attribute(p), all_list))
28+
def list_action(self, target: NodePath):
29+
all_list = self.list(target)
30+
return list(filter(lambda p: not self.is_attribute(p), all_list))
4131

42-
self.action_finder.install_action(".", "list", list_action)
32+
def list_all_action(self, target: NodePath):
33+
return self.list(target)
4334

44-
def list_all(tree: NodeTreeRoot, target: NodePath, action: NodePath):
45-
return tree.list(target)
35+
def list_attributes_action(self, target: NodePath):
36+
all_list = self.list(target)
37+
return list(filter(self.is_attribute, all_list))
4638

47-
self.action_finder.install_action(".", "list.all", list_all)
39+
def list_actions_action(self, target: NodePath):
40+
# FIXME: use the same mechanism as in self.find_action
41+
actions_branch = NodePath.join(target, '@actions')
42+
return self.list(actions_branch)
4843

49-
def list_attributes(tree: NodeTreeRoot, target: NodePath, action: NodePath):
50-
all_list = tree.list(target)
51-
return list(filter(self.is_attribute, all_list))
44+
def remove_action(self, target: NodePath):
45+
# CHECK: use 'path' argument?
46+
return self.remove(target)
5247

53-
self.action_finder.install_action(".", "list.attributes", list_attributes)
54-
55-
def list_actions(tree: NodeTreeRoot, target: NodePath, action: NodePath):
56-
# FIXME: use self.action_finder or other way of listing available actions
57-
from contextshell.ActionFinder import ActionFinder
58-
actions_branch = NodePath.join(target, ActionFinder.actions_branch_name)
59-
return tree.list(actions_branch)
60-
61-
self.action_finder.install_action(".", "list.actions", list_actions)
62-
63-
def remove(tree: NodeTreeRoot, target: NodePath, action: NodePath):
64-
return tree.remove(target)
65-
66-
self.action_finder.install_action(".", "remove", remove)
48+
def install_default_actions(self):
49+
self.install_global_action(action_from_function(self.create_action))
50+
self.install_global_action(action_from_function(self.exists_action))
51+
self.install_global_action(action_from_function(self.get_action))
52+
self.install_global_action(action_from_function(self.set_action))
53+
self.install_global_action(action_from_function(self.list_action))
54+
self.install_global_action(action_from_function(self.list_all_action))
55+
self.install_global_action(action_from_function(self.list_attributes_action))
56+
self.install_global_action(action_from_function(self.list_actions_action))
57+
self.install_global_action(action_from_function(self.remove_action))
6758

6859
def install_global_action(self, action: Action):
6960
self.install_action(NodePath('.'), action)
@@ -93,7 +84,7 @@ def _find_action_in(self, target: NodePath, action: NodePath) -> Optional[Action
9384
return action_implementation
9485

9586
def _is_action_implementation(self, node_value) -> bool:
96-
return isinstance(node_value, Callable)
87+
return isinstance(node_value, Action)
9788

9889
# def install_type(self, type: NodeType):
9990
# raise NotImplementedError()
@@ -115,10 +106,13 @@ def is_action(self, path: NodePath):
115106
return self._is_action_implementation(node_value)
116107

117108
def execute(self, target: NodePath, action: NodePath, *args):
118-
action_impl = self.action_finder.find_action(target, action)
109+
#print("Execute: {}: {} {}".format(target, action, args))
110+
action_impl = self.find_action(target, action)
119111
if action_impl is None:
120112
raise NameError("Could not find action named '{}'".format(action))
121-
return action_impl(self, target, action, *args)
113+
from collections import OrderedDict # FIXME: Temporary, until execute interface changes
114+
arguments = OrderedDict(enumerate(args))
115+
return action_impl.invoke(target, action, arguments)
122116

123117
def create_node(self, value):
124118
return Node(value)

contextshell/TreeRoot.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44

55
class TreeRoot(ABC):
66
@abstractmethod
7-
def execute(self, target: NodePath, action: NodePath, *args):
7+
def execute(self, target: NodePath, action: NodePath, *args): #FIXME: use Dict[Union[NodePath, int], Any] as arguments
88
raise NotImplementedError()
Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,68 @@
11
from contextshell.NodePath import NodePath
22
from contextshell.TreeRoot import TreeRoot
3+
from contextshell.NodeTreeRoot import NodeTreeRoot
34
from tests.functional.TestExecutor import script_test
45
from tests.functional.ShellTestsBase import NodeTreeTestsBase
56
import unittest
67

78

89
class ActionResolvingTests(NodeTreeTestsBase):
9-
def install_custom_actions(self, finder):
10-
def parent_action(tree: TreeRoot, target: NodePath, action: NodePath):
10+
def install_custom_actions(self, tree: NodeTreeRoot):
11+
from contextshell.CallableAction import action_from_function
12+
13+
def parent(target: NodePath):
1114
return "PARENT"
1215

13-
finder.install_action(".", "parent_action", parent_action)
16+
tree.install_global_action(action_from_function(parent))
1417

15-
def child_action(tree: TreeRoot, target: NodePath, action: NodePath):
18+
def child(target: NodePath):
1619
return "CHILD"
1720

18-
finder.install_action(".child", "child_action", child_action)
21+
tree.install_action(NodePath(".child"), action_from_function(child))
1922

20-
def partial_action(tree: TreeRoot, target: NodePath, action: NodePath):
23+
def multi_part(target: NodePath):
2124
pass
2225

23-
finder.install_action(".", "partial.action", partial_action)
26+
tree.install_global_action(action_from_function(multi_part))
2427

2528
@script_test
2629
def test_unknown_action(self):
2730
"""
28-
$ .: unknown_action
29-
NameError: Could not find action named 'unknown_action'
31+
$ .: unknown
32+
NameError: Could not find action named 'unknown'
3033
"""
3134

3235
@script_test
3336
def test_parent_action_from_child(self):
3437
"""
35-
$ .child: parent_action
38+
$ .child: parent
3639
PARENT
3740
"""
3841

3942
@script_test
4043
def test_child_action_from_child(self):
4144
"""
42-
$ .child: child_action
45+
$ .child: child
4346
CHILD
4447
"""
4548

4649
@script_test
4750
def test_parent_action_from_parent(self):
4851
"""
49-
$ .: parent_action
52+
$ .: parent
5053
PARENT
5154
"""
5255

5356
@script_test
5457
def test_child_action_from_parent(self):
5558
"""
56-
$ .: child_action
57-
NameError: Could not find action named 'child_action'
59+
$ .: child
60+
NameError: Could not find action named 'child'
5861
"""
5962

6063
@script_test
6164
def test_non_action_invoke(self):
6265
"""
63-
$ .: partial
64-
NameError: Could not find action named 'partial'
66+
$ .: multi
67+
NameError: Could not find action named 'multi'
6568
"""

tests/functional/ParserTypesTests.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66

77

88
class ParserTypesTests(NodeTreeTestsBase):
9-
def install_custom_actions(self, finder):
10-
def type_of(tree: NodeTreeRoot, target: NodePath, action: NodePath, value):
11-
return type(value).__name__
9+
def install_custom_actions(self, tree: NodeTreeRoot):
10+
def type_of(target: NodePath, value_to_check):
11+
return type(value_to_check).__name__
1212

13-
finder.install_action(".", "type.of", type_of)
13+
from contextshell.CallableAction import action_from_function
14+
tree.install_global_action(action_from_function(type_of))
1415

1516
@script_test
1617
def test_int(self):

tests/functional/ShellTestsBase.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from contextshell.CommandInterpreter import CommandInterpreter
66
from contextshell.VirtualTree import VirtualTree
77
from contextshell.NodeTreeRoot import NodeTreeRoot
8-
from contextshell.ActionFinder import ActionFinder
98

109

1110
class VirtualTreeTestsBase(unittest.TestCase, ABC):
@@ -25,8 +24,8 @@ def register_roots(self, virtual_tree: VirtualTree):
2524
class NodeTreeTestsBase(VirtualTreeTestsBase):
2625
def register_roots(self, virtual_tree: VirtualTree):
2726
tree_root = NodeTreeRoot()
28-
self.install_custom_actions(tree_root.action_finder)
27+
self.install_custom_actions(tree_root)
2928
virtual_tree.mount(NodePath("."), tree_root)
3029

31-
def install_custom_actions(self, action_finder: ActionFinder):
30+
def install_custom_actions(self, tree: NodeTreeRoot):
3231
pass

0 commit comments

Comments
 (0)