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 collects information about a given node of a `PyTables` database. 24""" 25 26__docformat__ = 'restructuredtext' 27 28import os.path 29 30import vitables.utils 31 32class NodeInfo(object): 33 """Collects information about a given node. 34 35 The following data and metadata can be collected: 36 37 * format of the database (generic `HDF5` or `PyTables`) 38 * filename of the database 39 * filepath of the database 40 * opening mode of the database 41 * size of the database 42 * node type 43 * node name 44 * node path 45 * for `tables.Group` nodes: 46 47 - attributes set instance and related info 48 - dictionary of nodes hanging from a group 49 - dictionary of groups hanging from a group 50 - dictionary of leaves hanging from a group 51 52 * for `tables.Table` nodes: 53 54 - columns names, datatypes and shapes 55 - number of rows and columns 56 - filters 57 - shape 58 - flavor 59 60 * for `tables.XArray` nodes: 61 62 - number of rows 63 - datatype 64 - filters 65 - shape 66 - flavor 67 68 :Parameter node_item: an instance of :meth:`RootGroupNode`, 69 :meth:`GroupNode` or :meth:`LeafNode`. 70 """ 71 72 def __init__(self, node_item): 73 """Collects information about a given node. 74 75 Some PyTables2.X string attributes are regular Python strings instead 76 of unicode strings and have to be explicitely converted to unicode. 77 """ 78 79 self.node = node_item.node 80 81 # The hosting File instance, filepath, filename and opening mode 82 self.filepath = str(node_item.filepath) 83 self.filename = os.path.basename(self.filepath) 84 self.h5file = self.node._v_file 85 mode = str(self.h5file.mode) 86 if mode == 'a': 87 self.mode = 'append' 88 elif mode == 'r': 89 self.mode = 'read-only' 90 else: 91 self.mode = 'read-write' 92 93 # The node type is a string with one of the following values: 94 # root group, group, table, vlarray, earray, carray, array 95 # or unimplemented 96 self.node_type = node_item.node_kind 97 self.file_type = self.format + ', ' + self.size 98 self.nodename = str(node_item.name) 99 self.nodepath = str(node_item.nodepath) 100 101 # The attributes set instance 102 self.asi = self.node._v_attrs 103 sysattrs_names = self.asi._v_attrnamessys 104 self.system_attrs = \ 105 dict((n, getattr(self.asi, n, None)) for n in sysattrs_names) 106 userattrs_names = self.asi._v_attrnamesuser 107 self.user_attrs = \ 108 dict((n, getattr(self.asi, n, None)) for n in userattrs_names) 109 110 # Properties for File instances 111 112 def _format(self): 113 """The format of the hosting `tables.File` instance""" 114 115 if self.h5file._isPTFile: 116 return 'PyTables file' 117 else: 118 return 'Generic HDF5 file' 119 120 format = property(fget=_format) 121 122 123 def _size(self): 124 """The size of the hosting `tables.File` instance""" 125 126 n_bytes = os.path.getsize(self.filepath) *1.0 127 kbytes = n_bytes/1024 128 mbytes = kbytes/1024 129 gbytes = mbytes/1024 130 tbytes = gbytes/1024 131 if kbytes < 1: 132 size = '{0:.0f} bytes'.format(n_bytes) 133 elif mbytes < 1: 134 size = '{0:.1f} KB'.format(kbytes) 135 elif gbytes < 1: 136 size = '{0:.1f} MB'.format(mbytes) 137 elif tbytes < 1: 138 size = '{0:.1f} GB'.format(gbytes) 139 else: 140 size = '{0:.1f} TB'.format(tbytes) 141 return size 142 143 size = property(fget=_size) 144 145 # Properties for Group instances 146 147 def _hangingNodes(self): 148 """The dictionary of nodes hanging from this node.""" 149 150 try: 151 return self.node._v_children 152 except AttributeError: 153 return {} 154 155 hanging_nodes = property(fget=_hangingNodes) 156 157 158 def _hangingGroups(self): 159 """The dictionary of groups hanging from this node.""" 160 161 try: 162 return self.node._v_groups 163 except AttributeError: 164 return {} 165 166 hanging_groups = property(fget=_hangingGroups) 167 168 169 def _hangingLeaves(self): 170 """The dictionary of leaves hanging from this node.""" 171 172 try: 173 return self.node._v_leaves 174 except AttributeError: 175 return {} 176 177 hanging_leaves = property(fget=_hangingLeaves) 178 179 180 def _hangingLinks(self): 181 """The dictionary of links hanging from this node.""" 182 183 try: 184 return self.node._v_links 185 except AttributeError: 186 return {} 187 188 hanging_links = property(fget=_hangingLinks) 189 190 191 # Properties for Leaf instances 192 193 def _type(self): 194 """The `PyTables` data type of the atom for `tables.Leaf` nodes.""" 195 196 if self.node_type.count('array'): 197 try: 198 return str(self.node.atom.type) 199 except AttributeError: 200 return None 201 elif self.node_type == 'table': 202 return 'record' 203 204 type = property(fget=_type) 205 206 207 def _nrows(self): 208 """The current number of rows in the `tables.Leaf` node.""" 209 210 try: 211 return self.node.shape[0] 212 except TypeError: # shape is None 213 return 0 214 except IndexError: # numpy scalar arrays have shape = () 215 return 1 216 217 nrows = property(fget=_nrows) 218 219 220 def _shape(self): 221 """The shape of data in the `tables.Leaf` node.""" 222 223 try: 224 return self.node.shape 225 except AttributeError: 226 return None 227 228 shape = property(fget=_shape) 229 230 231 def _flavor(self): 232 """The type of data object read from the `tables.Leaf` node.""" 233 234 try: 235 return str(self.node.flavor) 236 except AttributeError: 237 return None 238 239 flavor = property(fget=_flavor) 240 241 242 def _filters(self): 243 """Filters property for this `tables.Leaf` node.""" 244 245 try: 246 return self.node.filters 247 except AttributeError: 248 return None 249 250 filters = property(fget=_filters) 251 252 # Properties for Table instances 253 254 def _colNames(self): 255 """The list of names of top-level columns in a `tables.Table` node.""" 256 257 try: 258 return self.node.colnames 259 except AttributeError: 260 return [] 261 262 columns_names = property(fget=_colNames) 263 264 265 def _colPathNames(self): 266 """The list of paths of top-level columns in a `tables.Table` node.""" 267 268 try: 269 return self.node.colpathnames 270 except AttributeError: 271 return [] 272 273 columns_pathnames = property(fget=_colPathNames) 274 275 276 def _colTypes(self): 277 """ 278 Mapping with `tables.Table` field names and their `PyTables` datatypes. 279 """ 280 281 try: 282 return self.node.coltypes 283 except AttributeError: 284 return {} 285 286 columns_types = property(fget=_colTypes) 287 288 289 def _colShapes(self): 290 """ 291 Mapping with the `tables.Table` field names and their shapes. 292 """ 293 294 try: 295 coldescrs = self.node.coldescrs 296 return dict((k, v.shape) for (k, v) in coldescrs.items()) 297 except AttributeError: 298 return {} 299 300 columns_shapes = property(fget=_colShapes) 301 302 303 def _ncolumns(self): 304 """The current number of columns in the `tables.Table` node.""" 305 306 try: 307 return len(self.node.columns_names) 308 except AttributeError: 309 return None 310 311 ncolumns = property(fget=_ncolumns) 312 313 314 def _target(self): 315 """The target of a `tables.Link` node.""" 316 317 try: 318 return str(self.node.target) 319 except AttributeError: 320 return None 321 322 target = property(fget=_target) 323 324 325 def _link_type(self): 326 """The kind of link (i.e. soft or external) of a `tables.Link` node.""" 327 328 if self.target: 329 try: 330 link_type = 'external' 331 self.node.extfile 332 except AttributeError: 333 link_type = 'soft' 334 return link_type 335 else: 336 return None 337 338 link_type = property(fget=_link_type) 339 340 341