Coverage for awsutils / aws_s3_upload.py: 94%
83 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-21 13:47 +0900
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-21 13:47 +0900
1# -*- config: utf-8 -*-
2'''aws_s3_upload module.
4Copyright ycookjp
5https://github.com/ycookjp/
7'''
9import boto3
10import logging
11import os
12import shutil
13import sys
14import yaml
16class AWSS3MoveConfig():
17 region_name = ''
18 '''
19 リージョン名
20 '''
21 access_key_id = None
22 '''
23 IAMユーザーのアクセスキー
24 '''
25 secret_access_key = None
26 '''
27 IAMユーザーのシークレットアクセスキー
28 '''
30def _load_config(script_path: str):
31 '''
33 Loads configuration file with YAMS format.
34 Configuration file should be located at same directory of specified
35 script path, and name should be base name of this script except for
36 extension is '.yml'.
38 Args:
39 script_path (str): script path
41 Returns:
42 AWSS3MoveConfig: Returns configuration object.
44 '''
45 config_path = os.path.splitext(script_path)[0] + '.yml'
46 with open(config_path, 'r', encoding='utf-8') as file:
47 yaml_conf = yaml.load(file, Loader=yaml.SafeLoader)
48 config = AWSS3MoveConfig()
49 config.region_name = yaml_conf['region_name']
50 config.access_key_id = yaml_conf.get('access_key_id')
51 config.secret_access_key = yaml_conf.get('secret_access_key')
53 return config
55def _operation_log(file_path: str, s3bucket_name: str, s3key: str,
56 remove_src: bool):
57 '''
59 ファイルのアップロード/移動のログを出力します。
61 Arts:
62 file_path (str): アップロード/移動したファイルのパス
63 s3bucket_name (str): アップロード/移動先のS3バケット名
64 s3key (str): アップロード/移動先のキー(パス月乃ファイル名)
65 remove_src (bool): ファイルを移動した場合はTrue
67 '''
68 action = 'uploaded'
69 if remove_src:
70 action = 'moved'
72 logging.info(f"{action} {file_path} to s3://{s3bucket_name}/{s3key}")
74def _remove_files(file_path: str):
75 '''
77 指定されたファイル、または指定されたディレクトリ配下のファイル・ディレクトリ
78 を削除します。
80 Args:
81 file_path (str): 削除対象のファイルまたはディレクトリのパス
83 '''
84 if os.path.isfile(file_path):
85 os.remove(file_path)
86 elif os.path.isdir(file_path): 86 ↛ exitline 86 didn't return from function '_remove_files' because the condition on line 86 was always true
87 for name in os.listdir(file_path):
88 name_path = os.path.join(file_path, name)
89 if os.path.isfile(name_path):
90 os.remove(name_path)
91 elif os.path.isdir(name_path): 91 ↛ 87line 91 didn't jump to line 87 because the condition on line 91 was always true
92 shutil.rmtree(name_path)
94def _get_s3_key(s3_folder_path: str, top_dir: str, file_path: str):
95 '''
97 S3バケットのフォルダ名と、アップロード対象ファイルの最上位パスからの
98 相対パスを使用して、S3のキーを取得します。
100 Args:
101 s3_folder_path (str): S3バケットのフォルダの名前。サブフォルダの階層を
102 持つ場合は、フォルダを'/'で区切って指定する。
103 top_dir (str): アップロード対象のファイルが格納されているディレクトリの
104 最上位ディレクトリ。
105 file_path (str): アップロード対象のファイルのパス。
106 Returns:
107 str: s3パケットのフォルダ名の後ろに、アップロード対象ファイルの
108 最上位ディレクトリからの相対パスを'/'で連結した文字列を返します。
110 '''
111 s3key = file_path
113 if top_dir != None and len(top_dir) > 0 and file_path.index(top_dir) == 0: 113 ↛ 116line 113 didn't jump to line 116 because the condition on line 113 was always true
114 s3key = s3key[len(top_dir):len(s3key)]
116 if s3key[0] == os.sep:
117 s3key = s3key[1:len(s3key)]
119 if os.sep != '/':
120 s3key = s3key.replace(os.sep, '/')
122 if s3_folder_path != None and len(s3_folder_path) > 0:
123 s3key = s3_folder_path + '/' + s3key
125 return s3key
127def upload_file(file_or_dir_path: str, s3bucket_name: str, s3folder_path: str=None,
128 remove_src:bool=False, script_path:str=__file__,
129 access_key_id:str=None, secret_access_key:str=None):
130 '''
132 指定されたファイル、または指定されたディレクトリを再帰的に探して取得した
133 ファイルを指定されたS3バケットのs3フォルダの下にアップロードします。
134 この関数は、引数で指定されたスクリプトパスと同じディレクトリに存在する
135 設定ファイル(スクリプトファイルと同じディレクトリに配置された、
136 スクリプト名の拡張子が'.yml'であるファイル)から、以下の情報を取得して
137 AWSのS3サービスに接続します。
139 * region_name - リージョン名
140 * access_key_id - (オプション) IAMユーザーのアクセスキー。引数にアクセスキーが
141 指定されなかった場合は、設定ファイルから取得したものを使用する。
142 * secret_access_key - (オプション) IAMユーザーのシークレットキー。引数に
143 シークレットキーが指定されなかった場合は、設定ファイルから取得した
144 ものを使用する。
146 Args:
147 file_or_dir_path (str): アップロード対象のファイルのパス、または
148 ファイルを配置したディレクトリを指定します。
149 s3bucket_name (str): アップロード先のS3バケット名を指定します。
150 s3folder_path (str, optional): アップロード先のS3フォルダ名を
151 指定します。S3フォルダがサブフォルダの場合は、フォルダの間を'/'で
152 区切ります。この引数を省略するとフォルダ名を付けずにアップロード
153 します。
154 remove_src (bool, optional): ファイルをアップロード後に
155 元のファイルを削除する場合はTrue、削除しない場合はFalseを指定
156 します。Trueを指定した場合は、アップロード対象がファイルの場合は
157 そのファイルを、ディレクトリの場合は、そのディレクトリ配下の
158 ファイル・ディレクトリを削除します。
159 script_path (str, optional): スクリプトのパス
160 access_key_id (str, optional): IAMユーザーのアクセスキー
161 secret_access_key (str, optional): IAMユーザーのシークレットキー
163 Raises:
164 Exception: file_or_dir_path で指定したパスがファイルでも
165 ディレクトリでも無い場合
167 '''
168 config = _load_config(script_path)
169 if access_key_id == None: 169 ↛ 171line 169 didn't jump to line 171 because the condition on line 169 was always true
170 access_key_id = config.access_key_id
171 if secret_access_key == None: 171 ↛ 174line 171 didn't jump to line 174 because the condition on line 171 was always true
172 secret_access_key = config.secret_access_key
174 s3_client = boto3.client('s3', aws_access_key_id=access_key_id,
175 aws_secret_access_key=secret_access_key)
177 if os.path.isfile(file_or_dir_path):
178 file_path = file_or_dir_path
179 s3key = _get_s3_key(s3folder_path, os.path.dirname(file_path), file_path)
180 s3_client.upload_file(file_path, s3bucket_name, s3key)
181 _operation_log(file_path, s3bucket_name, s3key, remove_src)
182 elif os.path.isdir(file_or_dir_path):
183 topdir = os.path.abspath(file_or_dir_path)
184 for dirpath, dirnames, filenames in os.walk(topdir):
185 filenames.sort()
186 for filename in filenames:
187 file_path = os.path.join(dirpath, filename)
188 s3key = _get_s3_key(s3folder_path, topdir, file_path)
189 s3_client.upload_file(file_path, s3bucket_name, s3key)
190 _operation_log(file_path, s3bucket_name, s3key, remove_src)
191 else:
192 raise Exception('Not found source file or directory')
194 if remove_src:
195 _remove_files(file_or_dir_path)
197def main(args):
198 file_or_dir_path = args[1]
199 s3bucket_name = args[2]
200 s3folder_path = args[3]
201 remove_src = False
202 if len(args) > 4:
203 val = args[4].lower()
204 remove_src = val == 'true'
206 upload_file(file_or_dir_path, s3bucket_name, s3folder_path, remove_src)
208if __name__ == '__main__': 208 ↛ 209line 208 didn't jump to line 209 because the condition on line 208 was never true
209 main(sys.argv)