Skip to content

Commit f3e8274

Browse files
authored
Merge pull request #18 from idle-code/feature/linter
Feature/linter
2 parents 7646045 + 7429d13 commit f3e8274

File tree

10 files changed

+712
-43
lines changed

10 files changed

+712
-43
lines changed

.pylintrc

Lines changed: 564 additions & 0 deletions
Large diffs are not rendered by default.

Pipfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ name = "pypi"
55

66
[packages]
77
coverage = "==5.0a1"
8+
pylint = "*"
9+
git-pylint-commit-hook = "*"
810

911
[dev-packages]
1012

Pipfile.lock

Lines changed: 91 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contextshell/action.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,13 @@ def action_from_function(function_to_wrap: Callable) -> Action:
4343
return CallableAction(function_to_wrap, action_path)
4444

4545

46-
class ActionExecutor:
46+
class Executor(ABC):
47+
@abstractmethod
48+
def execute(self, target: NodePath, action_name: NodePath, args: ActionArgsPack = None):
49+
raise NotImplementedError()
50+
51+
52+
class ActionExecutor(Executor):
4753
"""Interface for backends allowing execution of arbitrary actions"""
4854

4955
def find_action(self, target: NodePath, action: NodePath) -> Optional[Action]:
@@ -66,7 +72,7 @@ def unpack_argument_tree(action_args: ActionArgsPack) -> Tuple[PositionalArgumen
6672
args[key] = value
6773
else:
6874
kwargs[key.to_python_name()] = value
69-
assert len(args) == 0 or max(args.keys()) < len(args)+len(kwargs)
75+
assert not args or max(args.keys()) < len(args)+len(kwargs)
7076
positional_args = [a[1] for a in sorted(args.items())]
7177
return positional_args, kwargs
7278

contextshell/backends/FilesystemTree.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def __init__(self, root_directory_path: str):
1717
self.register_builtin_action(action_from_function(self.list_actions_action))
1818

1919
def _to_os_path(self, *paths: NodePath) -> Path:
20-
node_paths = map(lambda p: NodePath(p), paths)
20+
node_paths = map(NodePath, paths)
2121
os_paths = map(lambda p: Path('').joinpath(*p), node_paths)
2222
return self.root_directory_path.joinpath(*os_paths)
2323

contextshell/backends/NodeTree.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,20 @@ def get(self):
2222

2323
def set(self, new_value):
2424
"""Store provided value in this node"""
25-
if type(self._value) != type(new_value):
26-
raise TypeError("Cannot assign value with type '{}' to '{}' node".format(type(new_value).__name__,
27-
type(self._value).__name__))
25+
if not isinstance(new_value, type(self._value)):
26+
new_type = type(new_value).__name__
27+
current_type = type(self._value).__name__
28+
raise TypeError(
29+
f"Cannot assign value with type '{new_type}' to '{current_type}' node")
2830
self._value = new_value
2931

3032
def list(self):
3133
"""List names of the subnodes"""
3234
names = map(lambda p: p[0], self._subnodes)
3335
index = 0
3436
indexed_names = []
35-
for n in names:
36-
indexed_names.append(n if n is not None else index)
37+
for name in names:
38+
indexed_names.append(name if name is not None else index)
3739
index += 1
3840
return indexed_names
3941

@@ -42,7 +44,7 @@ def append(self, node, name: str = None):
4244
if node is None:
4345
raise ValueError("Cannot append None as node")
4446
if name is not None:
45-
if len(name) == 0:
47+
if not name:
4648
raise NameError("Invalid appended node name - empty")
4749
if self.get_node(name) is not None:
4850
raise NameError("Node '{}' already exists".format(name))
@@ -52,9 +54,9 @@ def append(self, node, name: str = None):
5254
def get_node(self, name: str = None, index: int = None) -> Optional['Node']:
5355
"""Return subnode with provided name or index"""
5456
if name is not None:
55-
for p in self._subnodes:
56-
if p[0] == name:
57-
return p[1]
57+
for name_node_pair in self._subnodes:
58+
if name_node_pair[0] == name:
59+
return name_node_pair[1]
5860
elif index is not None:
5961
if 0 <= index < len(self._subnodes):
6062
return self._subnodes[index][1]
@@ -153,7 +155,7 @@ def install_action(self, target: NodePath, action: Action):
153155
self.create(NodePath.join(target, '@actions', action.name), action)
154156

155157
def find_first_in(self, candidate_paths: List[NodePath]) -> Optional[Node]:
156-
if candidate_paths is None or len(candidate_paths) == 0:
158+
if candidate_paths is None or not candidate_paths:
157159
raise ValueError("No candidate paths provided")
158160
for path in candidate_paths:
159161
node = self._resolve_optional_path(path)
@@ -177,10 +179,9 @@ def list_actions(self, path: NodePath) -> List[NodePath]:
177179
action_paths = self.list(NodePath.join(path, '@actions'))
178180
action_paths = sorted(action_paths)
179181

180-
if len(path) == 0: # Root
182+
if not path: # Root
181183
return action_paths
182-
else:
183-
return action_paths + self.list_actions(path.base_path)
184+
return action_paths + self.list_actions(path.base_path)
184185

185186
def install_global_type(self, node_type):
186187
self.install_type(NodePath('.'), node_type)
@@ -240,7 +241,7 @@ def _resolve_optional_path(self, path: NodePath, root: Node = None) -> Optional[
240241
raise ValueError("Could not resolve relative paths")
241242
root = self.root
242243
assert root is not None
243-
if len(path) == 0:
244+
if not path:
244245
return root
245246

246247
next_branch_name = path[0]
@@ -254,7 +255,7 @@ def _create_path(self, path: NodePath, root: Node = None) -> Node:
254255
raise ValueError("Could not resolve relative paths")
255256
root = self.root
256257
assert root is not None
257-
if len(path) == 0:
258+
if not path:
258259
return root
259260

260261
next_branch_name = path[0]

contextshell/backends/VirtualTree.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
from collections import OrderedDict
2+
from typing import Dict
23

3-
from ..action import ActionExecutor, ActionArgsPack
4+
from ..action import Executor, ActionArgsPack
45
from ..path import NodePath
56

67

7-
class VirtualTree(ActionExecutor):
8+
class VirtualTree(Executor):
89
"""Abstract frontend allowing embedding (mounting) of more specific tree roots"""
910

1011
def __init__(self):
11-
self.mounts: OrderedDict[NodePath, ActionExecutor] = OrderedDict()
12+
self.mounts: Dict[NodePath, Executor] = OrderedDict()
1213

1314
# TODO: rename to attach/detach
14-
def mount(self, path: NodePath, root: ActionExecutor):
15+
def mount(self, path: NodePath, root: Executor):
1516
if path.is_relative:
1617
raise ValueError("Could not mount relative path")
1718
if path in self.mounts:
@@ -27,7 +28,7 @@ def path_length_extractor(path_root_pair):
2728
def umount(self, path: NodePath):
2829
del self.mounts[path]
2930

30-
def execute(self, target: NodePath, action: NodePath, args: ActionArgsPack = None):
31+
def execute(self, target: NodePath, action_name: NodePath, args: ActionArgsPack = None):
3132
if target.is_relative:
3233
raise ValueError("Could not invoke action with relative target path")
3334
if not args:
@@ -36,6 +37,5 @@ def execute(self, target: NodePath, action: NodePath, args: ActionArgsPack = Non
3637
if path.is_parent_of(target):
3738
remapped_target = target.relative_to(path)
3839
remapped_target.is_absolute = True
39-
return root.execute(remapped_target, action, args)
40-
else:
41-
raise RuntimeError("Could not find provider for path: '{}'".format(target))
40+
return root.execute(remapped_target, action_name, args)
41+
raise RuntimeError("Could not find provider for path: '{}'".format(target))

contextshell/command.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def _to_string(param):
2727

2828

2929
class CommandInterpreter:
30+
"""Actually executes commands on provided backend tree"""
3031
def __init__(self, tree: ActionExecutor) -> None:
3132
self.tree = tree
3233

@@ -66,7 +67,7 @@ def tokenize(text: str) -> List[str]:
6667

6768
def finish_token():
6869
nonlocal tok, tokens
69-
if len(tok) > 0:
70+
if tok:
7071
tok = convert_token_type(tok)
7172
tokens.append(tok)
7273
tok = ''
@@ -103,7 +104,7 @@ def __init__(self):
103104

104105
def parse(self, command_line: str) -> Optional[Command]:
105106
tokens = tokenize(command_line)
106-
if len(tokens) == 0:
107+
if not tokens:
107108
return None # ignore empty lines
108109
if tokens[0] == '#':
109110
return None # ignore comments
@@ -116,17 +117,16 @@ def _parse_scope(self, token_iterator) -> Command:
116117
for tok in token_iterator:
117118
if tok == '{':
118119
parts.append(self._parse_scope(token_iterator))
119-
elif tok == '}':
120-
break
121-
else:
120+
elif tok != '}':
122121
parts.append(tok)
122+
else:
123+
break
123124

124125
if ':' in parts:
125126
cmd = Command(parts[2])
126127
cmd.target = parts[0]
127128
cmd.arguments = parts[3:]
128-
return cmd
129129
else:
130130
cmd = Command(parts[0])
131131
cmd.arguments = parts[1:]
132-
return cmd
132+
return cmd

contextshell/path.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def to_python_name(self) -> str:
3030
name = name.lstrip(NodePath.separator).replace(NodePath.separator, '_')
3131
return name
3232

33-
def __init__(self, representation=[], absolute=False):
33+
def __init__(self, representation=None, absolute=False):
3434
super().__init__()
3535
self.is_absolute = absolute
3636
if isinstance(representation, int):
@@ -40,10 +40,12 @@ def __init__(self, representation=[], absolute=False):
4040
elif isinstance(representation, NodePath):
4141
self.is_absolute = representation.is_absolute
4242
self.extend(representation)
43-
elif isinstance(representation, list) or isinstance(representation, tuple):
43+
elif isinstance(representation, (list, tuple)):
4444
# TODO: check element's types?
4545
# TODO: is it ever used?
4646
self.extend(representation)
47+
elif representation is None:
48+
pass
4749
else:
4850
raise ValueError("Could not convert {} to NodePath".format(representation))
4951

@@ -65,21 +67,21 @@ def base_path(self):
6567
@property
6668
def base_name(self):
6769
"""Returns last path element"""
68-
if len(self) == 0:
70+
if not self:
6971
return None
7072
return self[-1]
7173

7274
def is_parent_of(self, other: 'NodePath') -> bool:
7375
"""Checks if provided path prefix matches self"""
7476
other = NodePath.cast(other)
7577
if self.is_absolute != other.is_absolute:
76-
raise ValueError("Cannot compare absolute and relative paths: {} and {}".format(self, other))
78+
raise ValueError(f"Cannot compare absolute and relative paths: {self} and {other}")
7779
return NodePath(other[:len(self)], absolute=other.is_absolute) == self
7880

7981
def relative_to(self, other) -> 'NodePath':
8082
"""Make current path relative to provided one by removing common prefix"""
8183
if not other.is_parent_of(self):
82-
raise ValueError("{} is not relative to {}".format(self, other))
84+
raise ValueError(f"{self} is not relative to {other}")
8385
return NodePath(self[len(other):], absolute=False)
8486

8587
@staticmethod
@@ -94,15 +96,16 @@ def _parse_path(self, text):
9496
text = text.strip()
9597
if text.startswith(NodePath.separator):
9698
self.is_absolute = True
97-
new_path = map(NodePath._to_path_part, [part for part in text.split(NodePath.separator) if len(part) > 0])
99+
non_empty_path_parts = [part for part in text.split(NodePath.separator) if part]
100+
new_path = map(NodePath._to_path_part, non_empty_path_parts)
98101
self.extend(new_path)
99102

100103
def __eq__(self, other):
101104
other = NodePath.cast(other)
102105
return self.is_absolute == other.is_absolute and self[:] == other[:]
103106

104107
def __ne__(self, other):
105-
return not (self == other)
108+
return not self == other
106109

107110
def __str__(self):
108111
text_representation = NodePath.separator.join(map(str, self))

0 commit comments

Comments
 (0)