1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4#       Copyright (C) 2005-2007 Carabos Coop. V. All rights reserved
5#       Copyright (C) 2008-2019 Vicent Mas. All rights reserved
6#
7#       This program is free software: you can redistribute it and/or modify
8#       it under the terms of the GNU General Public License as published by
9#       the Free Software Foundation, either version 3 of the License, or
10#       (at your option) any later version.
11#
12#       This program is distributed in the hope that it will be useful,
13#       but WITHOUT ANY WARRANTY; without even the implied warranty of
14#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15#       GNU General Public License for more details.
16#
17#       You should have received a copy of the GNU General Public License
18#       along with this program.  If not, see <http://www.gnu.org/licenses/>.
19#
20#       Author:  Vicent Mas - vmas@vitables.org
21
22"""
23This module provides editing capabilities for PyTables soft and external links.
24
25The module defines methods for deleting, cutting, copying, pasting and
26moving links.
27"""
28
29__docformat__ = 'restructuredtext'
30
31import os
32
33import tables
34
35import vitables.utils
36
37
38
39class TLinkEditor(object):
40    """
41    An editor for `tables.Link` instances.
42    """
43
44    def __init__(self, dbdoc):
45        """
46        Initialises the tables.Link editor.
47
48        :Parameter h5file: the tables.File instance being operated
49        """
50
51        if not dbdoc.hidden_group:
52            dbdoc.createHiddenGroup()
53
54        self.h5file = dbdoc.h5file
55        self.hidden_group = dbdoc.hidden_group
56
57
58    def delete(self, nodepath):
59        """Delete a link.
60
61        :Parameters:
62
63        - `nodepath`: the full path of the node/link being deleted
64        """
65
66        try:
67            link = self.h5file.get_node(nodepath)
68            link.remove()
69            self.h5file.flush()
70        except (tables.NodeError, OSError):
71            vitables.utils.formatExceptionInfo()
72
73
74    def cut(self, nodepath):
75        """Moves a link to a hidden group of its database.
76
77        The cut node must be stored somewhere or it will no be possible
78        to paste it later. Storing it in the same database is extremely
79        fast independently of the node size. Storing it in other database
80        (i.e. in the temporary database) would have a cost which depends
81        on the size of the cut node.
82
83        :Parameters:
84
85        - `nodepath`: the path of the node being cut
86        """
87
88        nodename = os.path.basename(nodepath)
89        try:
90            # The hidden group should contain at most 1 node
91            for node in self.h5file.list_nodes(self.hidden_group):
92                self.h5file.deleteNode(node._v_pathname)
93
94            link = self.h5file.get_node(nodepath)
95            link.move(newparent=self.hidden_group, newname=nodename)
96            self.h5file.flush()
97        except(tables.NodeError, OSError):
98            vitables.utils.formatExceptionInfo()
99
100
101    def paste(self, link, parent, childname):
102        """Copy a link to a different location.
103
104        :Parameters:
105
106        - `link`: the tables.link instance being pasted
107        - `parent`: the new parent of the node being pasted
108        - `childname`: the new name of the node being pasted
109        """
110
111        try:
112            link.copy(newparent=parent, newname=childname,
113                overwrite=True, createparents=False)
114            self.h5file.flush()
115        except (tables.NodeError, OSError):
116            vitables.utils.formatExceptionInfo()
117
118
119    def rename(self, nodepath, new_name):
120        """
121        Rename the selected link from the object tree.
122
123        :Parameters:
124
125        - `nodepath`: the full path of the node being renamed
126        - `new_name`: the node new name
127        """
128
129        try:
130            link = self.h5file.get_node(nodepath)
131            link.rename(new_name)
132            self.h5file.flush()
133        except (tables.NodeError, OSError):
134            vitables.utils.formatExceptionInfo()
135
136
137    def move(self, childpath, dst_dbdoc, parentpath, childname):
138        """Move a ink to a different location.
139
140        :Parameters:
141
142        - `childpath`: the full path of the node being moved
143        - `dst_dbdoc`: the destination database (a :meth:`DBDoc` instance)
144        - `parentpath`: the full path of the new parent node
145        - `childname`: the name of the node in its final location
146        """
147
148        try:
149            dst_h5file = dst_dbdoc.h5file
150            parent_node = dst_h5file.get_node(parentpath)
151            link = self.h5file.get_node(childpath)
152            if self.h5file is dst_h5file:
153                link.move(newparent=parentpath, newname=childname)
154            else:
155                link.copy(newparent=parent_node, newname=childname)
156                dst_h5file.flush()
157                src_where, src_nodename = os.path.split(childpath)
158                self.h5file.remove_node(src_where, src_nodename, recursive=1)
159            self.h5file.flush()
160            return childname
161        except (tables.NodeError, OSError):
162            vitables.utils.formatExceptionInfo()
163            return None
164