Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/tables/path.py: 43%
58 statements
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-10 06:15 +0000
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-10 06:15 +0000
1"""Functionality related with node paths in a PyTables file.
3Variables
4=========
6`__docformat`__
7 The format of documentation strings in this module.
9"""
11import re
12import warnings
13import keyword
15from .exceptions import NaturalNameWarning
17__docformat__ = 'reStructuredText'
18"""The format of documentation strings in this module."""
21_python_id_re = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
22"""Python identifier regular expression."""
24_reserved_id_re = re.compile('^_[cfgv]_')
25"""PyTables reserved identifier regular expression.
27- c: class variables
28- f: class public methods
29- g: class private methods
30- v: instance variables
31"""
33_hidden_name_re = re.compile('^_[pi]_')
34"""Nodes with a name *matching* this expression are considered hidden.
36For instance, ``name`` whould be visible while ``_i_name`` would not.
37"""
39_hidden_path_re = re.compile('/_[pi]_')
40"""Nodes with a path *containing* this expression are considered hidden.
42For instance, a node with a pathname like ``/a/b/c`` would be visible
43while nodes with pathnames like ``/a/c/_i_x`` or ``/a/_p_x/y`` would
44not.
45"""
47_warnInfo = (
48 "you will not be able to use natural naming to access this object; "
49 "using ``getattr()`` will still work, though")
50"""Warning printed when a name will not be reachable through natural naming"""
53def check_attribute_name(name):
54 """Check the validity of the `name` of an attribute in AttributeSet.
56 If the name is not valid, a ``ValueError`` is raised. If it is
57 valid but it can not be used with natural naming, a
58 `NaturalNameWarning` is issued.
60 >>> warnings.simplefilter("ignore")
61 >>> check_attribute_name('a')
62 >>> check_attribute_name('a_b')
63 >>> check_attribute_name('a:b') # NaturalNameWarning
64 >>> check_attribute_name('/a/b') # NaturalNameWarning
65 >>> check_attribute_name('/') # NaturalNameWarning
66 >>> check_attribute_name('.') # NaturalNameWarning
67 >>> check_attribute_name('__members__')
68 Traceback (most recent call last):
69 ...
70 ValueError: ``__members__`` is not allowed as an object name
71 >>> check_attribute_name(1)
72 Traceback (most recent call last):
73 ...
74 TypeError: object name is not a string: 1
75 >>> check_attribute_name('')
76 Traceback (most recent call last):
77 ...
78 ValueError: the empty string is not allowed as an object name
79 """
80 if not isinstance(name, str): # Python >= 2.3
81 raise TypeError(f"object name is not a string: {name!r}")
83 if name == '':
84 raise ValueError("the empty string is not allowed as an object name")
86 # Check whether `name` is a valid Python identifier.
87 if not _python_id_re.match(name):
88 warnings.warn("object name is not a valid Python identifier: %r; "
89 "it does not match the pattern ``%s``; %s"
90 % (name, _python_id_re.pattern, _warnInfo),
91 NaturalNameWarning, stacklevel=2)
92 return
94 # However, Python identifiers and keywords have the same form.
95 if keyword.iskeyword(name):
96 warnings.warn("object name is a Python keyword: %r; %s"
97 % (name, _warnInfo), NaturalNameWarning, stacklevel=2)
98 return
100 # Still, names starting with reserved prefixes are not allowed.
101 if _reserved_id_re.match(name):
102 raise ValueError("object name starts with a reserved prefix: %r; "
103 "it matches the pattern ``%s``"
104 % (name, _reserved_id_re.pattern))
106 # ``__members__`` is the only exception to that rule.
107 if name == '__members__':
108 raise ValueError("``__members__`` is not allowed as an object name")
111def check_name_validity(name):
112 """Check the validity of the `name` of a Node object, which more limited
113 than attribute names.
115 If the name is not valid, a ``ValueError`` is raised. If it is
116 valid but it can not be used with natural naming, a
117 `NaturalNameWarning` is issued.
119 >>> warnings.simplefilter("ignore")
120 >>> check_name_validity('a')
121 >>> check_name_validity('a_b')
122 >>> check_name_validity('a:b') # NaturalNameWarning
123 >>> check_name_validity('/a/b')
124 Traceback (most recent call last):
125 ...
126 ValueError: the ``/`` character is not allowed in object names: '/a/b'
127 >>> check_name_validity('.')
128 Traceback (most recent call last):
129 ...
130 ValueError: ``.`` is not allowed as an object name
131 >>> check_name_validity('')
132 Traceback (most recent call last):
133 ...
134 ValueError: the empty string is not allowed as an object name
136 """
137 check_attribute_name(name)
139 # Check whether `name` is a valid HDF5 name.
140 # http://hdfgroup.org/HDF5/doc/UG/03_Model.html#Structure
141 if name == '.':
142 raise ValueError("``.`` is not allowed as an object name")
143 elif '/' in name:
144 raise ValueError("the ``/`` character is not allowed "
145 "in object names: %r" % name)
148def join_path(parentpath, name):
149 """Join a *canonical* `parentpath` with a *non-empty* `name`.
151 .. versionchanged:: 3.0
152 The *parentPath* parameter has been renamed into *parentpath*.
154 >>> join_path('/', 'foo')
155 '/foo'
156 >>> join_path('/foo', 'bar')
157 '/foo/bar'
158 >>> join_path('/foo', '/foo2/bar')
159 '/foo/foo2/bar'
160 >>> join_path('/foo', '/')
161 '/foo'
163 """
165 if name.startswith('./'): # Support relative paths (mainly for links)
166 name = name[2:]
167 if parentpath == '/' and name.startswith('/'):
168 pstr = '%s' % name
169 elif parentpath == '/' or name.startswith('/'):
170 pstr = f'{parentpath}{name}'
171 else:
172 pstr = f'{parentpath}/{name}'
173 if pstr.endswith('/'):
174 pstr = pstr[:-1]
175 return pstr
178def split_path(path):
179 """Split a *canonical* `path` into a parent path and a node name.
181 The result is returned as a tuple. The parent path does not
182 include a trailing slash.
184 >>> split_path('/')
185 ('/', '')
186 >>> split_path('/foo/bar')
187 ('/foo', 'bar')
189 """
191 lastslash = path.rfind('/')
192 ppath = path[:lastslash]
193 name = path[lastslash + 1:]
195 if ppath == '':
196 ppath = '/'
198 return (ppath, name)
201def isvisiblename(name):
202 """Does this `name` make the named node a visible one?"""
204 return _hidden_name_re.match(name) is None
207def isvisiblepath(path):
208 """Does this `path` make the named node a visible one?"""
210 return _hidden_path_re.search(path) is None
213def _test():
214 """Run ``doctest`` on this module."""
216 import doctest
217 doctest.testmod()
220if __name__ == '__main__':
221 _test()