Changeset - 9757ad98ea09
[Not reviewed]
default
0 2 0
Mads Kiilerich - 6 years ago 2020-03-28 21:07:08
mads@kiilerich.com
Grafted from: a234de987f8e
vcs: simplify nodes kind handling

Avoid pytype's very reasonable confusion over the _kind handling.

Node.kind is actually only ever set in __init__, so there is not much need for
a paranoid setter.
2 files changed with 5 insertions and 24 deletions:
0 comments (0 inline, 0 general)
kallithea/lib/vcs/nodes.py
Show inline comments
 
@@ -107,81 +107,67 @@ class Node(object):
 
            raise NodeError("Only DirNode and its subclasses may be "
 
                            "initialized with empty path")
 
        self.kind = kind
 
        #self.dirs, self.files = [], []
 
        if self.is_root() and not self.is_dir():
 
            raise NodeError("Root node cannot be FILE kind")
 

	
 
    @LazyProperty
 
    def parent(self):
 
        parent_path = self.get_parent_path()
 
        if parent_path:
 
            if self.changeset:
 
                return self.changeset.get_node(parent_path)
 
            return DirNode(parent_path)
 
        return None
 

	
 
    @LazyProperty
 
    def name(self):
 
        """
 
        Returns name of the node so if its path
 
        then only last part is returned.
 
        """
 
        return self.path.rstrip('/').split('/')[-1]
 

	
 
    def _get_kind(self):
 
        return self._kind
 

	
 
    def _set_kind(self, kind):
 
        if hasattr(self, '_kind'):
 
            raise NodeError("Cannot change node's kind")
 
        else:
 
            self._kind = kind
 
            # Post setter check (path's trailing slash)
 
            if self.path.endswith('/'):
 
                raise NodeError("Node's path cannot end with slash")
 

	
 
    kind = property(_get_kind, _set_kind)
 

	
 
    def __eq__(self, other):
 
        if type(self) is not type(other):
 
            return False
 
        if self._kind != other._kind:
 
        if self.kind != other.kind:
 
            return False
 
        if self.path != other.path:
 
            return False
 
        if self.is_file():
 
            return self.content == other.content
 
        else:
 
            # For DirNode's check without entering each dir
 
            self_nodes_paths = list(sorted(n.path for n in self.nodes))
 
            other_nodes_paths = list(sorted(n.path for n in self.nodes))
 
            return self_nodes_paths == other_nodes_paths
 

	
 
    def __lt__(self, other):
 
        if self._kind < other._kind:
 
        if self.kind < other.kind:
 
            return True
 
        if self._kind > other._kind:
 
        if self.kind > other.kind:
 
            return False
 
        if self.path < other.path:
 
            return True
 
        if self.path > other.path:
 
            return False
 
        if self.is_file():
 
            return self.content < other.content
 
        else:
 
            # For DirNode's check without entering each dir
 
            self_nodes_paths = list(sorted(n.path for n in self.nodes))
 
            other_nodes_paths = list(sorted(n.path for n in self.nodes))
 
            return self_nodes_paths < other_nodes_paths
 

	
 
    def __repr__(self):
 
        return '<%s %r>' % (self.__class__.__name__, self.path)
 

	
 
    def get_parent_path(self):
 
        """
 
        Returns node's parent path or empty string if node is root.
 
        """
 
        if self.is_root():
 
            return ''
 
        return posixpath.dirname(self.path.rstrip('/')) + '/'
 

	
 
@@ -566,44 +552,44 @@ class DirNode(Node):
 

	
 

	
 
class RootNode(DirNode):
 
    """
 
    DirNode being the root node of the repository.
 
    """
 

	
 
    def __init__(self, nodes=(), changeset=None):
 
        super(RootNode, self).__init__(path='', nodes=nodes,
 
            changeset=changeset)
 

	
 
    def __repr__(self):
 
        return '<%s>' % self.__class__.__name__
 

	
 

	
 
class SubModuleNode(Node):
 
    """
 
    represents a SubModule of Git or SubRepo of Mercurial
 
    """
 
    is_binary = False
 
    size = 0
 

	
 
    def __init__(self, name, url, changeset=None, alias=None):
 
        # Note: Doesn't call Node.__init__!
 
        self.path = name
 
        self.path = name.rstrip('/')
 
        self.kind = NodeKind.SUBMODULE
 
        self.alias = alias
 
        # we have to use emptyChangeset here since this can point to svn/git/hg
 
        # submodules we cannot get from repository
 
        self.changeset = EmptyChangeset(changeset, alias=alias)
 
        self.url = url
 

	
 
    def __repr__(self):
 
        return '<%s %r @ %s>' % (self.__class__.__name__, self.path,
 
                                 getattr(self.changeset, 'short_id', ''))
 

	
 
    @LazyProperty
 
    def name(self):
 
        """
 
        Returns name of the node so if its path
 
        then only last part is returned.
 
        """
 
        org = self.path.rstrip('/').rsplit('/', 1)[-1]
 
        return '%s @ %s' % (org, self.changeset.short_id)
