Skip to content

Commit

Permalink
Merge pull request #10 from kfirgoldberg/kfir/feature/str_anypath_int…
Browse files Browse the repository at this point in the history
…eroperability

added new type `AnyPathLikeType = NewType('AnyPathLikeType', Union[str, Path, 'AnyPath'])` which is now used in the `init` and `copy` of `AnyPath`
  • Loading branch information
kfirgoldberg authored May 30, 2024
2 parents f0db6ac + d6c6aa9 commit 9b7ba9d
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 5 deletions.
17 changes: 12 additions & 5 deletions anypathlib/anypath.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import shutil
import tempfile
from pathlib import Path, PurePath
from typing import Union, Optional, List, Dict
from typing import Union, Optional, List, Dict, NewType
from urllib.parse import urlparse

from anypathlib.path_handlers.azure_handler import AzureHandler
Expand All @@ -10,20 +10,24 @@
from anypathlib.path_handlers.path_types import PathType
from anypathlib.path_handlers.s3_handler import S3Handler

AnyPathLikeType = NewType('AnyPathLikeType', Union[str, Path, 'AnyPath'])


class AnyPath:
PATH_HANDLERS: Dict[PathType, BasePathHandler] = {PathType.local: LocalPathHandler,
PathType.s3: S3Handler,
PathType.azure: AzureHandler}
LOCAL_CACHE_PATH = Path(tempfile.gettempdir()) / 'AnyPath'

def __init__(self, base_path: Union[Path, str]):
def __init__(self, base_path: AnyPathLikeType):
if type(base_path) is str:
self._base_path = base_path
elif issubclass(type(base_path), PurePath):
self._base_path = base_path.absolute().as_posix()
elif type(base_path) is AnyPath:
self._base_path = base_path.base_path
else:
raise ValueError(f'base_path must be of type str or Path, got {type(base_path)}')
raise ValueError(f'base_path must be of type str, Path or AnyPath, got {type(base_path)}')
self.path_type = self.get_path_type(self._base_path)
self.path_handler = self.PATH_HANDLERS[self.path_type]

Expand Down Expand Up @@ -77,6 +81,8 @@ def base_path(self) -> str:
base_path = base_path.replace('s3:/', 's3://')
if base_path[-1] == '/':
base_path = base_path[:-1]
elif self.path_type == PathType.local:
base_path = Path(self._base_path).as_posix()
else:
base_path = self._base_path
return base_path
Expand Down Expand Up @@ -156,12 +162,13 @@ def __get_local_cache_path(self) -> 'AnyPath':
local_cache_path.parent.mkdir(exist_ok=True, parents=True)
return AnyPath(local_cache_path)

def copy(self, target: Optional['AnyPath'] = None, force_overwrite: bool = True, verbose: bool = False) -> 'AnyPath':
def copy(self, target: Optional[AnyPathLikeType] = None, force_overwrite: bool = True,
verbose: bool = False) -> 'AnyPath':
assert self.exists(), f'source path: {self.base_path} does not exist'
if target is None:
valid_target = self.__get_local_cache_path()
else:
valid_target = target
valid_target = AnyPath(target)
if valid_target.is_local:
self.__get_local_path(target_path=Path(valid_target.base_path), force_overwrite=force_overwrite,
verbose=verbose)
Expand Down
3 changes: 3 additions & 0 deletions tests/test_anypath_flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,7 @@ def test_caching(path_type: PathType, temp_dir_with_files, clean_remote_dir, ver
cloud_handler.upload_directory(local_dir=local_dir_path, target_url=remote_dir, verbose=verbose)
target1 = AnyPath(remote_dir).copy(target=None, force_overwrite=False, verbose=verbose)
target2 = AnyPath(remote_dir).copy(target=None, force_overwrite=False, verbose=verbose)
target1.remove()
if target2.exists():
target2.remove()
assert target1.base_path == target2.base_path
30 changes: 30 additions & 0 deletions tests/test_str_path_interoperability.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from pathlib import Path

import pytest

from anypathlib import AnyPath, PathType
from fixtures_anypath import temp_local_dir, temp_dir_with_files, clean_remote_dir
from tests.tests_urls import PATH_TYPE_TO_HANDLER


def test_init_anypath_from_anypath(tmpdir):
tmpdir_str = str(Path(tmpdir.dirname))
local_path = AnyPath(tmpdir_str)
local_path_init_from_anypath = AnyPath(local_path)
assert local_path_init_from_anypath.base_path == local_path.base_path
local_path_init_from_path = AnyPath(Path(tmpdir_str))
assert local_path_init_from_path.base_path == local_path.base_path


@pytest.mark.usefixtures("temp_dir_with_files", "temp_local_dir", "clean_remote_dir")
@pytest.mark.parametrize("target_type", [str, Path, AnyPath])
@pytest.mark.parametrize("path_type", [PathType.azure, PathType.s3])
def test_copy_targets(path_type: PathType, target_type, temp_dir_with_files, temp_local_dir, clean_remote_dir):
cloud_handler = PATH_TYPE_TO_HANDLER[path_type]
local_dir_path, local_dir_files = temp_dir_with_files
temp_local_dir = target_type(temp_local_dir)
remote_dir = clean_remote_dir
cloud_handler.upload_directory(local_dir=local_dir_path, target_url=remote_dir, verbose=False)
local_download_dir = AnyPath(remote_dir).copy(target=temp_local_dir, force_overwrite=True)
remote_files = AnyPath(remote_dir).listdir()
assert sorted([fn.name for fn in remote_files]) == sorted([fn.name for fn in local_download_dir.listdir()])

0 comments on commit 9b7ba9d

Please sign in to comment.