Source code for idmtools.assets.file_list
"""
idmtools FileList classes.
Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
"""
from typing import List
import os
import re
from idmtools.assets import Asset, AssetCollection
from idmtools.utils.local_os import LocalOS
[docs]class FileList:
"""
Special utility class to help handling user files.
"""
[docs] def __init__(self, root=None, files_in_root=None, recursive=False, ignore_missing=False, relative_path=None,
max_depth=3):
"""
Represents a set of files that are specified RELATIVE to root.
e.g. /a/b/c.json could be : root: '/a' files_in_root: ['b/c.json']
:param root: The dir all files_in_root are relative to.
:param files_in_root: The listed files
"""
self.files: List[Asset] = []
self.ignore_missing = ignore_missing
self.max_depth = max_depth
# Make sure we have correct separator
# os.path.normpath(f) would be best but is not working the same way on UNIX systems
if files_in_root is not None:
if LocalOS.is_window():
files_in_root = [os.path.normpath(f) for f in files_in_root]
else:
files_in_root = [re.sub(r"[\\/]", os.sep, os.path.normpath(f)) for f in files_in_root]
if root:
self.add_path(path=root, files_in_dir=files_in_root, recursive=recursive, relative_path=relative_path)
[docs] def add_asset_file(self, af):
"""
Method used to add asset file.
Args:
af: asset file to add
Returns: None
"""
self.files.append(af)
[docs] def add_file(self, path, relative_path=''):
"""
Method used to add a file.
Args:
path: file oath
relative_path: file relative path
Returns: None
"""
# If already present -> bypass
for f in self.files:
if f.absolute_path and os.path.abspath(f.absolute_path) == os.path.abspath(path):
return
if os.path.isdir(path):
raise ValueError("%s is a directory. add_file is expecting a file!" % path)
absolute_path = os.path.abspath(path)
file_name = os.path.basename(path)
try:
af = Asset(filename=file_name, relative_path=relative_path, absolute_path=absolute_path)
self.add_asset_file(af)
except Exception as e:
if not self.ignore_missing:
raise e
[docs] def add_path(self, path, files_in_dir=None, relative_path=None, recursive=False):
"""
Add a path to the file list.
Args:
path: The path to add (needs to be a dictionary)
files_in_dir: If we want to only retrieve certain files in this path
relative_path: relative_path: The relative path prefixed to each added files
recursive: Do we want to browse recursively
Returns: None
"""
# Little safety
if not os.path.isdir(path) and not path.startswith('\\\\'):
raise RuntimeError("add_path() requires a directory. '%s' is not." % path)
if not recursive:
if files_in_dir is None:
files_in_dir = [f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))]
for file_name in files_in_dir:
file_path = os.path.join(path, file_name)
f_relative_path = os.path.normpath(
file_path.replace(path, '').strip(os.sep).replace(os.path.basename(file_path), ''))
if relative_path is not None:
f_relative_path = os.path.join(relative_path, f_relative_path)
self.add_file(file_path, relative_path=f_relative_path)
else:
# Walk through the path
for root, _subdirs, files in os.walk(path):
# Little safety to not go too deep
depth = root[len(path) + len(os.path.sep):].count(os.path.sep)
if depth > self.max_depth:
continue
# Add the files in the current dir
for f in files:
# Find the file relative path compared to the root folder
# If the relative_path is . -> change it into ''
f_relative_path = os.path.normpath(os.path.relpath(root, path))
if f_relative_path == '.':
f_relative_path = ''
# if files_in_dir specified -> skip the ones not included
if files_in_dir is not None and f not in files_in_dir and os.path.join(f_relative_path,
f) not in files_in_dir:
continue
# if we want to force a relative path -> force it
if relative_path is not None:
f_relative_path = os.path.join(relative_path, f_relative_path)
# add the file
self.add_file(os.path.join(root, f), relative_path=f_relative_path)
[docs] def to_asset_collection(self) -> AssetCollection:
"""
Convert a file list to an asset collection.
Returns:
AssetCollection version of filelist
"""
ac = AssetCollection()
ac.assets = self.files
return ac
[docs] @staticmethod
def from_asset_collection(asset_collection: AssetCollection) -> 'FileList':
"""
Create a FileList from a AssetCollection.
Args:
asset_collection: AssetCollection to convert.
Returns:
FileList version of AssetCollection
"""
fl = FileList()
fl.files = [asset_collection.assets]
return fl
def __len__(self):
"""
Length of FileList.
Returns:
Length
"""
return len(self.files)
def __iter__(self):
"""
Iterator. Basically we proxy self.files.
Returns:
Iterator
"""
return self.files.__iter__()
def __getitem__(self, item):
"""
Get file.
Args:
item: Item
Returns:
Item
"""
return self.files.__getitem__(item)