pax_global_header00006660000000000000000000000064146466577300014534gustar00rootroot0000000000000052 comment=ae21dc3ace2f022d577f2e7d729fecfcd2fe058b aioshutil-1.5/000077500000000000000000000000001464665773000134025ustar00rootroot00000000000000aioshutil-1.5/.gitattributes000066400000000000000000000011301464665773000162700ustar00rootroot00000000000000# Basic .gitattributes for a python repo. # Source files # ============ *.pxd text diff=python *.py text diff=python *.py3 text diff=python *.pyw text diff=python *.pyx text diff=python *.pyz text diff=python # Binary files # ============ *.db binary *.p binary *.pkl binary *.pickle binary *.pyc binary *.pyd binary *.pyo binary # Jupyter notebook *.ipynb text # Note: .db, .p, and .pkl files are associated # with the python modules ``pickle``, ``dbm.*``, # ``shelve``, ``marshal``, ``anydbm``, & ``bsddb`` # (among others). aioshutil-1.5/.github/000077500000000000000000000000001464665773000147425ustar00rootroot00000000000000aioshutil-1.5/.github/CODEOWNERS000066400000000000000000000000221464665773000163270ustar00rootroot00000000000000* @kumaraditya303 aioshutil-1.5/.github/workflows/000077500000000000000000000000001464665773000167775ustar00rootroot00000000000000aioshutil-1.5/.github/workflows/CI.yml000066400000000000000000000016201464665773000200140ustar00rootroot00000000000000name: CI on: workflow_dispatch: push: branches: - "master" pull_request: jobs: ci: runs-on: ${{ matrix.os }} timeout-minutes: 30 strategy: fail-fast: false matrix: python-version: ["3.8", "3.12", "3.13-dev"] os: [windows-latest, macos-latest, ubuntu-latest] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | pip install --upgrade pip wheel pip install -e. pip install -r requirements.txt - name: Lint uses: pre-commit/action@v2.0.0 - name: Test with Pytest run: pytest - name: Upload Coverage Report uses: codecov/codecov-action@v1.3.1 aioshutil-1.5/.github/workflows/publish.yml000066400000000000000000000014641464665773000211750ustar00rootroot00000000000000name: Upload Python Package on: push: tags: - "v*" jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Python 3.9 uses: actions/setup-python@v2 with: python-version: 3.9 - name: Install dependencies run: | pip install --upgrade pip pip install twine wheel pip install -r requirements.txt - name: Build and publish env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | python setup.py bdist_wheel sdist twine upload dist/* - name: Upload wheels uses: actions/upload-artifact@v2 with: name: wheels path: dist/*.whl aioshutil-1.5/.gitignore000066400000000000000000000043331464665773000153750ustar00rootroot00000000000000 # Created by https://www.toptal.com/developers/gitignore/api/python # Edit at https://www.toptal.com/developers/gitignore?templates=python ### Python ### # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ parts/ sdist/ var/ wheels/ pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ pytestdebug.log # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ doc/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # poetry #poetry.lock # PEP 582; used by e.g. github.com/David-OConnor/pyflow __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments # .env .env/ .venv/ env/ venv/ ENV/ env.bak/ venv.bak/ pythonenv* # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # pytype static type analyzer .pytype/ # operating system-related files *.DS_Store #file properties cache/storage on macOS Thumbs.db #thumbnail cache on Windows # profiling data .prof # End of https://www.toptal.com/developers/gitignore/api/python aioshutil-1.5/.pre-commit-config.yaml000066400000000000000000000011061464665773000176610ustar00rootroot00000000000000repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: check-toml - id: check-added-large-files - id: fix-encoding-pragma - id: requirements-txt-fixer - repo: https://github.com/psf/black rev: 23.1.0 hooks: - id: black - repo: https://github.com/pycqa/flake8 rev: 6.0.0 hooks: - id: flake8 - repo: https://github.com/pycqa/isort rev: 5.12.0 hooks: - id: isort aioshutil-1.5/LICENSE.md000066400000000000000000000030151464665773000150050ustar00rootroot00000000000000BSD 3-Clause License Copyright (c) 2021, Kumar Aditya All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. aioshutil-1.5/README.md000066400000000000000000000026531464665773000146670ustar00rootroot00000000000000# aioshutil: Asynchronous shutil module. [![Downloads](https://static.pepy.tech/badge/aioshutil)](https://pepy.tech/project/aioshutil) ![](https://img.shields.io/pypi/v/aioshutil) ![](https://img.shields.io/pypi/pyversions/aioshutil) ![](https://img.shields.io/pypi/implementation/aioshutil) # Introduction `aioshutil` is a Python library which provides asynchronous version of function of shutil module. `shutil` module is blocking and using it in asyncio applications will block the event loop and slow down the application, `aioshutil` provides asynchronous friendly versions of the functions of the `shutil` module as it performs blocking io in a thread pool. # Installation ```console $ pip install aioshutil ``` # Usage The API of `aioshutil` module is same as `shutil` module except that it is asynchronous. ```python from aioshutil import rmtree await rmtree("/tmp") ``` `aioshutil` provides the following functions: - `copyfileobj` - `copyfile` - `copymode` - `copystat` - `copy` - `copy2` - `copytree` - `move` - `rmtree` - `make_archive` - `get_archive_formats` - `register_archive_format` - `unregister_archive_format` - `get_unpack_formats` - `register_unpack_format` - `unregister_unpack_format` - `unpack_archive` - `ignore_patterns` - `chown` - `which` - `get_terminal_size` `aioshutil` provides the following exceptions for consistency with `shutil` module: - `Error` - `SpecialFileError` - `ExecError` - `SameFileError` aioshutil-1.5/aioshutil/000077500000000000000000000000001464665773000154035ustar00rootroot00000000000000aioshutil-1.5/aioshutil/__init__.py000066400000000000000000000144751464665773000175270ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Asynchronous shutil module. """ from __future__ import annotations import asyncio import shutil from functools import partial, wraps from typing import ( TYPE_CHECKING, Any, Callable, Coroutine, Optional, Sequence, TypeVar, Union, overload, ) try: from typing import ParamSpec, TypeAlias # type: ignore except ImportError: # Python versions < 3.10 from typing_extensions import ParamSpec, TypeAlias __all__ = [ "copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2", "copytree", "move", "rmtree", "Error", "SpecialFileError", "ExecError", "make_archive", "get_archive_formats", "register_archive_format", "unregister_archive_format", "get_unpack_formats", "register_unpack_format", "unregister_unpack_format", "unpack_archive", "ignore_patterns", "chown", "which", "get_terminal_size", "SameFileError", ] P = ParamSpec("P") R = TypeVar("R") if TYPE_CHECKING: # pragma: no cover # type hints for wrapped functions with overloads (which are incompatible # with ParamSpec). import sys from os import PathLike StrPath: TypeAlias = Union[str, PathLike[str]] BytesPath: TypeAlias = Union[bytes, PathLike[bytes]] StrOrBytesPath: TypeAlias = Union[str, bytes, PathLike[str], PathLike[bytes]] _PathReturn: TypeAlias = Any _StrPathT = TypeVar("_StrPathT", bound=StrPath) @overload async def copy( src: StrPath, dst: StrPath, *, follow_symlinks: bool = ... ) -> _PathReturn: ... @overload async def copy( src: BytesPath, dst: BytesPath, *, follow_symlinks: bool = ... ) -> _PathReturn: ... async def copy(src, dst, *, follow_symlinks=...): ... @overload async def copy2( src: StrPath, dst: StrPath, *, follow_symlinks: bool = ... ) -> _PathReturn: ... @overload async def copy2( src: BytesPath, dst: BytesPath, *, follow_symlinks: bool = ... ) -> _PathReturn: ... async def copy2(src, dst, *, follow_symlinks=...): ... @overload async def register_archive_format( name: str, function: Callable[..., object], extra_args: Sequence[tuple[str, Any] | list[Any]], description: str = ..., ) -> None: ... @overload async def register_archive_format( name: str, function: Callable[[str, str], object], extra_args: None = ..., description: str = ..., ) -> None: ... async def register_archive_format(name, function, extra_args=..., description=...): ... @overload async def register_unpack_format( name: str, extensions: list[str], function: Callable[..., object], extra_args: Sequence[tuple[str, Any]], description: str = ..., ) -> None: ... @overload async def register_unpack_format( name: str, extensions: list[str], function: Callable[[str, str], object], extra_args: None = ..., description: str = ..., ) -> None: ... async def register_unpack_format( name, extensions, function, extra_args=..., description=... ): ... @overload async def chown( path: StrOrBytesPath, user: Union[str, int], group: None = ... ) -> None: ... @overload async def chown( path: StrOrBytesPath, user: None = ..., *, group: Union[str, int] ) -> None: ... @overload async def chown(path: StrOrBytesPath, user: None, group: Union[str, int]) -> None: ... @overload async def chown( path: StrOrBytesPath, user: Union[str, int], group: Union[str, int] ) -> None: ... async def chown(path, user=..., group=...): ... if sys.version_info >= (3, 8): @overload async def which( cmd: _StrPathT, mode: int = ..., path: Optional[StrPath] = ... ) -> Union[str, _StrPathT, None]: ... @overload async def which( cmd: bytes, mode: int = ..., path: Optional[StrPath] = ... ) -> Optional[bytes]: ... async def which( cmd, mode=..., path=... ) -> Union[bytes, str, StrPath, PathLike[str], None]: ... else: async def which( cmd: _StrPathT, mode: int = ..., path: StrPath | None = ... ) -> str | _StrPathT | None: ... def sync_to_async(func: Callable[P, R]) -> Callable[P, Coroutine[Any, Any, R]]: @wraps(func) async def run_in_executor(*args: P.args, **kwargs: P.kwargs) -> R: loop = asyncio.get_event_loop() pfunc = partial(func, *args, **kwargs) return await loop.run_in_executor(None, pfunc) return run_in_executor rmtree = sync_to_async(shutil.rmtree) copyfile = sync_to_async(shutil.copyfile) copyfileobj = sync_to_async(shutil.copyfileobj) copymode = sync_to_async(shutil.copymode) copystat = sync_to_async(shutil.copystat) copy = sync_to_async(shutil.copy) # type: ignore # noqa: F811 copy2 = sync_to_async(shutil.copy2) # type: ignore # noqa: F811 copytree = sync_to_async(shutil.copytree) move = sync_to_async(shutil.move) Error = shutil.Error SpecialFileError = shutil.SpecialFileError ExecError = shutil.ExecError make_archive = sync_to_async(shutil.make_archive) get_archive_formats = sync_to_async(shutil.get_archive_formats) register_archive_format = sync_to_async(shutil.register_archive_format) # type: ignore # noqa: F811 unregister_archive_format = sync_to_async(shutil.unregister_archive_format) get_unpack_formats = sync_to_async(shutil.get_unpack_formats) register_unpack_format = sync_to_async(shutil.register_unpack_format) # type: ignore # noqa: F811 unregister_unpack_format = sync_to_async(shutil.unregister_unpack_format) unpack_archive = sync_to_async(shutil.unpack_archive) ignore_patterns = sync_to_async(shutil.ignore_patterns) chown = sync_to_async(shutil.chown) # type: ignore # noqa: F811 which = sync_to_async(shutil.which) # type: ignore # noqa: F811 get_terminal_size = sync_to_async(shutil.get_terminal_size) SameFileError = shutil.SameFileError if "disk_usage" in shutil.__all__: # pragma: no cover __all__.append("disk_usage") disk_usage = sync_to_async(shutil.disk_usage) aioshutil-1.5/aioshutil/py.typed000066400000000000000000000000001464665773000170700ustar00rootroot00000000000000aioshutil-1.5/requirements.txt000066400000000000000000000000571464665773000166700ustar00rootroot00000000000000pre-commit pytest pytest-asyncio pytest-cov aioshutil-1.5/setup.cfg000066400000000000000000000002611464665773000152220ustar00rootroot00000000000000[tool:pytest] addopts = -rsx -vv --cov aioshutil --cov-report xml testpaths = tests [flake8] ignore = E501 W503 E302 W605 [isort] profile = black aioshutil-1.5/setup.py000066400000000000000000000027331464665773000151210ustar00rootroot00000000000000# -*- coding: utf-8 -*- from pathlib import Path from setuptools import setup setup( name="aioshutil", author="Kumar Aditya", author_email="kumaraditya@python.org", url="https://github.com/kumaraditya303/aioshutil", description="Asynchronous shutil module.", keywords=["asyncio", "io", "shutil"], long_description=Path("README.md").read_text(encoding="utf-8"), long_description_content_type="text/markdown", use_scm_version=True, packages=["aioshutil"], license="BSD License", include_package_data=True, zip_safe=False, python_requires=">=3.8", classifiers=[ "Development Status :: 5 - Production/Stable", "Framework :: AsyncIO", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Operating System :: OS Independent", "License :: OSI Approved :: BSD License", ], setup_requires=["setuptools_scm"], install_requires=["typing-extensions;python_version<'3.10'"], ) aioshutil-1.5/tests/000077500000000000000000000000001464665773000145445ustar00rootroot00000000000000aioshutil-1.5/tests/test_aioshutil.py000066400000000000000000000065741464665773000201720ustar00rootroot00000000000000# -*- coding: utf-8 -*- import math import os import stat from pathlib import Path import pytest import aioshutil pytestmark = [pytest.mark.asyncio] async def test_copyfileobj(tmp_path: Path): (tmp_path / "temp.txt").write_text("Hello World!", encoding="utf-8") with open(tmp_path / "temp.txt", "r") as fsrc, open( tmp_path / "temp1.txt", "w" ) as fdst: await aioshutil.copyfileobj(fsrc, fdst) assert (tmp_path / "temp1.txt").read_text() == "Hello World!" async def test_copyfile(tmp_path: Path): (tmp_path / "temp.txt").write_text("Hello World!", encoding="utf-8") await aioshutil.copyfile(tmp_path / "temp.txt", tmp_path / "temp1.txt") assert (tmp_path / "temp1.txt").read_text() == "Hello World!" async def test_copymode(tmp_path: Path): (tmp_path / "temp.txt").write_text("Hello World!", encoding="utf-8") (tmp_path / "temp1.txt").write_text("Hello World!", encoding="utf-8") os.chmod(tmp_path / "temp.txt", stat.S_IEXEC) await aioshutil.copymode(tmp_path / "temp.txt", tmp_path / "temp1.txt") assert (tmp_path / "temp1.txt").stat().st_mode == ( tmp_path / "temp.txt" ).stat().st_mode async def test_copystat(tmp_path: Path): tmp_path.joinpath("temp.txt").write_text("Hello World!", encoding="utf-8") tmp_path.joinpath("temp1.txt").write_text("Hello World!", encoding="utf-8") tmp_path.joinpath("temp1.txt").chmod(stat.S_IEXEC) await aioshutil.copystat(tmp_path / "temp.txt", tmp_path / "temp1.txt") assert math.isclose( tmp_path.joinpath("temp1.txt").stat().st_atime, tmp_path.joinpath("temp.txt").stat().st_atime, rel_tol=1e-6, ) assert ( tmp_path.joinpath("temp1.txt").stat().st_mode == tmp_path.joinpath("temp.txt").stat().st_mode ) async def test_copy(tmp_path: Path): tmp_path.joinpath("temp.txt").write_text("Hello World!", encoding="utf-8") tmp_path.joinpath("temp.txt").chmod( tmp_path.joinpath("temp.txt").stat().st_mode | stat.S_IEXEC ) await aioshutil.copy(tmp_path.joinpath("temp.txt"), tmp_path.joinpath("temp1.txt")) assert ( tmp_path.joinpath("temp1.txt").stat().st_mode == tmp_path.joinpath("temp.txt").stat().st_mode ) async def test_copy2(tmp_path: Path): tmp_path.joinpath("temp.txt").write_text("Hello World!", encoding="utf-8") tmp_path.joinpath("temp.txt").chmod( tmp_path.joinpath("temp.txt").stat().st_mode | stat.S_IEXEC ) await aioshutil.copy2(tmp_path.joinpath("temp.txt"), tmp_path.joinpath("temp1.txt")) assert math.isclose( tmp_path.joinpath("temp1.txt").stat().st_atime, tmp_path.joinpath("temp.txt").stat().st_atime, rel_tol=1e-6, ) assert ( tmp_path.joinpath("temp1.txt").stat().st_mode == tmp_path.joinpath("temp.txt").stat().st_mode ) async def test_copytree(tmp_path: Path): (tmp_path / "foo").mkdir() tmp_path.joinpath("foo", "bar.txt").write_text("Hello World!", encoding="utf-8") await aioshutil.copytree(tmp_path / "foo", tmp_path / "bar") assert (tmp_path / "bar" / "bar.txt").exists() async def test_move(tmp_path: Path): tmp_path.joinpath("temp.txt").write_text("Hello World!", encoding="utf-8") await aioshutil.move(tmp_path.joinpath("temp.txt"), tmp_path.joinpath("temp1.txt")) assert not tmp_path.joinpath("temp.txt").exists() assert tmp_path.joinpath("temp1.txt").exists() aioshutil-1.5/tests/test_typehints.yml000066400000000000000000000010431464665773000203530ustar00rootroot00000000000000- case: decorator_produces_coroutine regex: yes main: | from aioshutil import rmtree reveal_type(rmtree) out: | main:2: note: Revealed type is "def \(.*?\) -> typing\.Coroutine\[Any, Any, \w+\]" skip: sys.version_info < (3, 10) - case: copy_overload_typehint regex: yes main: | from aioshutil import copy reveal_type(copy) out: | main:2: note: Revealed type is "Overload\(def \(.*\) -> typing\.Coroutine\[Any, Any, \w+\], def \(.*\) -> typing\.Coroutine\[Any, Any, \w+\]\)" skip: sys.version_info < (3, 10)