From c925bb75ce9935185374405a31dbcb7ff27ad589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AB=B9=E6=B0=B8=E5=BA=B7?= Date: Wed, 24 Jul 2024 09:08:29 +0800 Subject: [PATCH] 1.1.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.Support direct traversal of file objects and content existence judgment. 2.Fix the issue of strict mode failure when splicing paths. 3.Adjusted code formatting to enhance readability. 4.Added comments in the `SystemPath` class to improve code maintainability. 5.Replaced the project's unique dependency library to ensure dependency updates and stability. 6.Add more detailed documentation in both English and Chinese. 1.支持直接遍历文件对象和内容存在性判断。 2.修复拼接路径时严格模式失效的问题。 3.调整代码格式,提升代码可读性。 4.在 `SystemPath` 类中添加注释,增强代码可维护性。 5.更换项目唯一依赖库,以确保依赖更新和稳定。 6.添加更详细的中英文文档。 --- .github/workflows/python-publish.yml | 2 +- README.md | 36 ++- README_CN.md | 57 +++++ requirements.txt | 2 +- setup.py | 16 +- systempath/__init__.py | 345 +++++++++++++++------------ systempath/i systempath.py | 202 ++++++++-------- test.py | 7 - 8 files changed, 389 insertions(+), 278 deletions(-) create mode 100644 README_CN.md delete mode 100644 test.py diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 906d290..10e6315 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -19,7 +19,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install setuptools wheel twine "gqylpy_exception>=3.0.1" + pip install setuptools wheel twine "exceptionx>=4.1.1,<5.0" - name: Build package run: python setup.py bdist_wheel - name: Publish package diff --git a/README.md b/README.md index f00f2b5..016013f 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ [LOGO](http://www.gqylpy.com) -[![Release](https://img.shields.io/github/release/gqylpy/systempath.svg?style=flat-square")](https://github.com/gqylpy/systempath/releases/latest) +[![Release](https://img.shields.io/github/release/gqylpy/systempath.svg?style=flat-square)](https://github.com/gqylpy/systempath/releases/latest) [![Python Versions](https://img.shields.io/pypi/pyversions/systempath)](https://pypi.org/project/systempath) [![License](https://img.shields.io/pypi/l/systempath)](https://github.com/gqylpy/systempath/blob/master/LICENSE) [![Downloads](https://static.pepy.tech/badge/systempath)](https://pepy.tech/project/systempath) # systempath +English | [中文](https://github.com/gqylpy/systempath/blob/master/README_CN.md) -> Object-oriented operation of files and system paths. -> Make Python operation of files and system paths become simple, simpler, simplest, humane, unified, and flawless. +**systempath** is a highly specialized library designed for Python developers for file and system path manipulation. By providing an intuitive and powerful object-oriented API, it significantly simplifies complex file and directory management tasks, allowing developers to focus more on implementing core business logic rather than the intricacies of low-level file system operations. pip3 install systempath @@ -24,6 +24,34 @@ >>> file /home/gqylpy/alpha.txt ->>> file.open.rb().read() +>>> file.content b'GQYLPY \xe6\x94\xb9\xe5\x8f\x98\xe4\xb8\x96\xe7\x95\x8c' ``` + +## Core Features + +### 1. Object-Oriented Path Representation + +- **Directory Class**: Specifically designed to represent directory paths, providing directory-specific operations such as traversal, creation, deletion, and management of subdirectories and files. +- **File Class**: Specifically designed to represent file paths, offering advanced functions beyond basic file operations, including content reading and writing, appending, and clearing. +- **SystemPath Class**: Serves as a universal interface for `Directory` and `File`, providing maximum flexibility to handle any type of path, whether it's a file or directory. + +### 2. Automation and Flexibility + +- **Automatic Absolute Path Conversion**: Supports automatically converting relative paths to absolute paths during path object initialization, reducing issues caused by incorrect paths. +- **Strict Mode**: Allows developers to enable strict mode, ensuring that paths do exist during initialization; otherwise, exceptions are thrown, enhancing code robustness and reliability. + +### 3. Rich Operational Interfaces + +- **Path Concatenation**: Supports path concatenation using `/`, `+` operators, and even brackets, making path construction more intuitive and flexible. +- **Comprehensive File and Directory Operations**: Provides a complete set of file and directory operation methods, including but not limited to reading, writing, copying, moving, deleting, and traversing, meeting various file processing needs. + +## Usage Scenarios + +- **Automation Script Development**: In scenarios such as automated testing, deployment scripts, log management, systempath offers powerful file and directory manipulation capabilities, simplifying script writing processes. +- **Web Application Development**: Handles user-uploaded files, generates temporary files, and more, making these operations simpler and more efficient with systempath. +- **Data Science and Analysis**: When reading, writing, and processing data files stored in the file system, systempath provides a convenient file management approach for data scientists. + +## Conclusion + +systempath is a comprehensive and easy-to-use library for file and system path manipulation. Through its object-oriented API design, it significantly simplifies the complexity of file and directory management in Python, allowing developers to focus more on implementing core business logic. Whether it's automation script development, web application building, or data science projects, systempath will be an indispensable and valuable assistant. diff --git a/README_CN.md b/README_CN.md new file mode 100644 index 0000000..25bb2ba --- /dev/null +++ b/README_CN.md @@ -0,0 +1,57 @@ +[LOGO](http://www.gqylpy.com) +[![Release](https://img.shields.io/github/release/gqylpy/systempath.svg?style=flat-square")](https://github.com/gqylpy/systempath/releases/latest) +[![Python Versions](https://img.shields.io/pypi/pyversions/systempath)](https://pypi.org/project/systempath) +[![License](https://img.shields.io/pypi/l/systempath)](https://github.com/gqylpy/systempath/blob/master/LICENSE) +[![Downloads](https://static.pepy.tech/badge/systempath)](https://pepy.tech/project/systempath) + +# systempath - 专业级的文件与系统路径操作库 +[English](README.md) | 中文 + +**systempath** 是一个专为Python开发者设计的,高度专业化的文件与系统路径操作库。通过提供一套直观且功能强大的面向对象API,它极大地简化了复杂文件与目录管理的任务,使开发者能够更专注于核心业务逻辑的实现,而非底层文件系统操作的细节。 + +pip3 install systempath + +```python +>>> from systempath import SystemPath, Directory, File + +>>> root = SystemPath('/') + +>>> home: Directory = root['home']['gqylpy'] +>>> home +/home/gqylpy + +>>> file: File = home['alpha.txt'] +>>> file +/home/gqylpy/alpha.txt + +>>> file.content +b'GQYLPY \xe6\x94\xb9\xe5\x8f\x98\xe4\xb8\x96\xe7\x95\x8c' +``` + +## 核心特性 + +### 1. 面向对象的路径表示 + +- **Directory 类**:专门用于表示目录路径,提供目录遍历、创建、删除及子目录与文件管理等目录特定操作。 +- **File 类**:专门用于表示文件路径,除了基本的文件操作外,还提供了内容读写、追加、清空等高级功能。 +- **SystemPath 类**:作为 `Directory` 和 `File` 的通用接口,提供了最大的灵活性,能够处理任何类型的路径,无论是文件还是目录。 + +### 2. 自动化与灵活性 + +- **自动绝对路径转换**:支持在路径对象初始化时自动将相对路径转换为绝对路径,减少因路径错误导致的问题。 +- **严格模式**:允许开发者启用严格模式,确保路径在初始化时确实存在,否则抛出异常,增强代码的健壮性和可靠性。 + +### 3. 丰富的操作接口 + +- **路径拼接**:支持使用 `/` 和 `+` 操作符甚至是中括号进行路径拼接,使得路径构建更加直观和灵活。 +- **全面的文件与目录操作**:提供了一整套文件与目录操作方法,包括但不限于读取、写入、复制、移动、删除、遍历等,满足各种文件处理需求。 + +## 使用场景 + +- **自动化脚本开发**:在自动化测试、部署脚本、日志管理等场景中,systempath 提供强大的文件与目录操作能力,能够简化脚本编写过程。 +- **Web应用开发**:处理用户上传的文件、生成临时文件等场景,systempath 使得这些操作更加简单高效。 +- **数据科学与分析**:读取、写入和处理存储在文件系统中的数据文件时,systempath 为数据科学家提供了便捷的文件管理方式。 + +## 结论 + +systempath 是一个功能全面、易于使用的文件与系统路径操作库。通过其面向对象的API设计,它极大地简化了Python中文件与目录管理的复杂性,使得开发者能够更专注于核心业务逻辑的实现。无论是自动化脚本开发、Web应用构建,还是数据科学项目,systempath 都将是您不可或缺的得力助手。 diff --git a/requirements.txt b/requirements.txt index a2b9e33..b18a9ed 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -gqylpy_exception>=3.0.1 +exceptionx>=4.1.2,<5.0 diff --git a/setup.py b/setup.py index 291320d..09b56f9 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,6 @@ import setuptools import systempath as i - -from systempath import Content +from systempath import File idoc: list = i.__doc__.split('\n') @@ -20,12 +19,19 @@ license='Apache 2.0', url='http://gqylpy.com', project_urls={'Source': source}, - description='Object-oriented operation of files and system paths.', - long_description=open('README.md', encoding='utf8').read(), + description=''' + The `systempath` is a highly specialized library designed for Python + developers for file and system path manipulation. By providing an + intuitive and powerful object-oriented API, it significantly simplifies + complex file and directory management tasks, allowing developers to + focus more on implementing core business logic rather than the + intricacies of low-level file system operations. + '''.strip().replace('\n ', ''), + long_description=File('README.md').content.decode('utf-8'), long_description_content_type='text/markdown', packages=[i.__name__], python_requires='>=3.8', - install_requires=[x.decode() for x in Content('requirements.txt') if x], + install_requires=[x.decode() for x in File('requirements.txt') if x], classifiers=[ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', diff --git a/systempath/__init__.py b/systempath/__init__.py index d00fd4a..d4c0c1d 100644 --- a/systempath/__init__.py +++ b/systempath/__init__.py @@ -1,7 +1,10 @@ -"""Object-oriented operation of files and system paths. +"""A Professional Library for File and System Path Manipulation -Make Python operation of files and system paths become simple, simpler, -simplest, humane, unified, and flawless. +The `systempath` is a highly specialized library designed for Python developers +forfile and system path manipulation. By providing an intuitive and powerful +object-oriented API, it significantly simplifies complex file and directory +management tasks, allowing developers to focus more on implementing core +business logic rather than the intricacies of low-level file system operations. >>> from systempath import SystemPath, Directory, File @@ -15,16 +18,16 @@ >>> file /home/gqylpy/alpha.txt - >>> file.open.rb().read() + >>> file.content b'GQYLPY \xe6\x94\xb9\xe5\x8f\x98\xe4\xb8\x96\xe7\x95\x8c' - @version: 1.1 - @author: 竹永康 - @source: https://github.com/gqylpy/systempath - ──────────────────────────────────────────────────────────────────────────────── Copyright (c) 2022-2024 GQYLPY . All rights reserved. + @version: 1.1.1 + @author: 竹永康 + @source: https://github.com/gqylpy/systempath + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -39,7 +42,7 @@ """ import os import sys -import gqylpy_exception as ge +import exceptionx as ex from typing import ( Type, TypeVar, Literal, Optional, Union, Tuple, List, BinaryIO, TextIO, @@ -49,20 +52,21 @@ if sys.version_info >= (3, 10): from typing import TypeAlias else: - TypeAlias = TypeVar("TypeAlias") + TypeAlias = TypeVar('TypeAlias') __all__ = ['SystemPath', 'Path', 'Directory', 'File', 'Open', 'Content', 'tree'] -BytesOrStr: TypeAlias = TypeVar('BytesOrStr', bytes, str) -PathLink: TypeAlias = BytesOrStr -PathType: TypeAlias = \ - TypeVar('PathType', 'Path', 'Directory', 'File', 'SystemPath') +BytesOrStr: TypeAlias = TypeVar('BytesOrStr', bytes, str) +PathLink: TypeAlias = BytesOrStr +PathType: TypeAlias = Union['Path', 'Directory', 'File', 'SystemPath'] +FileOpener: TypeAlias = Callable[[PathLink, int], int] +FileNewline: TypeAlias = Literal['', '\n', '\r', '\r\n'] -SystemPathNotFoundError: Type[ge.GqylpyError] = ge.SystemPathNotFoundError -NotAPathError: Type[ge.GqylpyError] = ge.NotAPathError -NotAFileError: Type[ge.GqylpyError] = ge.NotAFileError -NotADirectoryOrFileError: Type[ge.GqylpyError] = ge.NotADirectoryOrFileError -IsSameFileError: Type[ge.GqylpyError] = ge.IsSameFileError +SystemPathNotFoundError: Type[ex.Error] = ex.SystemPathNotFoundError +NotAPathError: Type[ex.Error] = ex.NotAPathError +NotAFileError: Type[ex.Error] = ex.NotAFileError +NotADirectoryOrFileError: Type[ex.Error] = ex.NotADirectoryOrFileError +IsSameFileError: Type[ex.Error] = ex.IsSameFileError class Path: @@ -84,13 +88,14 @@ def __init__( @param autoabs Automatically normalize the path link and convert to absolute path, - at initialization. Default False. It is always recommended that you - enable the parameter when the passed path is a relative path. + at initialization. The default is False. It is always recommended + that you enable the parameter when the passed path is a relative + path. @param strict Set to True to enable strict mode, which means that the passed path must exist, otherwise raise `SystemPathNotFoundError` (or other). - Default False. + The default is False. @param dir_fd This optional parameter applies only to the following methods: @@ -118,10 +123,10 @@ def __init__( `listxattr`, `removexattr`, `walk`, `copy`, `link` - Used to indicate whether symbolic links are followed, default True. - If specified as False, and the last element of the parameter `path` - is a symbolic link, the action will point to the symbolic link - itself, not to the path to which the link points. + Used to indicate whether symbolic links are followed, the default is + True. If specified as False, and the last element of the parameter + `path` is a symbolic link, the action will point to the symbolic + link itself, not to the path to which the link points. This parameter may not be available on your platform, using them will raise `NotImplementedError` if unavailable. @@ -178,8 +183,8 @@ def basename(self) -> BytesOrStr: def dirname(self) -> 'Directory': return Directory( os.path.dirname(self), - strict =self.strict, - dir_fd =self.dir_fd, + strict=self.strict, + dir_fd=self.dir_fd, follow_symlinks=self.follow_symlinks ) @@ -187,8 +192,8 @@ def dirnamel(self, level: int) -> 'Directory': """Like `self.dirname`, and can specify the directory level.""" return Directory( self.name.rsplit(os.sep, maxsplit=level)[0], - strict =self.strict, - dir_fd =self.dir_fd, + strict=self.strict, + dir_fd=self.dir_fd, follow_symlinks=self.follow_symlinks ) @@ -196,43 +201,43 @@ def dirnamel(self, level: int) -> 'Directory': def abspath(self) -> PathType: return self.__class__( os.path.abspath(self), - strict =self.strict, + strict=self.strict, follow_symlinks=self.follow_symlinks ) def realpath(self, *, strict: Optional[bool] = None) -> PathType: return self.__class__( os.path.realpath(self, strict=strict), - strict =self.strict, + strict=self.strict, follow_symlinks=self.follow_symlinks ) def relpath(self, start: Optional[PathLink] = None) -> PathType: return self.__class__( os.path.relpath(self, start=start), - strict =self.strict, + strict=self.strict, follow_symlinks=self.follow_symlinks ) def normpath(self) -> PathType: return self.__class__( os.path.normpath(self), - strict =self.strict, - dir_fd =self.dir_fd, + strict=self.strict, + dir_fd=self.dir_fd, follow_symlinks=self.follow_symlinks ) def expanduser(self) -> PathType: return self.__class__( os.path.expanduser(self), - strict =self.strict, + strict=self.strict, follow_symlinks=self.follow_symlinks ) def expandvars(self) -> PathType: return self.__class__( os.path.expandvars(self), - strict =self.strict, + strict=self.strict, follow_symlinks=self.follow_symlinks ) @@ -305,8 +310,8 @@ def executable(self) -> bool: def delete( self, *, - ignore_errors: Optional[bool] = None, - onerror: Optional[Callable] = None + ignore_errors: Optional[bool] = None, + onerror: Optional[Callable] = None ) -> None: """ Delete the path, if the path is a file then call `os.remove` internally, @@ -314,7 +319,8 @@ def delete( @param ignore_errors If the path does not exist will raise `FileNotFoundError`, can set - this parameter to True to silence the exception. Default False. + this parameter to True to silence the exception. The default is + False. @param onerror An optional error handler, used only if the path is a directory, for @@ -384,7 +390,7 @@ def replace(self, dst: PathLink, /) -> PathLink: def move( self, - dst: Union[PathType, PathLink], + dst: Union[PathType, PathLink], /, *, copy_function: Optional[Callable[[PathLink, PathLink], None]] = None ) -> Union[PathType, PathLink]: @@ -552,9 +558,9 @@ def access( `os.F_OK`: real value is 0, whether exists. @param effective_ids - Default False, this parameter may not be available on your platform, - using them will ignore if unavailable. You can look up `os.access` - for more description. + The default is False, this parameter may not be available on your + platform, using them will ignore if unavailable. You can look up + `os.access` for more description. If the optional initialization parameter `self.follow_symlinks` is specified as False, and the last element of the path is a symbolic link, @@ -814,7 +820,7 @@ def __bool__(self) -> bool: @staticmethod def home( *, - strict: Optional[bool] = None, + strict: Optional[bool] = None, follow_symlinks: Optional[bool] = None ) -> 'Directory': return Directory( @@ -856,7 +862,7 @@ def tree( def walk( self, *, - topdown: Optional[bool] = None, + topdown: Optional[bool] = None, onerror: Optional[Callable] = None ) -> Iterator[Tuple[PathLink, List[BytesOrStr], List[BytesOrStr]]]: """ @@ -868,8 +874,8 @@ def walk( (current_directory_path, all_subdirectory_names, all_file_names) @param topdown - Default True, generate the directory tree from the outside in. If - specified as False, from the inside out. + The default is True, generate the directory tree from the outside + in. If specified as False, from the inside out. @param onerror An optional error handler, for more instructions see `os.walk`. @@ -877,15 +883,17 @@ def walk( def copytree( self, - dst: Union['Directory', PathLink], + dst: Union['Directory', PathLink], /, *, - symlinks: Optional[bool] = None, - ignore: Optional[Callable[ - [PathLink, List[BytesOrStr]], List[BytesOrStr]]] = None, - copy_function: Optional[Callable[[PathLink, PathLink], None]] - = None, - ignore_dangling_symlinks: Optional[bool] = None, - dirs_exist_ok: Optional[bool] = None + symlinks: Optional[bool] = None, + ignore: Optional[ + Callable[[PathLink, List[BytesOrStr]], List[BytesOrStr]] + ] = None, + copy_function: Optional[ + Callable[[PathLink, PathLink], None] + ] = None, + ignore_dangling_symlinks: Optional[bool] = None, + dirs_exist_ok: Optional[bool] = None ) -> Union['Directory', PathLink]: """ Copy the directory tree recursively, call `shutil.copytree` internally. @@ -898,7 +906,7 @@ def copytree( For symbolic links in the source tree, the content of the file to which the symbolic link points is copied by default. If this parameter is set to True, the symbolic link itself is copied. - Default False. + The default is False. If the file to which the symbolic link points does not exist, raise an exception at the end of the replication process. If you do not @@ -933,8 +941,8 @@ def copytree( @param ignore_dangling_symlinks Used to ignore exceptions raised by symbolic link errors, use with - parameter `symlinks`. Default False. This parameter has no effect on - platforms that do not support `os.symlink`. + parameter `symlinks`. The default is False. This parameter has no + effect on platforms that do not support `os.symlink`. @param dirs_exist_ok If the destination path already exists will raise `FileExistsError`, @@ -954,7 +962,7 @@ def clear(self) -> None: def mkdir( self, - mode: Optional[int] = None, + mode: Optional[int] = None, *, ignore_exists: Optional[bool] = None ) -> None: @@ -971,12 +979,12 @@ def mkdir( @param ignore_exists If the directory already exists, call this method will raise `FileExistsError`. But, if this parameter is set to True then - silently skip. Default False. + silently skip. The default is False. """ def makedirs( self, - mode: Optional[int] = None, + mode: Optional[int] = None, *, exist_ok: Optional[bool] = None ) -> None: @@ -993,7 +1001,8 @@ def makedirs( @param exist_ok If the directory already exists will raise `FileExistsError`, can - set this parameter to True to silence the exception. Default False. + set this parameter to True to silence the exception. The default is + False. """ def rmdir(self) -> None: @@ -1013,15 +1022,16 @@ def removedirs(self) -> None: def rmtree( self, *, - ignore_errors: Optional[bool] = None, - onerror: Optional[Callable] = None + ignore_errors: Optional[bool] = None, + onerror: Optional[Callable] = None ) -> None: """ Delete the directory tree recursively, call `shutil.rmtree` internally. @param ignore_errors If the directory does not exist will raise `FileNotFoundError`, can - set this parameter to True to silence the exception. Default False. + set this parameter to True to silence the exception. The default is + False. @param onerror An optional error handler, described more see `shutil.rmtree`. @@ -1040,6 +1050,12 @@ class File(Path): def __bool__(self) -> bool: return self.isfile + def __contains__(self, subcontent: bytes, /) -> bool: + return subcontent in self.contents + + def __iter__(self) -> Iterator[bytes]: + yield from self.contents + @property def open(self) -> 'Open': return Open(self) @@ -1088,9 +1104,9 @@ def copy(self, dst: Union['File', PathLink], /) -> Union['File', PathLink]: def copycontent( self, - dst: Union['File', BinaryIO], + dst: Union['File', BinaryIO], /, *, - bufsize: Optional[int] = None + bufsize: Optional[int] = None ) -> Union['File', BinaryIO]: """ Copy the file contents to another file. @@ -1138,9 +1154,9 @@ def clear(self) -> None: def mknod( self, - mode: Optional[int] = None, + mode: Optional[int] = None, *, - device: Optional[int] = None, + device: Optional[int] = None, ignore_exists: Optional[bool] = None ) -> None: """ @@ -1160,14 +1176,14 @@ def mknod( @param ignore_exists If the file already exists, call this method will raise `FileExistsError`. But, if this parameter is set to True then - silently skip. Default False. + silently skip. The default is False. """ def mknods( self, - mode: Optional[int] = None, + mode: Optional[int] = None, *, - device: Optional[int] = None, + device: Optional[int] = None, ignore_exists: Optional[bool] = None ) -> None: """Create the file and all intermediate paths, super version of @@ -1181,7 +1197,8 @@ def remove(self, *, ignore_errors: Optional[bool] = None) -> None: @param ignore_errors If the file does not exist will raise `FileNotFoundError`, can set - this parameter to True to silence the exception. Default False. + this parameter to True to silence the exception. The default is + False. """ def unlink(self) -> None: @@ -1306,7 +1323,7 @@ class Open: @param line_buffering If set to True, automatically call `flush()` when writing contains a - newline character, default False. + newline character, The default is False. @param write_through We do not find any description of this parameter in the Python3 source @@ -1325,151 +1342,151 @@ def __init__(self, file: Union[File, PathLink], /): def rb( self, *, - bufsize: Optional[int] = None, - opener: Optional[Callable[[PathLink, int], int]] = None + bufsize: Optional[int] = None, + opener: Optional[FileOpener] = None ) -> BinaryIO: ... def wb( self, *, - bufsize: Optional[int] = None, - opener: Optional[Callable[[PathLink, int], int]] = None + bufsize: Optional[int] = None, + opener: Optional[FileOpener] = None ) -> BinaryIO: ... def xb( self, *, - bufsize: Optional[int] = None, - opener: Optional[Callable[[PathLink, int], int]] = None + bufsize: Optional[int] = None, + opener: Optional[FileOpener] = None ) -> BinaryIO: ... def ab( self, *, - bufsize: Optional[int] = None, - opener: Optional[Callable[[PathLink, int], int]] = None + bufsize: Optional[int] = None, + opener: Optional[FileOpener] = None ) -> BinaryIO: ... def rb_plus( self, *, - bufsize: Optional[int] = None, - opener: Optional[Callable[[PathLink, int], int]] = None + bufsize: Optional[int] = None, + opener: Optional[FileOpener] = None ) -> BinaryIO: ... def wb_plus( self, *, - bufsize: Optional[int] = None, - opener: Optional[Callable[[PathLink, int], int]] = None + bufsize: Optional[int] = None, + opener: Optional[FileOpener] = None ) -> BinaryIO: ... def xb_plus( self, *, - bufsize: Optional[int] = None, - opener: Optional[Callable[[PathLink, int], int]] = None + bufsize: Optional[int] = None, + opener: Optional[FileOpener] = None ) -> BinaryIO: ... def ab_plus( self, *, - bufsize: Optional[int] = None, - opener: Optional[Callable[[PathLink, int], int]] = None + bufsize: Optional[int] = None, + opener: Optional[FileOpener] = None ) -> BinaryIO: ... def r( self, *, - bufsize: Optional[int] = None, - encoding: Optional[str] = None, - errors: Optional[str] = None, - newline: Optional[Literal['', '\n', '\r', '\r\n']] = None, - opener: Optional[Callable[[PathLink, int], int]] = None + bufsize: Optional[int] = None, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[FileNewline] = None, + opener: Optional[FileOpener] = None ) -> TextIO: ... def w( self, *, - bufsize: Optional[int] = None, - encoding: Optional[str] = None, - errors: Optional[str] = None, - newline: Optional[Literal['', '\n', '\r', '\r\n']] = None, - line_buffering: Optional[bool] = None, - write_through: Optional[bool] = None, - opener: Optional[Callable[[PathLink, int], int]] = None + bufsize: Optional[int] = None, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[FileNewline] = None, + line_buffering: Optional[bool] = None, + write_through: Optional[bool] = None, + opener: Optional[FileOpener] = None ) -> TextIO: ... def x( self, *, - bufsize: Optional[int] = None, - encoding: Optional[str] = None, - errors: Optional[str] = None, - newline: Optional[Literal['', '\n', '\r', '\r\n']] = None, - line_buffering: Optional[bool] = None, - write_through: Optional[bool] = None, - opener: Optional[Callable[[PathLink, int], int]] = None + bufsize: Optional[int] = None, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[FileNewline] = None, + line_buffering: Optional[bool] = None, + write_through: Optional[bool] = None, + opener: Optional[FileOpener] = None ) -> TextIO: ... def a( self, *, - bufsize: Optional[int] = None, - encoding: Optional[str] = None, - errors: Optional[str] = None, - newline: Optional[Literal['', '\n', '\r', '\r\n']] = None, - line_buffering: Optional[bool] = None, - write_through: Optional[bool] = None, - opener: Optional[Callable[[PathLink, int], int]] = None + bufsize: Optional[int] = None, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[FileNewline] = None, + line_buffering: Optional[bool] = None, + write_through: Optional[bool] = None, + opener: Optional[FileOpener] = None ) -> TextIO: ... def r_plus( self, *, - bufsize: Optional[int] = None, - encoding: Optional[str] = None, - errors: Optional[str] = None, - newline: Optional[Literal['', '\n', '\r', '\r\n']] = None, - line_buffering: Optional[bool] = None, - write_through: Optional[bool] = None, - opener: Optional[Callable[[PathLink, int], int]] = None + bufsize: Optional[int] = None, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[FileNewline] = None, + line_buffering: Optional[bool] = None, + write_through: Optional[bool] = None, + opener: Optional[FileOpener] = None ) -> TextIO: ... def w_plus( self, *, - bufsize: Optional[int] = None, - encoding: Optional[str] = None, - errors: Optional[str] = None, - newline: Optional[Literal['', '\n', '\r', '\r\n']] = None, - line_buffering: Optional[bool] = None, - write_through: Optional[bool] = None, - opener: Optional[Callable[[PathLink, int], int]] = None + bufsize: Optional[int] = None, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[FileNewline] = None, + line_buffering: Optional[bool] = None, + write_through: Optional[bool] = None, + opener: Optional[FileOpener] = None ) -> TextIO: ... def x_plus( self, *, - bufsize: Optional[int] = None, - encoding: Optional[str] = None, - errors: Optional[str] = None, - newline: Optional[Literal['', '\n', '\r', '\r\n']] = None, - line_buffering: Optional[bool] = None, - write_through: Optional[bool] = None, - opener: Optional[Callable[[PathLink, int], int]] = None + bufsize: Optional[int] = None, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[FileNewline] = None, + line_buffering: Optional[bool] = None, + write_through: Optional[bool] = None, + opener: Optional[FileOpener] = None ) -> TextIO: ... def a_plus( self, *, - bufsize: Optional[int] = None, - encoding: Optional[str] = None, - errors: Optional[str] = None, - newline: Optional[Literal['', '\n', '\r', '\r\n']] = None, - line_buffering: Optional[bool] = None, - write_through: Optional[bool] = None, - opener: Optional[Callable[[PathLink, int], int]] = None + bufsize: Optional[int] = None, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[FileNewline] = None, + line_buffering: Optional[bool] = None, + write_through: Optional[bool] = None, + opener: Optional[FileOpener] = None ) -> TextIO: ... @@ -1527,9 +1544,9 @@ def contains(self, subcontent: bytes, /) -> bool: def copy( self, - dst: Union['Content', BinaryIO], + dst: Union['Content', BinaryIO], /, *, - bufsize: Optional[int] = None + bufsize: Optional[int] = None ) -> None: """ Copy the file contents to another file. @@ -1580,7 +1597,7 @@ def tree( True. @param omit_dir - Omit all subdirectories when yielding paths. Default False. + Omit all subdirectories when yielding paths. The default is False. @param pure_path By default, if the subpath is a directory then yield a `Directory` @@ -1590,7 +1607,7 @@ def tree( @param shortpath Yield short path link string, delete the `dirpath` from the left end of - the path, used with the parameter `pure_path`. Default False. + the path, used with the parameter `pure_path`. The default is False. """ @@ -1598,16 +1615,30 @@ class SystemPath(Directory, File): def __init__( self, - root: Optional[PathLink] = None, + root: Optional[PathLink] = None, /, *, - autoabs: Optional[bool] = None, - strict: Optional[bool] = None + autoabs: Optional[bool] = None, + strict: Optional[bool] = None ): - super().__init__( - '.' if root in (None, '') else b'.' if root == b'' else root, - autoabs=autoabs, - strict =strict - ) + """ + @param root + A path link, hopefully absolute. If it is a relative path, the + current working directory is used as the parent directory (the + return value of `os.getcwd()`). The default value is also the return + value of `os.getcwd()`. + + @param autoabs + Automatically normalize the path link and convert to absolute path, + at initialization. The default is False. It is always recommended + that you enable the parameter when the passed path is a relative + path. + + @param strict + Set to True to enable strict mode, which means that the passed path + must exist, otherwise raise `SystemPathNotFoundError` (or other). + The default is False. + """ + super().__init__(root, autoabs=autoabs, strict =strict) class _xe6_xad_x8c_xe7_x90_xaa_xe6_x80_xa1_xe7_x8e_xb2_xe8_x90_x8d_xe4_xba_x91: diff --git a/systempath/i systempath.py b/systempath/i systempath.py index 6e87548..63a5cb7 100644 --- a/systempath/i systempath.py +++ b/systempath/i systempath.py @@ -75,8 +75,8 @@ def getpwuid(_): raise NotImplementedError from _io import ( FileIO, BufferedReader, BufferedWriter, BufferedRandom, TextIOWrapper, - _BufferedIOBase as BufferedIOBase, - DEFAULT_BUFFER_SIZE as __io_bufsize__ + _BufferedIOBase as BufferedIOBase, + DEFAULT_BUFFER_SIZE ) from hashlib import md5 @@ -97,9 +97,9 @@ def __getitem__(self, *a): ... if sys.version_info >= (3, 10): from typing import TypeAlias else: - TypeAlias = TypeVar("TypeAlias") + TypeAlias = TypeVar('TypeAlias') -import gqylpy_exception as ge +import exceptionx as ex BytesOrStr: TypeAlias = Union[bytes, str] PathLink: TypeAlias = BytesOrStr @@ -123,7 +123,7 @@ def __getitem__(self, *a): ... 'namereplace' ], 'The error handling modes for encoding and decoding (strictness).'] -__unique__: Final[Annotated[object, 'A unique object.']] = object() +UNIQUE: Final[Annotated[object, 'A unique object.']] = object() class MasqueradeClass(type): @@ -182,14 +182,14 @@ class ReadOnlyMode(type, metaclass=MasqueradeClass): def __setattr__(cls, name: str, value: Any) -> None: if sys._getframe(1).f_globals['__package__'] != __package__: - raise ge.SetAttributeError( + raise ex.SetAttributeError( f'cannot set "{name}" attribute ' f'of immutable type "{cls.__name__}".' ) type.__setattr__(cls, name, value) def __delattr__(cls, name: str) -> NoReturn: - raise ge.DeleteAttributeError( + raise ex.DeleteAttributeError( f'cannot delete "{name}" attribute ' f'of immutable type "{cls.__name__}".' ) @@ -197,7 +197,7 @@ def __delattr__(cls, name: str) -> NoReturn: class ReadOnly(metaclass=ReadOnlyMode): # Disallow modifying the attributes of the instances externally. - __module__ = builtins.__name__ + __module__ = builtins.__name__ __qualname__ = object.__name__ # __dict__ = {} @@ -209,7 +209,7 @@ class ReadOnly(metaclass=ReadOnlyMode): def __setattr__(self, name: str, value: Any) -> None: if sys._getframe(1).f_globals['__name__'] != __name__ and not \ (isinstance(self, File) and name in ('content', 'contents')): - raise ge.SetAttributeError( + raise ex.SetAttributeError( f'cannot set "{name}" attribute in instance ' f'of immutable type "{self.__class__.__name__}".' ) @@ -217,7 +217,7 @@ def __setattr__(self, name: str, value: Any) -> None: def __delattr__(self, name: str) -> None: if not isinstance(self, File) or name != 'content': - raise ge.DeleteAttributeError( + raise ex.DeleteAttributeError( f'cannot delete "{name}" attribute in instance ' f'of immutable type "{self.__class__.__name__}".' ) @@ -237,7 +237,7 @@ def core(path: PathType, dst: PathLink) -> PathLink: try: singlename: bool = basename(dst) == dst except TypeError: - raise ge.DestinationPathTypeError( + raise ex.DestinationPathTypeError( 'destination path type can only be "bytes" or "str", ' f'not "{dst.__class__.__name__}".' ) from None @@ -302,18 +302,16 @@ def testpath(testfunc: Callable[[int], bool], path: PathType) -> bool: class Path(ReadOnly): - def __new__( - cls, name: PathLink = __unique__, /, strict: bool = False, **kw - ): + def __new__(cls, name: PathLink = UNIQUE, /, *, strict: bool = False, **kw): # Compatible object deserialization. - if name is not __unique__: + if name is not UNIQUE: if name.__class__ not in (bytes, str): - raise ge.NotAPathError( + raise ex.NotAPathError( 'path type can only be "bytes" or "str", ' f'not "{name.__class__.__name__}".' ) if strict and not exists(name): - raise ge.SystemPathNotFoundError( + raise ex.SystemPathNotFoundError( f'system path {name!r} does not exist.' ) return object.__new__(cls) @@ -383,7 +381,7 @@ def __truediv__(self, subpath: Union[PathType, PathLink], /) -> PathType: elif subpath.__class__ is str: subpath: bytes = subpath.encode() else: - raise ge.NotAPathError( + raise ex.NotAPathError( 'right path can only be an instance of ' f'"{__package__}.{Path.__name__}" or a path link, ' f'not "{subpath.__class__.__name__}".' @@ -404,35 +402,38 @@ def __truediv__(self, subpath: Union[PathType, PathLink], /) -> PathType: else: pathtype = SystemPath - ins: PathType = pathtype( + return pathtype( joined_path, - dir_fd =self.dir_fd, + strict=self.strict, + dir_fd=self.dir_fd, follow_symlinks=self.follow_symlinks ) - ins.strict = self.strict - return ins def __add__(self, subpath: Union[PathType, PathLink], /) -> PathType: - return self / subpath + return self.__truediv__(subpath) def __rtruediv__(self, dirpath: PathLink, /) -> PathType: try: - path: PathLink = join(dirpath, self) + joined_path: PathLink = join(dirpath, self) except TypeError: if dirpath.__class__ is bytes: dirpath: str = dirpath.decode() elif dirpath.__class__ is str: dirpath: bytes = dirpath.encode() else: - raise ge.NotAPathError( + raise ex.NotAPathError( 'left path type can only be "bytes" or "str", ' f'not "{dirpath.__class__.__name__}".' ) from None - path: PathLink = join(dirpath, self) - return self.__class__(path, follow_symlinks=self.follow_symlinks) + joined_path: PathLink = join(dirpath, self) + return self.__class__( + joined_path, + strict=self.strict, + follow_symlinks=self.follow_symlinks + ) def __radd__(self, dirpath: PathLink, /) -> PathType: - return dirpath / self + return self.__rtruediv__(dirpath) @property def basename(self) -> BytesOrStr: @@ -442,8 +443,8 @@ def basename(self) -> BytesOrStr: def dirname(self) -> 'Directory': return Directory( dirname(self), - strict =self.strict, - dir_fd =self.dir_fd, + strict=self.strict, + dir_fd=self.dir_fd, follow_symlinks=self.follow_symlinks ) @@ -453,8 +454,8 @@ def dirnamel(self, level: int) -> 'Directory': directory: PathLink = dirname(directory) return Directory( directory, - strict =self.strict, - dir_fd =self.dir_fd, + strict=self.strict, + dir_fd=self.dir_fd, follow_symlinks=self.follow_symlinks ) @@ -462,43 +463,43 @@ def dirnamel(self, level: int) -> 'Directory': def abspath(self) -> PathType: return self.__class__( abspath(self), - strict =self.strict, + strict=self.strict, follow_symlinks=self.follow_symlinks ) def realpath(self, *, strict: bool = False) -> PathType: return self.__class__( realpath(self, strict=strict), - strict =self.strict, + strict=self.strict, follow_symlinks=self.follow_symlinks ) def relpath(self, start: Optional[PathLink] = None) -> PathType: return self.__class__( relpath(self, start=start), - strict =self.strict, + strict=self.strict, follow_symlinks=self.follow_symlinks ) def normpath(self) -> PathType: return self.__class__( normpath(self), - strict =self.strict, - dir_fd =self.dir_fd, + strict=self.strict, + dir_fd=self.dir_fd, follow_symlinks=self.follow_symlinks ) def expanduser(self) -> PathType: return self.__class__( expanduser(self), - strict =self.strict, + strict=self.strict, follow_symlinks=self.follow_symlinks ) def expandvars(self) -> PathType: return self.__class__( expandvars(self), - strict =self.strict, + strict=self.strict, follow_symlinks=self.follow_symlinks ) @@ -571,41 +572,35 @@ def isempty(self) -> bool: if self.isfile: return not bool(getsize(self)) if self.exists: - raise ge.NotADirectoryOrFileError(repr(self.name)) + raise ex.NotADirectoryOrFileError(repr(self.name)) - raise ge.SystemPathNotFoundError( + raise ex.SystemPathNotFoundError( f'system path {self.name!r} does not exist.' ) @property def readable(self) -> bool: return access( - self, 4, - dir_fd =self.dir_fd, - follow_symlinks=self.follow_symlinks + self, 4, dir_fd=self.dir_fd, follow_symlinks=self.follow_symlinks ) @property def writeable(self) -> bool: return access( - self, 2, - dir_fd =self.dir_fd, - follow_symlinks=self.follow_symlinks + self, 2, dir_fd=self.dir_fd, follow_symlinks=self.follow_symlinks ) @property def executable(self) -> bool: return access( - self, 1, - dir_fd =self.dir_fd, - follow_symlinks=self.follow_symlinks + self, 1, dir_fd=self.dir_fd, follow_symlinks=self.follow_symlinks ) def delete( self, *, - ignore_errors: bool = False, - onerror: Optional[Callable] = None + ignore_errors: bool = False, + onerror: Optional[Callable] = None ) -> None: if self.isdir: rmtree(self, ignore_errors=ignore_errors, onerror=onerror) @@ -630,7 +625,7 @@ def replace(self, dst: PathLink, /) -> None: def move( self, - dst: Union[PathType, PathLink], + dst: Union[PathType, PathLink], /, *, copy_function: Callable[[PathLink, PathLink], None] = copy2 ) -> None: @@ -678,8 +673,8 @@ def chmod(self, mode: int, /) -> None: def access(self, mode: int, /, *, effective_ids: bool = False) -> bool: return access( self, mode, - dir_fd =self.dir_fd, - effective_ids =effective_ids, + dir_fd=self.dir_fd, + effective_ids=effective_ids, follow_symlinks=self.follow_symlinks ) @@ -698,7 +693,7 @@ def group(self) -> str: def chown(self, uid: int, gid: int) -> None: return chown( self, uid, gid, - dir_fd =self.dir_fd, + dir_fd=self.dir_fd, follow_symlinks=self.follow_symlinks ) @@ -717,14 +712,14 @@ def chattr(self, operator: Literal['+', '-', '='], attrs: str) -> None: 'system command `chattr`, so this is very unreliable.' , stacklevel=2) if operator not in ('+', '-', '='): - raise ge.ChattrError( + raise ex.ChattrError( f'unsupported operation "{operator}", only "+", "-" or "=".' ) pathlink: str = self.name if self.name.__class__ is str \ else self.name.decode() c: str = f'chattr {operator}{attrs} {pathlink}' if system(f'sudo {c} &>/dev/null'): - raise ge.ChattrError(c) + raise ex.ChattrError(c) def lsattr(self) -> str: warnings.warn( @@ -738,7 +733,7 @@ def lsattr(self) -> str: "sudo %s 2>/dev/null | awk '{print $1}'" % c ).read()[:-1] if len(attrs) != 16: - raise ge.LsattrError(c) + raise ex.LsattrError(c) return attrs def exattr(self, attr: str, /) -> bool: @@ -751,11 +746,7 @@ def getxattr(self, attribute: BytesOrStr, /) -> bytes: ) def setxattr( - self, - attribute: BytesOrStr, - value: bytes, - *, - flags: int = 0 + self, attribute: BytesOrStr, value: bytes, *, flags: int = 0 ) -> None: setxattr( self, attribute, value, flags, @@ -779,7 +770,7 @@ def utime( ) -> None: utime( self, times, - dir_fd =self.dir_fd, + dir_fd=self.dir_fd, follow_symlinks=self.follow_symlinks ) @@ -787,8 +778,8 @@ def utime( class Directory(Path): def __new__( - cls, name: PathLink = '.', /, strict: bool = False, **kw - ) -> 'Directory': + cls, name: PathLink = '.', /, *, strict: bool = False, **kw +) -> 'Directory': instance = Path.__new__(cls, name, strict=strict, **kw) if strict and not isdir(name): @@ -807,7 +798,7 @@ def __getitem__(self, name: PathLink) -> PathType: return File(name) if exists(name): return Path(name) - raise ge.SystemPathNotFoundError( + raise ex.SystemPathNotFoundError( f'system path {name!r} does not exist.' ) return SystemPath(name) @@ -849,10 +840,10 @@ def tree( *, level: int = float('inf'), downtop: Optional[bool] = None, - bottom_up: bool = __unique__, + bottom_up: bool = UNIQUE, omit_dir: bool = False, pure_path: Optional[bool] = None, - mysophobia: bool = __unique__, + mysophobia: bool = UNIQUE, shortpath: bool = False ) -> Iterator[Union[Path, PathLink]]: return tree( @@ -871,8 +862,8 @@ def walk( ) -> Iterator[Tuple[PathLink, List[BytesOrStr], List[BytesOrStr]]]: return walk( self, - topdown =topdown, - onerror =onerror, + topdown=topdown, + onerror=onerror, followlinks=not self.follow_symlinks ) @@ -898,8 +889,8 @@ def copytree( def clear( self, *, - ignore_errors: bool = False, - onerror: Optional[Callable] = None + ignore_errors: bool = False, + onerror: Optional[Callable] = None ) -> None: for name in listdir(self): path: PathLink = join(self, name) @@ -931,8 +922,8 @@ def removedirs(self) -> None: def rmtree( self, *, - ignore_errors: bool = False, - onerror: Optional[Callable] = None + ignore_errors: bool = False, + onerror: Optional[Callable] = None ) -> None: rmtree(self, ignore_errors=ignore_errors, onerror=onerror) @@ -946,19 +937,23 @@ def chdir(self) -> None: class File(Path): - def __new__( - cls, name: PathLink = __unique__, /, strict: bool = False, **kw - ): + def __new__(cls, name: PathLink = UNIQUE, /, *, strict: bool = False, **kw): instance = Path.__new__(cls, name, strict=strict, **kw) if strict and not isfile(name): - raise ge.NotAFileError(f'system path {name!r} is not a file.') + raise ex.NotAFileError(f'system path {name!r} is not a file.') return instance def __bool__(self) -> bool: return self.isfile + def __contains__(self, subcontent: bytes, /) -> bool: + return subcontent in Content(self) + + def __iter__(self) -> Iterator[bytes]: + yield from Content(self) + def __truediv__(self, other: Any, /) -> NoReturn: x: str = __package__ + '.' + File.__name__ y: str = other.__class__.__name__ @@ -1010,9 +1005,9 @@ def copy(self, dst: Union[PathType, PathLink], /) -> None: def copycontent( self, - other: Union['File', FileIO], + other: Union['File', FileIO], /, *, - bufsize: int = __read_bufsize__ + bufsize: int = __read_bufsize__ ) -> Union['File', FileIO]: write, read = ( FileIO(other.name, 'wb') if isinstance(other, File) else other @@ -1029,8 +1024,8 @@ def copycontent( def link(self, dst: Union[PathType, PathLink], /) -> None: link( self, dst, - src_dir_fd =self.dir_fd, - dst_dir_fd =self.dir_fd, + src_dir_fd=self.dir_fd, + dst_dir_fd=self.dir_fd, follow_symlinks=self.follow_symlinks ) @@ -1047,7 +1042,7 @@ def clear(self) -> None: if sys.platform == 'win32': def mknod( self, - mode: int = 0o600, + mode: int = 0o600, *, ignore_exists: bool = False, **__ @@ -1062,9 +1057,9 @@ def mknod( else: def mknod( self, - mode: int = None, + mode: int = None, *, - device: int = 0, + device: int = 0, ignore_exists: bool = False ) -> None: try: @@ -1075,9 +1070,9 @@ def mknod( def mknods( self, - mode: int = 0o600 if sys.platform == 'win32' else None, + mode: int = 0o600 if sys.platform == 'win32' else None, *, - device: int = 0, + device: int = 0, ignore_exists: bool = False ) -> None: parentdir: PathLink = dirname(self) @@ -1125,7 +1120,7 @@ class Open(ReadOnly): def __init__(self, file: Union[File, PathLink], /): if not isinstance(file, (File, bytes, str)): - raise ge.NotAFileError( + raise ex.NotAFileError( 'file can only be an instance of ' f'"{__package__}.{File.__name__}" or a path link, ' f'not "{file.__class__.__name__}".' @@ -1156,7 +1151,7 @@ def __repr__(self) -> str: def __pass__(self, buffer: Type[BufferedIOBase], mode: OpenMode) -> Closure: def init_buffer_instance( *, - bufsize: int = __io_bufsize__, + bufsize: int = DEFAULT_BUFFER_SIZE, encoding: Optional[str] = None, errors: Optional[EncodingErrorHandlingMode] = None, newline: Optional[str] = None, @@ -1166,8 +1161,8 @@ def init_buffer_instance( ) -> Union[BufferedIOBase, TextIOWrapper]: buf: BufferedIOBase = buffer( raw=FileIO( - file =self.file, - mode =mode.replace('_plus', '+'), + file=self.file, + mode=mode.replace('_plus', '+'), opener=opener ), buffer_size=bufsize @@ -1181,7 +1176,7 @@ def init_buffer_instance( write_through =write_through ) - init_buffer_instance.__name__ = mode + init_buffer_instance.__name__ = mode init_buffer_instance.__qualname__ = f'{Open.__name__}.{mode}' return init_buffer_instance @@ -1198,7 +1193,7 @@ def __bytes__(self) -> bytes: def __ior__(self, other: Union['Content', bytes], /) -> 'Content': if isinstance(other, Content): if abspath(other.file) == abspath(self.file): - raise ge.IsSameFileError( + raise ex.IsSameFileError( 'source and destination cannot be the same, ' f'path "{abspath(self.file)}".' ) @@ -1308,16 +1303,16 @@ def append(self, content: Union['Content', bytes], /) -> None: self.__iadd__(content) def contains(self, subcontent: bytes, /) -> bool: - return subcontent in self + return self.__contains__(subcontent) def copy( self, - other: Union['Content', FileIO], + other: Union['Content', FileIO], /, *, - bufsize: int = __read_bufsize__ + bufsize: int = __read_bufsize__ ) -> None: write = (other.ab() if isinstance(other, Content) else other).write - read = self.rb().read + read = self.rb().read while True: content = read(bufsize) @@ -1352,10 +1347,10 @@ def __init__( /, *, level: int = float('inf'), downtop: Optional[bool] = None, - bottom_up: bool = __unique__, + bottom_up: bool = UNIQUE, omit_dir: bool = False, pure_path: Optional[bool] = None, - mysophobia: bool = __unique__, + mysophobia: bool = UNIQUE, shortpath: bool = False ): if dirpath == b'': @@ -1365,7 +1360,7 @@ def __init__( self.root = dirpath - if bottom_up is not __unique__: + if bottom_up is not UNIQUE: warnings.warn( 'parameter "bottom_up" will be deprecated soon, replaced to ' '"downtop".', stacklevel=2 @@ -1379,7 +1374,7 @@ def __init__( self.omit_dir = omit_dir - if mysophobia is not __unique__: + if mysophobia is not UNIQUE: warnings.warn( 'parameter "mysophobia" will be deprecated soon, replaced to ' '"pure_path".', stacklevel=2 @@ -1460,6 +1455,7 @@ def __init__( follow_symlinks=follow_symlinks ) + __new__ = Path.__new__ __bool__ = Path.__bool__ __truediv__ = Path.__truediv__ diff --git a/test.py b/test.py deleted file mode 100644 index aab294c..0000000 --- a/test.py +++ /dev/null @@ -1,7 +0,0 @@ -from systempath import Directory, File - -home: Directory = Directory.home() - -file: File = home['alpha.txt'] - -file.content = b'GQYLPY \xe6\x94\xb9\xe5\x8f\x98\xe4\xb8\x96\xe7\x95\x8c'