Skip to content

Commit 9493779

Browse files
committed
PR feedback
1 parent 2b425bb commit 9493779

18 files changed

+124
-80
lines changed

README.md

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ refreshing files and (Geo)DataFrames or updating layer styles and element proper
2323
pip install felt-python
2424
```
2525

26-
## Documentation
26+
## Notebooks
2727

28-
See the [docs](/docs) directory for Juypter notebooks with complete examples of using the API.
28+
See the [notebooks](/notebooks) directory for Juypter notebooks with complete examples of using the API.
2929

3030
## Basic Usage
3131

@@ -68,5 +68,60 @@ upload = upload_file(
6868
layer_id = upload["layer_id"]
6969
```
7070

71+
### Uploading a Pandas DataFrame
72+
```python
73+
import pandas as pd
74+
from felt_python import upload_dataframe
75+
76+
df = pd.read_csv("path/to/file.csv")
77+
upload_dataframe(
78+
map_id=map_id,
79+
dataframe=df,
80+
layer_name="Felt <3 Pandas",
81+
)
82+
```
83+
84+
### Uploading a GeoPandas GeoDataFrame
85+
```python
86+
import geopandas as gpd
87+
from felt_python import upload_geodataframe
88+
89+
gdf = gpd.read_file("path/to/file.shp")
90+
upload_geodataframe(
91+
map_id=map_id,
92+
geodataframe=gdf,
93+
layer_name="Felt <3 GeoPandas",
94+
)
95+
```
96+
97+
### Refreshing a layer
98+
```python
99+
from felt_python import refresh_file_layer
100+
101+
refresh_file_layer(
102+
map_id=map_id,
103+
layer_id=layer_id,
104+
file_path="path/to/new_file.csv",
105+
)
106+
```
107+
108+
### Styling a layer
109+
```python
110+
from felt_python import get_layer_details, update_layer_style
111+
112+
current_style = get_layer_details(
113+
map_id=map_id,
114+
layer_id=layer_id,
115+
)["style"]
116+
new_style = current_style.copy()
117+
new_style["color"] = "#FF0000"
118+
new_style["size"] = 20
119+
update_layer_style(
120+
map_id=map_id,
121+
layer_id=layer_id,
122+
style=new_style,
123+
)
124+
```
125+
71126
## Support
72127
We are always eager to hear from you. Reach out to [email protected] for all your Felt support needs.

felt_python/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
list_element_groups,
3636
upsert_elements,
3737
delete_element,
38-
show_element_group,
38+
get_element_group,
3939
create_element_groups,
4040
# Deprecated:
4141
post_elements,

felt_python/elements.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""Elements and element groups"""
22

33
import json
4-
from typing import Dict, Any, List, Union
54

65
from urllib.parse import urljoin
76

@@ -51,10 +50,8 @@ def list_element_groups(map_id: str, api_token: str | None = None):
5150
return json.load(response)
5251

5352

54-
def show_element_group(
55-
map_id: str, element_group_id: str, api_token: str | None = None
56-
):
57-
"""Show all elements in a group
53+
def get_element_group(map_id: str, element_group_id: str, api_token: str | None = None):
54+
"""Get contents of an element group
5855
5956
Args:
6057
map_id: The ID of the map containing the group
@@ -72,11 +69,11 @@ def show_element_group(
7269
return json.load(response)
7370

7471

75-
@deprecated(reason="Please use `show_element_group` instead")
72+
@deprecated(reason="Please use `get_element_group` instead")
7673
def list_elements_in_group(
7774
map_id: str, element_group_id: str, api_token: str | None = None
7875
):
79-
show_element_group(map_id, element_group_id, api_token)
76+
get_element_group(map_id, element_group_id, api_token)
8077

8178

8279
@deprecated(reason="Please use `upsert_elements` instead")
@@ -140,7 +137,7 @@ def post_element_group(
140137

141138
def create_element_groups(
142139
map_id: str,
143-
element_groups: List[Dict[str, Any]],
140+
element_groups: list[dict[str, str]],
144141
api_token: str | None = None,
145142
):
146143
"""Post multiple element groups

felt_python/layer_groups.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""Layer groups"""
22

33
import json
4-
from typing import Dict, Any, List, Union, Optional
54

65
from urllib.parse import urljoin
76

@@ -58,7 +57,7 @@ def get_layer_group(
5857

5958
def update_layer_groups(
6059
map_id: str,
61-
layer_group_params_list: List[Dict[str, Any]],
60+
layer_group_params_list: list[dict[str, str | int]],
6261
api_token: str | None = None,
6362
):
6463
"""Update multiple layer groups at once

felt_python/layers.py

Lines changed: 49 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import typing
88
import urllib.request
99
import uuid
10-
from typing import Dict, Any, List, Union, Optional
10+
import typing
1111

1212
from 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-
6641
def 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

12391
def 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

197157
def 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

325285
def 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

464424
def 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")

felt_python/maps.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""Maps"""
22

33
import json
4-
from typing import Dict, Any, List, Union, Optional
54

65
from urllib.parse import urljoin
76

@@ -25,7 +24,7 @@ def create_map(
2524
lat: float = None,
2625
lon: float = None,
2726
zoom: float = None,
28-
layer_urls: List[str] = None,
27+
layer_urls: list[str] = None,
2928
workspace_id: str = None,
3029
api_token: str = None,
3130
):
@@ -208,7 +207,7 @@ def create_embed_token(map_id: str, user_email: str = None, api_token: str = Non
208207

209208

210209
def add_source_layer(
211-
map_id: str, source_layer_params: Dict[str, Any], api_token: str = None
210+
map_id: str, source_layer_params: dict[str, str], api_token: str = None
212211
):
213212
"""Add a layer from a source to a map
214213

felt_python/sources.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import json
44

55
from urllib.parse import urljoin
6-
from typing import Dict, Any, List, Union
76

87
from .api import make_request, BASE_URL
98

@@ -29,8 +28,8 @@ def list_sources(workspace_id: str | None = None, api_token: str | None = None):
2928

3029
def create_source(
3130
name: str,
32-
connection: Dict[str, Any],
33-
permissions: Dict[str, Any] = None,
31+
connection: dict[str, str],
32+
permissions: dict[str, str] = None,
3433
api_token: str | None = None,
3534
):
3635
"""Create a new source
@@ -70,8 +69,8 @@ def get_source(source_id: str, api_token: str | None = None):
7069
def update_source(
7170
source_id: str,
7271
name: str | None = None,
73-
connection: Dict[str, Any] | None = None,
74-
permissions: Dict[str, Any] | None = None,
72+
connection: dict[str, str] | None = None,
73+
permissions: dict[str, str] | None = None,
7574
api_token: str | None = None,
7675
):
7776
"""Update a source's details
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
" delete_map,\n",
2121
" list_elements,\n",
2222
" list_element_groups,\n",
23-
" show_element_group,\n",
23+
" get_element_group,\n",
2424
" upsert_elements,\n",
2525
" delete_element,\n",
2626
" create_element_groups\n",
@@ -230,7 +230,7 @@
230230
"metadata": {},
231231
"outputs": [],
232232
"source": [
233-
"group_elements = show_element_group(map_id, element_group_id)\n",
233+
"group_elements = get_element_group(map_id, element_group_id)\n",
234234
"group_elements"
235235
]
236236
},
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)