对标准pathlib模块和pathlib2包的改进
ruamel.std.pathlib的Python项目详细描述
package ruamel.std.pathlib是一个下拉列表 替换以扩展python标准的pathlib`模块。
您只需替换:
from pathlib import PosixPath, Path
使用:
from ruamel.std.pathlib import PosixPath, Path
对于较旧版本的python,它还用作依赖项检查。 从pypi安装pathlib2。你只需要 您的包依赖于ruamel.std.pathlib和pathlib2 将在必要时安装。
额外路径功能
- 路径上unlink的别名remove。
- 将copy()和rmtree()从shutil添加到路径
- 将hash()添加到path返回 文件内容(默认为“sha224”,其他算法如下 参数:print(p.hash('md5').hexdigest()))
转换助手
如果开始使用标准的pathlib库,则 立即更改所有内容,并将所有参数更改为调用 os.path.join,os.rename,os.path.dirname封装在str()
通过将PathLibConversionHelper的实例命名为pl,您可以更改 os.path.join()到pl.path.join()等,然后开始传入路径 实例而不是字符串。
- PathLibConversionHelper目前支持以下操作系统的替换
os.path,shuil和内置函数:
.chdir() replaces: os.chdir() .copy() replaces: shutil.copy() .glob() replaces: glob.glob() .listdir() replaces: os.listdir() .makedirs() replaces: os.makedirs() .mkstemp() replaces: tempfile.mkstemp() .open() replaces: built-in open() .path.basename() replaces: os.path.basename() .path.dirname() replaces: os.path.dirname() .path.exists() replaces: os.path.exists() .path.expanduser() replaces: os.path.expanduser() .path.getmtime() replaces: os.path.getmtime() .path.isdir() replaces: os.path.isdir() .path.join() replaces: os.path.join() .path.splitext() replaces: os.path.splitext() .remove() replaces: os.remove() .rename() replaces: os.rename() .rmdir() replaces: os.rmdir() .rmtree() replaces: shutil.rmtree() .walk() replaces: os.walk()
您可以在创建 pathlibconversionhelper()实例。
- 如果check为非零,则记录所有调用并调用 可以转储,例如在程序结束时 pl.dump(stream, show_all=False)这将包括 不使用path(以及唯一使用path)的调用数 如果show_all=True)
- 如果check大于1,则立即转储第一次使用。
如果您从以下代码开始:
# coding: utf-8 from __future__ import print_function import os import glob import tempfile import shutil import random class TempDir(object): """self removing (unless keep=True) temporary directory""" def __init__(self, keep=False, basedir=None, prefix=None): self._keep = keep # mkdtemp creates with permissions rwx------ kw = dict(dir=basedir) if prefix is not None: kw['prefix'] = prefix # mkdtemp doesn't do the right thing if None is passed in # as it has prefix=template in definition self._tmpdir = tempfile.mkdtemp(**kw) def remove(self): shutil.rmtree(self._tmpdir) def chdir(self): os.chdir(self._tmpdir) def tempfilename(self, extension=''): fd, name = tempfile.mkstemp(suffix=extension, dir=self._tmpdir) os.close(fd) return name def tempfilename2(self, extension=''): while True: name = os.path.join( self._tmpdir, '%08d' % random.randint(0, 100000) + extension ) if not os.path.exists(name): break return name @property def directory(self): return self._tmpdir def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): if not self._keep: self.remove() def main(): """contrived example using TempDir""" org_dir = os.getcwd() with TempDir() as td: for n in range(3): t1 = td.tempfilename(extension='.sample') with open(t1, 'w') as fp: fp.write('content\n') t2 = td.tempfilename2(extension='.sample2') with open(t2, 'w') as fp: fp.write('content\n') os.chdir(td.directory) count = 0 for file_name in glob.glob('*.samp*'): full_name = os.path.join(os.getcwd(), file_name) # noqa # print(full_name) count += 1 os.chdir('/tmp') # not using Path os.chdir(org_dir) print('{} files found in temporary directory'.format(count)) main()
你得到:
4 files found in temporary directory
当您开始更改TempDir()以存储 实际目录作为路径,会立即中断:
# coding: utf-8 from __future__ import print_function import os import glob import tempfile import shutil import random from ruamel.std.pathlib import Path # added class TempDir(object): """self removing (unless keep=True) temporary directory""" def __init__(self, keep=False, basedir=None, prefix=None): self._keep = keep # mkdtemp creates with permissions rwx------ kw = dict(dir=basedir) if prefix is not None: kw['prefix'] = prefix # mkdtemp doesn't do the right thing if None is passed in # as it has prefix=template in definition self._tmpdir = Path(tempfile.mkdtemp(**kw)) # changed def remove(self): shutil.rmtree(self._tmpdir) def chdir(self): os.chdir(self._tmpdir) def tempfilename(self, extension=''): fd, name = tempfile.mkstemp(suffix=extension, dir=self._tmpdir) os.close(fd) return name def tempfilename2(self, extension=''): while True: name = os.path.join( self._tmpdir, '%08d' % random.randint(0, 100000) + extension ) if not os.path.exists(name): break return name @property def directory(self): return self._tmpdir def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): if not self._keep: self.remove() def main(): """contrived example using TempDir""" org_dir = os.getcwd() with TempDir() as td: for n in range(3): t1 = td.tempfilename(extension='.sample') with open(t1, 'w') as fp: fp.write('content\n') t2 = td.tempfilename2(extension='.sample2') with open(t2, 'w') as fp: fp.write('content\n') os.chdir(td.directory) count = 0 for file_name in glob.glob('*.samp*'): full_name = os.path.join(os.getcwd(), file_name) # noqa # print(full_name) count += 1 os.chdir('/tmp') # not using Path os.chdir(org_dir) print('{} files found in temporary directory'.format(count)) main()
有一些错误:
Traceback (most recent call last): File "_example/stage1.py", line 80, in <module> main() File "_example/stage1.py", line 77, in main os.chdir(org_dir) File "_example/stage1.py", line 56, in __exit__ self.remove() File "_example/stage1.py", line 27, in remove shutil.rmtree(self._tmpdir) File "/opt/python/2.7.13/lib/python2.7/shutil.py", line 228, in rmtree if os.path.islink(path): File "/home/venv/dev/lib/python2.7/posixpath.py", line 135, in islink st = os.lstat(path) TypeError: coercing to Unicode: need string or buffer, PosixPath found
而不是一次性改变程序中的每一个用法, 希望它能再次工作,你取代了标准的程序 模块:
# coding: utf-8 from __future__ import print_function import os import glob import tempfile import shutil # noqa import random from ruamel.std.pathlib import Path, PathLibConversionHelper # changed pl = PathLibConversionHelper() # added class TempDir(object): """self removing (unless keep=True) temporary directory""" def __init__(self, keep=False, basedir=None, prefix=None): self._keep = keep # mkdtemp creates with permissions rwx------ kw = dict(dir=basedir) if prefix is not None: kw['prefix'] = prefix # mkdtemp doesn't do the right thing if None is passed in # as it has prefix=template in definition self._tmpdir = Path(tempfile.mkdtemp(**kw)) def remove(self): pl.rmtree(self._tmpdir) def chdir(self): os.chdir(self._tmpdir) def tempfilename(self, extension=''): fd, name = pl.mkstemp(suffix=extension, dir=self._tmpdir) # changed os.close(fd) return name def tempfilename2(self, extension=''): while True: name = pl.path.join( self._tmpdir, '%08d' % random.randint(0, 100000) + extension ) if not pl.path.exists(name): # changed break return name @property def directory(self): return self._tmpdir def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): if not self._keep: self.remove() def main(): """contrived example using TempDir""" org_dir = os.getcwd() with TempDir() as td: for n in range(3): t1 = td.tempfilename(extension='.sample') with open(t1, 'w') as fp: fp.write('content\n') t2 = td.tempfilename2(extension='.sample2') with pl.open(t2, 'w') as fp: c = 'content\n' # added if not isinstance(fp, file): # added c = unicode(c) # added fp.write(c) # changed pl.chdir(td.directory) count = 0 for file_name in glob.glob('*.samp*'): full_name = pl.path.join(os.getcwd(), file_name) # noqa # changed # print(full_name) count += 1 pl.chdir('/tmp') # not using Path pl.chdir(org_dir) # changed print('{} files found in temporary directory'.format(count)) main()
给予(再次):
4 files found in temporary directory
只需将self._tempdir的创建改回原来的:
self._tmpdir = tempfile.mkdtemp(**kw)
输出保持:
4 files found in temporary directory
如果现在将pl的创建更改为:
pl = PathLibConversionHelper(check=2)
输出:
update .mkstemp to use Path.mkstemp() [_example/stage3.py:34 / Path (True,)] update .path.join to use "/" [_example/stage3.py:42 / Path (True, False)] update .exists to use Path.exists() [_example/stage3.py:44 / Path (True,)] update .open to use Path.open() [_example/stage3.py:69 / Path (True,)] update .chdir to use Path.chdir() or os.chdir(str(Path)) [_example/stage3.py:74 / Path (True,)] update .path.join to use "/" [_example/stage3.py:77 / Path (False, False)] update .chdir to use Path.chdir() or os.chdir(str(Path)) [_example/stage3.py:80 / Path (False,)] update .chdir to use Path.chdir() or os.chdir(str(Path)) [_example/stage3.py:81 / Path (False,)] update .rmtree to use Path.rmtree() or shutil.rmtree(str(Path)) [_example/stage3.py:28 / Path (True,)] 4 files found in temporary directory
如果您使用check=1并在pl.dump()结尾处,您将得到:
4 files found in temporary directory update .path.join to use "/" [_example/stage4.py:42 / 1 / Path (True, False)] update .chdir to use Path.chdir() or os.chdir(str(Path)) [_example/stage4.py:81 / 1 / Path (False,)] update .path.join to use "/" [_example/stage4.py:77 / 4 / Path (False, False)] update .chdir to use Path.chdir() or os.chdir(str(Path)) [_example/stage4.py:80 / 1 / Path (False,)]
显示仍在何处使用基于字符串的路径/文件名。
信息 部分file_name.py: 123 / 2 / Path (True, False)表示 在file_name.py的123行有两个调用 第一个参数是路径,第二个不是路径(替换时 os.path.join()与路径的"/"连接运算符 作为一个好的起点,对于其他情况,您可能需要转换 路径实例的第二个参数)。
扩展PathLibConversionHelper
如果PathLibConversionHelper还不包含特定函数 您可以轻松地将其子类化并添加自己的:
from ruamel.std.pathlib import Path, PathLibConversionHelper class MyPLCH(PathLibConversionHelper): # an example, ruamel.std.pathlib already adds mkstemp def mkstemp(self, suffix="", prefix=None, dir=None, text=False): import tempfile # would be much better if prefix defaults to built-in value (int, None, string) if prefix is None: prefix = tempfile.template self.__add_usage(dir, 'update .mkstemp to use Path.mkstemp()') if isinstance(dir, Path): dir = str(dir) return tempfile.mkstemp(suffix, prefix, dir, text) pl = MyPLCH(check=1)
self.add_usage()的第一个参数用于确定 是否使用路径。这应该是所有相关变量的列表 (可能是Path实例,也可能不是)。如果名单上只有 它不必作为列表传入(如 示例)。第二个参数应该是一个字符串,可以进一步帮助 取消对.mkstemp()的调用。