kallithea/tests/vcs/test_nodes.py
Show inline comments
 
@@ -28,53 +28,48 @@ class TestNodeBasic(object):
 
        for path in wrong_paths:
 
            with pytest.raises(NodeError):
 
                Node(path, NodeKind.DIR)
 

	
 
    def test_name(self):
 
        node = Node('', NodeKind.DIR)
 
        assert node.name == ''
 

	
 
        node = Node('path', NodeKind.FILE)
 
        assert node.name == 'path'
 

	
 
        node = Node('path/', NodeKind.DIR)
 
        assert node.name == 'path'
 

	
 
        node = Node('some/path', NodeKind.FILE)
 
        assert node.name == 'path'
 

	
 
        node = Node('some/path/', NodeKind.DIR)
 
        assert node.name == 'path'
 

	
 
    def test_root_node(self):
 
        with pytest.raises(NodeError):
 
            Node('', NodeKind.FILE)
 

	
 
    def test_kind_setter(self):
 
        node = Node('', NodeKind.DIR)
 
        with pytest.raises(NodeError):
 
            setattr(node, 'kind', NodeKind.FILE)
 

	
 
    def _test_parent_path(self, node_path, expected_parent_path):
 
        """
 
        Tests if node's parent path are properly computed.
 
        """
 
        node = Node(node_path, NodeKind.DIR)
 
        parent_path = node.get_parent_path()
 
        assert parent_path.endswith('/') or node.is_root() and parent_path == ''
 
        assert parent_path == expected_parent_path, \
 
            "Node's path is %r and parent path is %r but should be %r" \
 
            % (node.path, parent_path, expected_parent_path)
 

	
 
    def test_parent_path(self):
 
        test_paths = (
 
            # (node_path, expected_parent_path)
 
            ('', ''),
 
            ('some/path/', 'some/'),
 
            ('some/longer/path/', 'some/longer/'),
 
        )
 
        for node_path, expected_parent_path in test_paths:
 
            self._test_parent_path(node_path, expected_parent_path)
 

	
 
    '''
 
    def _test_trailing_slash(self, path):
 
        if not path.endswith('/'):
 
@@ -83,49 +78,49 @@ class TestNodeBasic(object):
 
            with pytest.raises(NodeError):
 
                Node(path=path, kind=kind)
 

	
 
    def test_trailing_slash(self):
 
        for path in ('/', 'foo/', 'foo/bar/', 'foo/bar/biz/'):
 
            self._test_trailing_slash(path)
 
    '''
 

	
 
    def test_is_file(self):
 
        node = Node('any', NodeKind.FILE)
 
        assert node.is_file()
 

	
 
        node = FileNode('any')
 
        assert node.is_file()
 
        with pytest.raises(AttributeError):
 
            getattr(node, 'nodes')
 

	
 
    def test_is_dir(self):
 
        node = Node('any_dir', NodeKind.DIR)
 
        assert node.is_dir()
 

	
 
        node = DirNode('any_dir')
 

	
 
        assert node.is_dir()
 
        with pytest.raises(NodeError):
 
        with pytest.raises(AttributeError):  # Note: this used to raise NodeError
 
            getattr(node, 'content')
 

	
 
    def test_dir_node_iter(self):
 
        nodes = [
 
            DirNode('docs'),
 
            DirNode('tests'),
 
            FileNode('bar'),
 
            FileNode('foo'),
 
            FileNode('readme.txt'),
 
            FileNode('setup.py'),
 
        ]
 
        dirnode = DirNode('', nodes=nodes)
 
        for node in dirnode:
 
            node == dirnode.get_node(node.path)
 

	
 
    def test_node_state(self):
 
        """
 
        Without link to changeset nodes should raise NodeError.
 
        """
 
        node = FileNode('anything')
 
        with pytest.raises(NodeError):
 
            getattr(node, 'state')
 
        node = DirNode('anything')
 
        with pytest.raises(NodeError):
0 comments (0 inline, 0 general)