11from typing import Union
22
3- import pyarrow .dataset as ds
4- from funcy import iffy , lmap
5- from pyarrow ._fs import FileInfo , FileSelector
6- from pyarrow .fs import S3FileSystem
7-
8- from odd_collector_aws .domain .plugin import AwsPlugin
3+ from odd_collector_aws .domain .plugin import S3Plugin
94
105from ...domain .dataset_config import DatasetConfig
6+ from ...filesystem .pyarrow_fs import FileSystem as PyarrowFs
7+ from ...utils .remove_s3_protocol import remove_protocol
118from .domain .models import Bucket , File , Folder
129from .logger import logger
1310from .utils import file_format
1411
1512
16- class FileSystem :
13+ class FileSystem ( PyarrowFs ) :
1714 """
1815 FileSystem hides pyarrow.fs implementation details.
1916 """
2017
21- def __init__ (self , config : AwsPlugin ):
22- params = {}
23-
24- if config .aws_access_key_id :
25- params ["access_key" ] = config .aws_access_key_id
26- if config .aws_secret_access_key :
27- params ["secret_key" ] = config .aws_secret_access_key
28- if config .aws_session_token :
29- params ["session_token" ] = config .aws_session_token
30- if config .aws_region :
31- params ["region" ] = config .aws_region
32- if config .endpoint_url :
33- params ["endpoint_override" ] = config .endpoint_url
34-
35- self .fs = S3FileSystem (** params )
36-
37- def get_file_info (self , path : str ) -> list [FileInfo ]:
38- """
39- Get file info from path.
40- @param path: s3 path to file or folder
41- @return: FileInfo
42- """
43- return self .fs .get_file_info (FileSelector (base_dir = path ))
44-
45- def get_dataset (self , file_path : str , format : str ) -> ds .Dataset :
46- """
47- Get dataset from file path.
48- @param file_path:
49- @param format: Should be one of available formats: https://arrow.apache.org/docs/python/api/dataset.html#file-format
50- @return: Dataset
51- """
52- return ds .dataset (source = file_path , filesystem = self .fs , format = format )
18+ def __init__ (self , config : S3Plugin ):
19+ self .fs = PyarrowFs (config )
20+ self .filename_filter = config .filename_filter
5321
5422 def get_folder_as_file (self , dataset_config : DatasetConfig ) -> File :
5523 """
@@ -59,15 +27,13 @@ def get_folder_as_file(self, dataset_config: DatasetConfig) -> File:
5927 """
6028 logger .debug (f"Getting folder dataset for { dataset_config = } " )
6129
62- dataset = ds . dataset (
63- source = dataset_config .full_path ,
30+ dataset = self . get_dataset (
31+ path = dataset_config .full_path ,
6432 format = dataset_config .folder_as_dataset .file_format ,
65- partitioning = ds .partitioning (
66- flavor = dataset_config .folder_as_dataset .flavor ,
67- field_names = dataset_config .folder_as_dataset .field_names ,
68- ),
69- filesystem = self .fs ,
33+ partitioning_flavor = dataset_config .folder_as_dataset .flavor ,
34+ field_names = dataset_config .folder_as_dataset .field_names ,
7035 )
36+
7137 return File (
7238 path = dataset_config .full_path ,
7339 base_name = dataset_config .full_path ,
@@ -103,14 +69,18 @@ def list_objects(self, path: str) -> list[Union[File, Folder]]:
10369 @return: list of either File or Folder
10470 """
10571 logger .debug (f"Getting objects for { path = } " )
106- return lmap (
107- iffy (
108- lambda x : x .is_file ,
109- lambda x : self .get_file (x .path , x .base_name ),
110- lambda x : self .get_folder (x .path ),
111- ),
112- self .get_file_info (path ),
113- )
72+ objects = []
73+
74+ for obj in self .fs .get_file_info (path ):
75+ if obj .is_file :
76+ if not self .filename_filter .is_allowed (obj .base_name ):
77+ continue
78+
79+ objects .append (self .get_file (obj .path , obj .base_name ))
80+ else :
81+ objects .append (self .get_folder (obj .path ))
82+
83+ return objects
11484
11585 def get_file (self , path : str , file_name : str = None ) -> File :
11686 """
@@ -125,7 +95,7 @@ def get_file(self, path: str, file_name: str = None) -> File:
12595
12696 try :
12797 file_fmt = file_format (file_name )
128- dataset = self .get_dataset (path , file_fmt )
98+ dataset = self .fs . get_dataset (path , file_fmt )
12999
130100 return File .dataset (
131101 path = path ,
@@ -146,17 +116,9 @@ def get_folder(self, path: str, recursive: bool = True) -> Folder:
146116 """
147117 Get Folder with objects recursively.
148118 @param path: s3 path to
119+ @param recursive: Flag to recursively search nested objects
149120 @return: Folder class with objects and path
150121 """
151122 path = remove_protocol (path )
152123 objects = self .list_objects (path ) if recursive else []
153124 return Folder (path , objects )
154-
155-
156- def remove_protocol (path : str ) -> str :
157- if path .startswith ("s3://" ):
158- return path .removeprefix ("s3://" )
159- elif path .startswith (("s3a://" , "s3n://" )):
160- return path [6 :]
161- else :
162- return path
0 commit comments