44
55from copy import deepcopy
66
7- from . import filesize
87from .path import join
98from .enums import ResourceType
9+ from .errors import MissingInfoNamespace
1010from .permissions import Permissions
1111from .time import epoch_to_datetime
1212
@@ -59,10 +59,8 @@ def get(self, namespace, key, default=None):
5959 >>> info.get('access', 'permissions')
6060 ['u_r', 'u_w', '_wx']
6161
62- :param namespace: A namespace identifier.
63- :type namespace: str
64- :param key: A key within the namespace.
65- :type key: str
62+ :param str namespace: A namespace identifier.
63+ :param str key: A key within the namespace.
6664 :param default: A default value to return if either the
6765 namespace or namespace + key is not found.
6866 """
@@ -71,6 +69,15 @@ def get(self, namespace, key, default=None):
7169 except KeyError :
7270 return default
7371
72+ def _require_namespace (self , namespace ):
73+ """
74+ Raise a MissingInfoNamespace if the given namespace is not
75+ present in the info.
76+
77+ """
78+ if namespace not in self .raw :
79+ raise MissingInfoNamespace (namespace )
80+
7481 def is_writeable (self , namespace , key ):
7582 """
7683 Check if a given key in a namespace is writable (with
@@ -146,6 +153,17 @@ def is_file(self):
146153 """
147154 return not self .get ('basic' , 'is_dir' )
148155
156+ @property
157+ def is_link (self ):
158+ """
159+ Check if a resource is a symlink.
160+
161+ :rtype: bool
162+
163+ """
164+ self ._require_namespace ('link' )
165+ return self .get ('link' , 'target' ) is not None
166+
149167 @property
150168 def type (self ):
151169 """
@@ -154,8 +172,11 @@ def type(self):
154172 Requires the ``"details"`` namespace.
155173
156174 :type: :class:`~fs.ResourceType`
175+ :raises ~fs.errors.MissingInfoNamespace: if the 'details'
176+ namespace is not in the Info.
157177
158178 """
179+ self ._require_namespace ('details' )
159180 return ResourceType (self .get ('details' , 'type' , 0 ))
160181
161182 @property
@@ -167,8 +188,11 @@ def accessed(self):
167188 Requires the ``"details"`` namespace.
168189
169190 :rtype: datetime
191+ :raises ~fs.errors.MissingInfoNamespace: if the 'details'
192+ namespace is not in the Info.
170193
171194 """
195+ self ._require_namespace ('details' )
172196 _time = self ._make_datetime (
173197 self .get ('details' , 'accessed' )
174198 )
@@ -183,8 +207,11 @@ def modified(self):
183207 Requires the ``"details"`` namespace.
184208
185209 :rtype: datetime
210+ :raises ~fs.errors.MissingInfoNamespace: if the 'details'
211+ namespace is not in the Info.
186212
187213 """
214+ self ._require_namespace ('details' )
188215 _time = self ._make_datetime (
189216 self .get ('details' , 'modified' )
190217 )
@@ -199,8 +226,11 @@ def created(self):
199226 Requires the ``"details"`` namespace.
200227
201228 :rtype: datetime
229+ :raises ~fs.errors.MissingInfoNamespace: if the 'details'
230+ namespace is not in the Info.
202231
203232 """
233+ self ._require_namespace ('details' )
204234 _time = self ._make_datetime (
205235 self .get ('details' , 'created' )
206236 )
@@ -215,8 +245,11 @@ def metadata_changed(self):
215245 Requires the ``"details"`` namespace.
216246
217247 :rtype: datetime
248+ :raises ~fs.errors.MissingInfoNamespace: if the 'details'
249+ namespace is not in the Info.
218250
219251 """
252+ self ._require_namespace ('details' )
220253 _time = self ._make_datetime (
221254 self .get ('details' , 'metadata_changed' )
222255 )
@@ -230,8 +263,11 @@ def permissions(self):
230263 Requires the ``"access"`` namespace.
231264
232265 :rtype: :class:`fspermissions.Permissions`
266+ :raises ~fs.errors.MissingInfoNamespace: if the 'ACCESS'
267+ namespace is not in the Info.
233268
234269 """
270+ self ._require_namespace ('access' )
235271 _perm_names = self .get ('access' , 'permissions' )
236272 if _perm_names is None :
237273 return None
@@ -246,8 +282,11 @@ def size(self):
246282 Requires the ``"details"`` namespace.
247283
248284 :rtype: int
285+ :raises ~fs.errors.MissingInfoNamespace: if the 'details'
286+ namespace is not in the Info.
249287
250288 """
289+ self ._require_namespace ('details' )
251290 return self .get ('details' , 'size' )
252291
253292 @property
@@ -258,8 +297,11 @@ def user(self):
258297 Requires the ``"access"`` namespace.
259298
260299 :rtype: str
300+ :raises ~fs.errors.MissingInfoNamespace: if the 'access'
301+ namespace is not in the Info.
261302
262303 """
304+ self ._require_namespace ('access' )
263305 return self .get ('access' , 'user' )
264306
265307 @property
@@ -270,8 +312,11 @@ def uid(self):
270312 Requires the ``"access"`` namespace.
271313
272314 :rtype: int
315+ :raises ~fs.errors.MissingInfoNamespace: if the 'access'
316+ namespace is not in the Info.
273317
274318 """
319+ self ._require_namespace ('access' )
275320 return self .get ('access' , 'uid' )
276321
277322 @property
@@ -283,8 +328,11 @@ def group(self):
283328 Requires the ``"access"`` namespace.
284329
285330 :rtype: str
331+ :raises ~fs.errors.MissingInfoNamespace: if the 'access'
332+ namespace is not in the Info.
286333
287334 """
335+ self ._require_namespace ('access' )
288336 return self .get ('access' , 'group' )
289337
290338 @property
@@ -295,6 +343,25 @@ def gid(self):
295343 Requires the ``"access"`` namespace.
296344
297345 :rtype: int
346+ :raises ~fs.errors.MissingInfoNamespace: if the 'access'
347+ namespace is not in the Info.
298348
299349 """
350+ self ._require_namespace ('access' )
300351 return self .get ('access' , 'gid' )
352+
353+ @property
354+ def target (self ):
355+ """
356+ Get the link target, if this is a symlink, or ``None`` if this
357+ is not a symlink.
358+
359+ Requires the ``"link"`` namespace.
360+
361+ :rtype: bool
362+ :raises ~fs.errors.MissingInfoNamespace: if the 'link'
363+ namespace is not in the Info.
364+
365+ """
366+ self ._require_namespace ('link' )
367+ return self .get ('link' , 'target' )
0 commit comments