2014-01-28 15:17:51 +01:00
|
|
|
# flake8: noqa
|
2010-04-12 21:54:37 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Author: Aziz Köksal
|
2013-08-22 06:38:23 +02:00
|
|
|
from __future__ import absolute_import
|
|
|
|
|
2013-08-19 04:40:20 +02:00
|
|
|
import glob
|
2010-06-03 04:25:26 +02:00
|
|
|
import os
|
|
|
|
import shutil
|
2017-05-16 12:16:30 +02:00
|
|
|
|
|
|
|
from pip._vendor import six
|
2010-04-12 21:54:37 +02:00
|
|
|
|
2013-08-19 04:40:20 +02:00
|
|
|
try:
|
|
|
|
from os import supports_fd
|
|
|
|
except ImportError:
|
|
|
|
supports_fd = set()
|
|
|
|
|
2011-03-15 20:49:48 +01:00
|
|
|
|
2017-03-24 19:43:05 +01:00
|
|
|
|
|
|
|
_base = six.text_type if os.path.supports_unicode_filenames else str
|
2010-04-24 09:18:12 +02:00
|
|
|
|
2011-05-04 09:44:02 +02:00
|
|
|
|
2010-04-24 09:18:12 +02:00
|
|
|
class Path(_base):
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
|
|
|
Models a path in an object oriented way.
|
|
|
|
"""
|
2010-06-03 04:25:26 +02:00
|
|
|
|
2013-08-19 04:40:20 +02:00
|
|
|
# File system path separator: '/' or '\'.
|
|
|
|
sep = os.sep
|
|
|
|
|
|
|
|
# Separator in the PATH environment variable.
|
|
|
|
pathsep = os.pathsep
|
2010-06-03 04:25:26 +02:00
|
|
|
|
|
|
|
def __new__(cls, *paths):
|
|
|
|
if len(paths):
|
|
|
|
return _base.__new__(cls, os.path.join(*paths))
|
|
|
|
return _base.__new__(cls)
|
|
|
|
|
|
|
|
def __div__(self, path):
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
|
|
|
Joins this path with another path.
|
|
|
|
|
|
|
|
>>> path_obj / 'bc.d'
|
|
|
|
>>> path_obj / path_obj2
|
|
|
|
"""
|
2010-06-03 04:25:26 +02:00
|
|
|
return Path(self, path)
|
2011-05-04 09:44:02 +02:00
|
|
|
|
2011-03-15 20:49:48 +01:00
|
|
|
__truediv__ = __div__
|
2010-06-03 04:25:26 +02:00
|
|
|
|
|
|
|
def __rdiv__(self, path):
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
|
|
|
Joins this path with another path.
|
|
|
|
|
|
|
|
>>> "/home/a" / path_obj
|
|
|
|
"""
|
2010-06-03 04:25:26 +02:00
|
|
|
return Path(path, self)
|
|
|
|
|
2011-03-15 20:49:48 +01:00
|
|
|
__rtruediv__ = __rdiv__
|
|
|
|
|
2010-06-03 04:25:26 +02:00
|
|
|
def __idiv__(self, path):
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
|
|
|
Like __div__ but also assigns to the variable.
|
|
|
|
|
|
|
|
>>> path_obj /= 'bc.d'
|
|
|
|
"""
|
2010-06-03 04:25:26 +02:00
|
|
|
return Path(self, path)
|
|
|
|
|
2011-03-15 20:49:48 +01:00
|
|
|
__itruediv__ = __idiv__
|
|
|
|
|
2010-06-03 04:25:26 +02:00
|
|
|
def __add__(self, path):
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
|
|
|
>>> Path('/home/a') + 'bc.d'
|
|
|
|
'/home/abc.d'
|
|
|
|
"""
|
2010-06-03 04:25:26 +02:00
|
|
|
return Path(_base(self) + path)
|
|
|
|
|
|
|
|
def __radd__(self, path):
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
|
|
|
>>> '/home/a' + Path('bc.d')
|
|
|
|
'/home/abc.d'
|
|
|
|
"""
|
2010-06-03 04:25:26 +02:00
|
|
|
return Path(path + _base(self))
|
|
|
|
|
|
|
|
def __repr__(self):
|
2020-02-29 20:53:59 +01:00
|
|
|
return u"Path({inner})".format(inner=_base.__repr__(self))
|
2010-06-03 04:25:26 +02:00
|
|
|
|
|
|
|
def __hash__(self):
|
|
|
|
return _base.__hash__(self)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
|
|
|
'/home/a/bc.d' -> 'bc.d'
|
|
|
|
"""
|
2010-06-03 04:25:26 +02:00
|
|
|
return os.path.basename(self)
|
|
|
|
|
|
|
|
@property
|
2019-07-02 07:00:32 +02:00
|
|
|
def stem(self):
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
|
|
|
'/home/a/bc.d' -> 'bc'
|
|
|
|
"""
|
2019-07-01 03:55:00 +02:00
|
|
|
return Path(os.path.splitext(self)[0]).name
|
2010-06-03 04:25:26 +02:00
|
|
|
|
|
|
|
@property
|
2019-07-02 07:00:32 +02:00
|
|
|
def suffix(self):
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
|
|
|
'/home/a/bc.d' -> '.d'
|
|
|
|
"""
|
2010-06-03 04:25:26 +02:00
|
|
|
return Path(os.path.splitext(self)[1])
|
|
|
|
|
2019-07-02 07:00:32 +02:00
|
|
|
def resolve(self):
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
|
|
|
Resolves symbolic links.
|
|
|
|
"""
|
2010-06-03 04:25:26 +02:00
|
|
|
return Path(os.path.realpath(self))
|
|
|
|
|
|
|
|
@property
|
2019-07-02 07:00:32 +02:00
|
|
|
def parent(self):
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
2019-07-02 07:00:32 +02:00
|
|
|
Returns the parent directory of this path.
|
2013-08-19 04:40:20 +02:00
|
|
|
|
|
|
|
'/home/a/bc.d' -> '/home/a'
|
|
|
|
'/home/a/' -> '/home/a'
|
|
|
|
'/home/a' -> '/home'
|
|
|
|
"""
|
2010-06-03 04:25:26 +02:00
|
|
|
return Path(os.path.dirname(self))
|
|
|
|
|
|
|
|
def exists(self):
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
|
|
|
Returns True if the path exists.
|
|
|
|
"""
|
2010-06-03 04:25:26 +02:00
|
|
|
return os.path.exists(self)
|
|
|
|
|
2019-08-17 03:34:17 +02:00
|
|
|
def mkdir(self, mode=0x1FF, exist_ok=False, parents=False): # 0o777
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
|
|
|
Creates a directory, if it doesn't exist already.
|
2010-06-03 04:25:26 +02:00
|
|
|
|
2019-07-12 10:00:18 +02:00
|
|
|
:param parents: Whether to create parent directories.
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
2019-07-12 10:00:18 +02:00
|
|
|
|
|
|
|
maker_func = os.makedirs if parents else os.mkdir
|
2019-08-17 03:34:17 +02:00
|
|
|
try:
|
|
|
|
maker_func(self, mode)
|
|
|
|
except OSError:
|
|
|
|
if not exist_ok or not os.path.isdir(self):
|
|
|
|
raise
|
2010-06-03 04:25:26 +02:00
|
|
|
|
2019-07-02 07:00:32 +02:00
|
|
|
def unlink(self):
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
|
|
|
Removes a file.
|
|
|
|
"""
|
|
|
|
return os.remove(self)
|
|
|
|
|
2010-06-03 04:25:26 +02:00
|
|
|
def rmdir(self):
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
|
|
|
Removes a directory.
|
|
|
|
"""
|
2010-06-03 04:25:26 +02:00
|
|
|
return os.rmdir(self)
|
|
|
|
|
|
|
|
def rename(self, to):
|
2013-08-19 04:40:20 +02:00
|
|
|
"""
|
|
|
|
Renames a file or directory. May throw an OSError.
|
|
|
|
"""
|
|
|
|
return os.rename(self, to)
|
2010-06-03 04:25:26 +02:00
|
|
|
|
|
|
|
def glob(self, pattern):
|
2019-07-02 07:00:32 +02:00
|
|
|
return (Path(i) for i in glob.iglob(self.joinpath(pattern)))
|
2013-08-19 04:40:20 +02:00
|
|
|
|
2019-07-02 07:00:32 +02:00
|
|
|
def joinpath(self, *parts):
|
2013-08-19 04:40:20 +02:00
|
|
|
return Path(self, *parts)
|
|
|
|
|
2019-07-02 07:00:32 +02:00
|
|
|
# TODO: Remove after removing inheritance from str.
|
|
|
|
def join(self, *parts):
|
|
|
|
raise RuntimeError('Path.join is invalid, use joinpath instead.')
|
|
|
|
|
2019-12-14 01:32:35 +01:00
|
|
|
def read_bytes(self):
|
|
|
|
# type: () -> bytes
|
|
|
|
with open(self, "rb") as fp:
|
|
|
|
return fp.read()
|
|
|
|
|
2019-12-31 16:17:41 +01:00
|
|
|
def write_bytes(self, content):
|
|
|
|
# type: (bytes) -> None
|
|
|
|
with open(self, "wb") as f:
|
|
|
|
f.write(content)
|
|
|
|
|
2017-08-07 18:03:43 +02:00
|
|
|
def read_text(self):
|
|
|
|
with open(self, "r") as fp:
|
|
|
|
return fp.read()
|
|
|
|
|
2019-07-02 07:00:32 +02:00
|
|
|
def write_text(self, content):
|
2013-08-19 04:40:20 +02:00
|
|
|
with open(self, "w") as fp:
|
|
|
|
fp.write(content)
|
|
|
|
|
2019-07-12 09:49:17 +02:00
|
|
|
def touch(self):
|
2013-08-19 04:40:20 +02:00
|
|
|
with open(self, "a") as fp:
|
2019-07-12 10:08:04 +02:00
|
|
|
path = fp.fileno() if os.utime in supports_fd else self
|
2019-07-12 23:11:24 +02:00
|
|
|
os.utime(path, None) # times is not optional on Python 2.7
|
2010-04-28 17:41:55 +02:00
|
|
|
|
2019-08-23 23:11:12 +02:00
|
|
|
def symlink_to(self, target):
|
|
|
|
os.symlink(target, self)
|
|
|
|
|
|
|
|
def stat(self):
|
|
|
|
return os.stat(self)
|
|
|
|
|
2010-04-28 17:41:55 +02:00
|
|
|
curdir = Path(os.path.curdir)
|