1
1
# /// script
2
+ # requires-python = ">=3.13"
2
3
# dependencies = [
3
- # "requests<3",
4
+ # "httpx~=0.28.1",
5
+ # "colorama",
4
6
# ]
5
7
# ///
6
8
from pathlib import Path
7
- from argparse import ArgumentParser
8
- import requests
9
+ from colorama import init , Fore
10
+
11
+ import argparse
12
+ import textwrap
13
+ import httpx
9
14
import json
10
15
import re
11
16
17
+ # Initialize colorama
18
+ init (autoreset = True )
19
+
20
+
21
+ DROPBOX_PERMISSION_MESSAGE = f"""
22
+ { Fore .YELLOW }
23
+ ----------------------------------------------------
24
+ Make sure the dropbox App includes these permissions
25
+ - files.metadata.read
26
+ - files.content.write
27
+ - files.content.read
28
+ - sharing.write
29
+ - sharing.read
30
+ """
31
+
32
+
33
+ def dropbox_request_error_handler (res : httpx .Response ):
34
+ try :
35
+ res .raise_for_status ()
36
+ except httpx .HTTPStatusError as http_err :
37
+ print (f"{ Fore .RED } HTTP error occurred while requesting { res .url } : { http_err } " )
38
+ print (f"{ Fore .RED } Response content: { res .text } " )
39
+ raise
40
+ except httpx .RequestError as req_err :
41
+ print (
42
+ f"{ Fore .RED } An error occurred while making the request to { res .url } : { req_err } "
43
+ )
44
+ raise
45
+ except Exception as err :
46
+ print (f"{ Fore .RED } An unexpected error occurred: { err } " )
47
+ raise
48
+ finally :
49
+ print (DROPBOX_PERMISSION_MESSAGE )
50
+
51
+
12
52
def dropbox_request (endpoint : str , data : object , * , access_token : str ):
13
53
url = f"https://api.dropboxapi.com/2/{ endpoint } "
14
54
headers = {
15
55
"Authorization" : f"Bearer { access_token } " ,
16
56
"Content-Type" : "application/json" ,
17
57
}
18
- res = requests .post (
58
+ res = httpx .post (
19
59
url ,
20
60
headers = headers ,
21
61
data = json .dumps (data ),
22
62
)
23
- res . raise_for_status ( )
63
+ dropbox_request_error_handler ( res )
24
64
return res .json ()
25
65
26
- def dropbox_content_request (endpoint : str , path : str , data : object , * , access_token : str ):
66
+
67
+ def dropbox_content_request (
68
+ endpoint : str , path : str , data : object , * , access_token : str
69
+ ):
27
70
url = f"https://content.dropboxapi.com/2/{ endpoint } "
28
71
headers = {
29
72
"Authorization" : f"Bearer { access_token } " ,
30
73
"Content-Type" : "application/octet-stream" ,
31
- "Dropbox-API-Arg" : json .dumps ({
32
- "path" : path ,
33
- "mode" : "overwrite" , # overwrite if exists
34
- "autorename" : False ,
35
- "mute" : False
36
- })
74
+ "Dropbox-API-Arg" : json .dumps (
75
+ {
76
+ "path" : path ,
77
+ "mode" : "overwrite" , # overwrite if exists
78
+ "autorename" : False ,
79
+ "mute" : False ,
80
+ }
81
+ ),
37
82
}
38
- res = requests .post (
83
+ res = httpx .post (
39
84
url ,
40
85
headers = headers ,
41
86
data = json .dumps (data ).encode ("utf-8" ),
42
87
)
43
- res . raise_for_status ( )
88
+ dropbox_request_error_handler ( res )
44
89
return res .json ()
45
90
91
+
46
92
def list_all_files (folder_path : str , * , access_token : str ):
47
93
ALLOWED_EXTENSIONS = {".jpg" , ".jpeg" , ".png" , ".webp" }
48
94
files = []
@@ -65,11 +111,14 @@ def list_all_files(folder_path: str, *, access_token: str):
65
111
files = sorted (files , key = lambda file : file ["name" ].lower ())
66
112
# Filter out only files (not folders) that are supported
67
113
files = [
68
- file for file in files
69
- if file [".tag" ] == "file" and Path (file ["name" ]).suffix .lower () in ALLOWED_EXTENSIONS
114
+ file
115
+ for file in files
116
+ if file [".tag" ] == "file"
117
+ and Path (file ["name" ]).suffix .lower () in ALLOWED_EXTENSIONS
70
118
]
71
119
return files
72
120
121
+
73
122
def share_file_and_get_links (files , * , access_token : str ):
74
123
total = len (files )
75
124
images = []
@@ -88,34 +137,40 @@ def share_file_and_get_links(files, *, access_token: str):
88
137
if res .get ("links" ):
89
138
link = res ["links" ][0 ]["url" ]
90
139
else :
91
- data = {
92
- "path" : path ,
93
- "settings" : {
94
- "requested_visibility" : "public"
95
- }
96
- }
140
+ data = {"path" : path , "settings" : {"requested_visibility" : "public" }}
97
141
res_create = dropbox_request (
98
142
"sharing/create_shared_link_with_settings" ,
99
143
data ,
100
144
access_token = access_token ,
101
145
)
102
146
link = res_create ["url" ]
103
147
104
- raw_url = re .sub (r' &dl=0\b' , '' , link ) + ' &raw=1'
148
+ raw_url = re .sub (r" &dl=0\b" , "" , link ) + " &raw=1"
105
149
106
- images .append ({
107
- "id" : i + 1 ,
108
- "file_name" : actual_path ,
109
- "coco_url" : raw_url ,
110
- })
150
+ images .append (
151
+ {
152
+ "id" : i + 1 ,
153
+ "file_name" : actual_path ,
154
+ "coco_url" : raw_url ,
155
+ }
156
+ )
111
157
return images
112
158
113
159
114
160
def main ():
115
- parser = ArgumentParser (description = "Generate COCO file from images folder." )
161
+ parser = argparse .ArgumentParser (
162
+ description = "Generate COCO file from images folder." ,
163
+ formatter_class = argparse .RawDescriptionHelpFormatter ,
164
+ epilog = textwrap .dedent (DROPBOX_PERMISSION_MESSAGE ),
165
+ )
116
166
parser .add_argument ("access_token" , help = "Access token for authentication" )
117
- parser .add_argument ("images_folder" , help = "Path to the images folder" )
118
- parser .add_argument ("export_file_name" , help = "Name of the export COCO file" )
167
+ parser .add_argument (
168
+ "images_folder" , help = 'Path to the images folder in dropbox. eg: "/COCO TEST"'
169
+ )
170
+ parser .add_argument (
171
+ "export_file_name" ,
172
+ help = "Name of the export COCO file to be created in dropbox under provided images_folder" ,
173
+ )
119
174
120
175
args = parser .parse_args ()
121
176
@@ -141,17 +196,18 @@ def main():
141
196
dropbox_content_request (
142
197
"files/upload" ,
143
198
absolute_export_file_name ,
144
- { "images" : public_images },
199
+ {"images" : public_images },
145
200
access_token = access_token ,
146
201
)
147
202
148
203
# Get temporary link
149
204
res = dropbox_request (
150
205
"files/get_temporary_link" ,
151
- { "path" : absolute_export_file_name },
206
+ {"path" : absolute_export_file_name },
152
207
access_token = access_token ,
153
208
)
154
- print (f"COCO file available at { res ["link" ]} " )
209
+ print (f"COCO file available at { res ['link' ]} " )
210
+
155
211
156
212
if __name__ == "__main__" :
157
213
main ()
0 commit comments