77import typing
88import urllib .request
99import uuid
10- from typing import Dict , Any , List , Union , Optional
10+ import typing
1111
1212from urllib .parse import urljoin
1313
@@ -38,37 +38,12 @@ def list_layers(map_id: str, api_token: str | None = None):
3838 return json .load (response )
3939
4040
41- def _multipart_request (
42- url : str , presigned_attributes : dict [str , str ], file_obj : typing .IO [bytes ]
43- ) -> urllib .request .Request :
44- """Make a multipart/form-data request with the given file"""
45- boundary = "-" * 20 + str (uuid .uuid4 ())
46- headers = {"Content-Type" : f'multipart/form-data; boundary="{ boundary } "' }
47- fname = os .path .basename (file_obj .name )
48-
49- data = io .BytesIO ()
50- text = io .TextIOWrapper (data , encoding = "latin-1" )
51- for key , value in presigned_attributes .items ():
52- text .write (f"--{ boundary } \r \n " )
53- text .write (f'Content-Disposition: form-data; name="{ key } "\r \n \r \n ' )
54- text .write (f"{ value } \r \n " )
55- text .write (f"--{ boundary } \r \n " )
56- text .write (f'Content-Disposition: form-data; name="file"; filename="{ fname } "\r \n ' )
57- text .write ("Content-Type: application/octet-stream\r \n \r \n " )
58- text .flush ()
59- data .write (file_obj .read ())
60- data .write (f"\r \n --{ boundary } " .encode ("latin-1" ))
61- body = data .getvalue ()
62-
63- return urllib .request .Request (url , data = body , headers = headers , method = "POST" )
64-
65-
6641def upload_file (
6742 map_id : str ,
6843 file_name : str ,
6944 layer_name : str ,
70- metadata : Dict [str , Any ] = None ,
71- hints : List [ Dict [str , Any ]] = None ,
45+ metadata : dict [str , str ] = None ,
46+ hints : list [ dict [str , str ]] = None ,
7247 lat : float = None ,
7348 lng : float = None ,
7449 zoom : float = None ,
@@ -109,23 +84,16 @@ def upload_file(
10984 api_token = api_token ,
11085 json = json_payload ,
11186 )
112- presigned_upload = json .load (response )
113- url = presigned_upload ["url" ]
114- presigned_attributes = presigned_upload ["presigned_attributes" ]
11587
116- with open (file_name , "rb" ) as file_obj :
117- request = _multipart_request (url , presigned_attributes , file_obj )
118- urllib .request .urlopen (request )
119-
120- return presigned_upload
88+ return _upload_file (json .load (response ), file_name )
12189
12290
12391def upload_dataframe (
12492 map_id : str ,
12593 dataframe : "pd.DataFrame" ,
12694 layer_name : str ,
127- metadata : Dict [str , Any ] = None ,
128- hints : List [ Dict [str , Any ]] = None ,
95+ metadata : dict [str , str ] = None ,
96+ hints : list [ dict [str , str ]] = None ,
12997 api_token : str | None = None ,
13098):
13199 """Upload a Pandas DataFrame to a Felt map"""
@@ -146,8 +114,8 @@ def upload_geodataframe(
146114 map_id : str ,
147115 geodataframe : "gpd.GeoDataFrame" ,
148116 layer_name : str ,
149- metadata : Dict [str , Any ] = None ,
150- hints : List [ Dict [str , Any ]] = None ,
117+ metadata : dict [str , str ] = None ,
118+ hints : list [ dict [str , str ]] = None ,
151119 api_token : str | None = None ,
152120):
153121 """Upload a GeoPandas GeoDataFrame to a Felt map"""
@@ -183,23 +151,15 @@ def refresh_file_layer(
183151 method = "POST" ,
184152 api_token = api_token ,
185153 )
186- presigned_upload = json .load (response )
187- url = presigned_upload ["url" ]
188- presigned_attributes = presigned_upload ["presigned_attributes" ]
189-
190- with open (file_name , "rb" ) as file_obj :
191- request = _multipart_request (url , presigned_attributes , file_obj )
192- urllib .request .urlopen (request )
193-
194- return presigned_upload
154+ return _upload_file (json .load (response ), file_name )
195155
196156
197157def upload_url (
198158 map_id : str ,
199159 layer_url : str ,
200160 layer_name : str ,
201- metadata : Dict [str , Any ] = None ,
202- hints : List [ Dict [str , Any ]] = None ,
161+ metadata : dict [str , str ] = None ,
162+ hints : list [ dict [str , str ]] = None ,
203163 api_token : str | None = None ,
204164):
205165 """Upload a URL to a Felt map
@@ -324,7 +284,7 @@ def download_layer(
324284
325285def update_layers (
326286 map_id : str ,
327- layer_params_list : List [ Dict [str , Any ]],
287+ layer_params_list : list [ dict [str , object ]],
328288 api_token : str | None = None ,
329289):
330290 """Update multiple layers at once
@@ -396,7 +356,7 @@ def create_custom_export(
396356 map_id : str ,
397357 layer_id : str ,
398358 output_format : str ,
399- filters : List [ Dict [ str , Any ]] = None ,
359+ filters : list = None ,
400360 email_on_completion : bool = True ,
401361 api_token : str | None = None ,
402362):
@@ -462,7 +422,7 @@ def get_custom_export_status(
462422
463423
464424def duplicate_layers (
465- duplicate_params : List [ Dict [str , str ]], api_token : str | None = None
425+ duplicate_params : list [ dict [str , str ]], api_token : str | None = None
466426):
467427 """Duplicate layers from one map to another
468428
@@ -486,3 +446,38 @@ def duplicate_layers(
486446 api_token = api_token ,
487447 )
488448 return json .load (response )
449+
450+
451+ def _upload_file (presigned_upload , file_name ):
452+ url = presigned_upload ["url" ]
453+ presigned_attributes = presigned_upload ["presigned_attributes" ]
454+
455+ with open (file_name , "rb" ) as file_obj :
456+ request = _multipart_request (url , presigned_attributes , file_obj )
457+ urllib .request .urlopen (request )
458+ return presigned_upload
459+
460+
461+ def _multipart_request (
462+ url : str , presigned_attributes : dict [str , str ], file_obj : typing .IO [bytes ]
463+ ) -> urllib .request .Request :
464+ """Make a multipart/form-data request with the given file"""
465+ boundary = "-" * 20 + str (uuid .uuid4 ())
466+ headers = {"Content-Type" : f'multipart/form-data; boundary="{ boundary } "' }
467+ fname = os .path .basename (file_obj .name )
468+
469+ data = io .BytesIO ()
470+ text = io .TextIOWrapper (data , encoding = "latin-1" )
471+ for key , value in presigned_attributes .items ():
472+ text .write (f"--{ boundary } \r \n " )
473+ text .write (f'Content-Disposition: form-data; name="{ key } "\r \n \r \n ' )
474+ text .write (f"{ value } \r \n " )
475+ text .write (f"--{ boundary } \r \n " )
476+ text .write (f'Content-Disposition: form-data; name="file"; filename="{ fname } "\r \n ' )
477+ text .write ("Content-Type: application/octet-stream\r \n \r \n " )
478+ text .flush ()
479+ data .write (file_obj .read ())
480+ data .write (f"\r \n --{ boundary } " .encode ("latin-1" ))
481+ body = data .getvalue ()
482+
483+ return urllib .request .Request (url , data = body , headers = headers , method = "POST" )
0 commit comments