os3/fs/entry.py
# -*- coding: utf-8 -*-
import stat
import datetime
import os
import shutil
import six
from os3.core.comparators import StartsWithEqual
from os3.core.item import Os3Item
class Entry(Os3Item):
_stat = None
_type = None
path = ''
root = None
entry_class = None
def __new__(cls, *args, **kwargs):
classes = cls.get_classes()
Dir, File = classes['Dir'], classes['File']
if cls != (cls.entry_class or Entry) or not args:
return Os3Item.__new__(cls)
if args and isinstance(args[0], Entry):
path = args[0].path
else:
path = os.path.realpath(os.path.expanduser(args[0])) if args else None
if path and os.path.isdir(path):
return Dir.__new__(Dir, *args, **kwargs)
elif path and os.path.isfile(path):
return File.__new__(File, *args, **kwargs)
return File.__new__(File, *args, **kwargs)
# return Os3Item.__new__(cls)
def __init__(self, path, **kwargs):
self.path = self._get_path(path)
@classmethod
def get_classes(cls):
from os3.fs.directory import Dir
from os3.fs.file import File
return {
'Dir': Dir,
'File': File,
}
@classmethod
def get_entry_class(self):
return self.entry_class or Entry
@property
def name(self):
return os.path.split(self.path)[1]
@property
def size(self):
return os.path.getsize(self.path)
@property
def ctime(self):
return os.path.getctime(self.path)
@property
def mtime(self):
stat = self.stat()
if not stat:
return
return datetime.datetime.fromtimestamp(stat.st_mtime)
@property
def atime(self):
stat = self.stat()
if not stat:
return
return datetime.datetime.fromtimestamp(stat.st_atime)
def stat(self):
if self._stat is None:
try:
self._stat = os.stat(self.path)
except FileNotFoundError:
self._stat = False
return self._stat
@classmethod
def get_cls(cls, path):
classes = cls.get_classes()
if os.path.isdir(path):
# return File
return classes['Dir']
else:
return classes['File']
@classmethod
def get_node(cls, path):
path = cls._get_path(path)
return cls.get_cls(path)(path)
@property
def type(self):
return StartsWithEqual(self._type)
def exists(self):
return os.path.exists(self.path)
def lexists(self):
return os.path.lexists(self.path)
def is_dir(self):
return self.type == 'directory'
def is_file(self):
return self.type == 'file'
def bak(self):
if not self.lexists():
return self
i = -1
bak_name = self.path + '.bak'
while True:
new_bak_name = bak_name
if i > -1:
new_bak_name += str(i)
if not os.path.lexists(new_bak_name):
shutil.move(self.path, new_bak_name)
break
i += 1
return self
def symlink(self, link_name):
os.symlink(self.path, get_path(link_name))
def move(self, dst):
shutil.move(self.path, dst)
def remove(self):
raise NotImplementedError
def parent(self):
path = os.path.split(self.path)[0]
if self.root and not path.startswith(self.root):
return None
return self.get_classes()['Dir'](path)
def sub(self, subpath):
# TODO: Esto no deberÃa estar limitado a los directorios?
return Entry(os.path.join(self.path, get_path(subpath)))
def depth(self):
# TODO: tener en cuenta self.root
return self.path.split(os.sep)
@classmethod
def _get_path(cls, path):
"""Obtener el path de una variable path, que puede ser el propio path, o un DirEntry
"""
if not isinstance(path, (str, six.string_types)):
# Es un DirEntry
path = path.path
return os.path.abspath(os.path.expanduser(path))
def get_path(node):
if isinstance(node, Entry):
return node.path
return os.path.expanduser(node)