Skip to content

Commit 2a85633

Browse files
authored
Merge branch 'main' into CUST-4514-python-sdk-handle-non-json-responses-html-fastly-empty-etc-stemming-from-500-s
2 parents ebedcce + 5536a00 commit 2a85633

File tree

7 files changed

+478
-20
lines changed

7 files changed

+478
-20
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ nylas-python Changelog
44
Unreleased
55
----------------
66
* Added handling for non-JSON responses
7+
* Added support for `single_level` query parameter in `ListFolderQueryParams` for Microsoft accounts to control folder hierarchy traversal
78
* Added support for `earliest_message_date` query parameter for threads
89
* Fixed `earliest_message_date` not being an optional response field
910
* Added support for new message fields query parameter values: `include_tracking_options` and `raw_mime`
1011
* Added `tracking_options` field to Message model for message tracking settings
1112
* Added `raw_mime` field to Message model for Base64url-encoded message data
1213
* Added TrackingOptions model for message tracking configuration
1314
* Maintained backwards compatibility for existing message functionality
15+
* Added support for `include_hidden_folders` query parameter for listing folders (Microsoft only)
1416

1517
v6.9.0
1618
----------------
@@ -98,7 +100,7 @@ v6.0.0
98100
* **BREAKING CHANGE**: Models no longer inherit from `dict` but instead either are a `dataclass` or inherit from `TypedDict`
99101
* **BREAKING CHANGE**: Renamed the SDK entrypoint from `APIClient` to `Client`
100102
* **REMOVED**: Local Webhook development support is removed due to incompatibility
101-
* Rewrote the majority of SDK to be more intuitive, explicit, and efficient
103+
* Rewritten the majority of SDK to be more intuitive, explicit, and efficient
102104
* Created models for all API resources and endpoints, for all HTTP methods to reduce confusion on which fields are available for each endpoint
103105
* Created error classes for the different API errors as well as SDK-specific errors
104106

examples/folders_demo/README.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Folders Single Level Parameter Example
2+
3+
This example demonstrates how to use the `single_level` query parameter when listing folders to control folder hierarchy traversal for Microsoft accounts.
4+
5+
## Overview
6+
7+
The `single_level` parameter is a Microsoft-only feature that allows you to control whether the folders API returns:
8+
- **`single_level=true`**: Only top-level folders (single-level hierarchy)
9+
- **`single_level=false`**: All folders including nested ones (multi-level hierarchy, default)
10+
11+
This parameter is useful for:
12+
- **Performance optimization**: Reducing response size when you only need top-level folders
13+
- **UI simplification**: Building folder trees incrementally
14+
- **Microsoft-specific behavior**: Taking advantage of Microsoft's folder hierarchy structure
15+
16+
## Prerequisites
17+
18+
- Nylas API key
19+
- Nylas grant ID for a Microsoft account (this parameter only works with Microsoft accounts)
20+
21+
## Setup
22+
23+
1. Install the SDK in development mode:
24+
```bash
25+
cd /path/to/nylas-python
26+
pip install -e .
27+
```
28+
29+
2. Set your environment variables:
30+
```bash
31+
export NYLAS_API_KEY="your_api_key"
32+
export NYLAS_GRANT_ID="your_microsoft_grant_id"
33+
```
34+
35+
## Running the Example
36+
37+
```bash
38+
python examples/folders_demo/folders_single_level_example.py
39+
```
40+
41+
## What the Example Demonstrates
42+
43+
1. **Multi-level folder hierarchy** (default behavior)
44+
2. **Single-level folder hierarchy** using `single_level=true`
45+
3. **Combined parameters** showing how to use `single_level` with other query parameters
46+
4. **Hierarchy comparison** showing the difference in folder counts
47+
48+
## Expected Output
49+
50+
The example will show:
51+
- Folders returned with multi-level hierarchy
52+
- Folders returned with single-level hierarchy only
53+
- Count comparison between the two approaches
54+
- How to combine the parameter with other options like `limit` and `select`
55+
56+
## Use Cases
57+
58+
- **Folder tree UI**: Load top-level folders first, then expand as needed
59+
- **Performance**: Reduce API response size for Microsoft accounts with deep folder structures
60+
- **Microsoft-specific integrations**: Take advantage of Microsoft's native folder organization
61+
62+
## Note
63+
64+
This parameter only works with Microsoft accounts. If you use it with other providers, it will be ignored.
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Nylas SDK Example: Using Single Level Parameter for Folders
4+
5+
This example demonstrates how to use the 'single_level' query parameter when listing folders
6+
to control the folder hierarchy traversal for Microsoft accounts.
7+
8+
Required Environment Variables:
9+
NYLAS_API_KEY: Your Nylas API key
10+
NYLAS_GRANT_ID: Your Nylas grant ID (must be a Microsoft account)
11+
12+
Usage:
13+
First, install the SDK in development mode:
14+
cd /path/to/nylas-python
15+
pip install -e .
16+
17+
Then set environment variables and run:
18+
export NYLAS_API_KEY="your_api_key"
19+
export NYLAS_GRANT_ID="your_microsoft_grant_id"
20+
python examples/folders_demo/folders_single_level_example.py
21+
"""
22+
23+
import os
24+
import sys
25+
import json
26+
from nylas import Client
27+
28+
29+
def get_env_or_exit(var_name: str) -> str:
30+
"""Get an environment variable or exit if not found."""
31+
value = os.getenv(var_name)
32+
if not value:
33+
print(f"Error: {var_name} environment variable is required")
34+
sys.exit(1)
35+
return value
36+
37+
38+
def print_folders(folders: list, title: str) -> None:
39+
"""Pretty print the folders with a title."""
40+
print(f"\n{title}:")
41+
if not folders:
42+
print(" No folders found.")
43+
return
44+
45+
for folder in folders:
46+
# Convert to dict and pretty print relevant fields
47+
folder_dict = folder.to_dict()
48+
print(
49+
f" - {folder_dict.get('name', 'Unknown')} (ID: {folder_dict.get('id', 'Unknown')})"
50+
)
51+
if folder_dict.get("parent_id"):
52+
print(f" Parent ID: {folder_dict['parent_id']}")
53+
if folder_dict.get("child_count") is not None:
54+
print(f" Child Count: {folder_dict['child_count']}")
55+
56+
57+
def demonstrate_multi_level_folders(client: Client, grant_id: str) -> None:
58+
"""Demonstrate multi-level folder hierarchy (default behavior)."""
59+
print("\n=== Multi-Level Folder Hierarchy (Default) ===")
60+
61+
# Default behavior - retrieves folders across multi-level hierarchy
62+
print("\nFetching folders with multi-level hierarchy (single_level=False):")
63+
folders = client.folders.list(
64+
identifier=grant_id, query_params={"single_level": False}
65+
)
66+
print_folders(folders.data, "Multi-level folder hierarchy")
67+
68+
# Also demonstrate without explicitly setting single_level (default behavior)
69+
print("\nFetching folders without single_level parameter (default behavior):")
70+
folders = client.folders.list(identifier=grant_id)
71+
print_folders(folders.data, "Default folder hierarchy (multi-level)")
72+
73+
74+
def demonstrate_single_level_folders(client: Client, grant_id: str) -> None:
75+
"""Demonstrate single-level folder hierarchy."""
76+
print("\n=== Single-Level Folder Hierarchy ===")
77+
78+
# Single-level hierarchy - only retrieves folders from the top level
79+
print("\nFetching folders with single-level hierarchy (single_level=True):")
80+
folders = client.folders.list(
81+
identifier=grant_id, query_params={"single_level": True}
82+
)
83+
print_folders(folders.data, "Single-level folder hierarchy")
84+
85+
86+
def demonstrate_combined_parameters(client: Client, grant_id: str) -> None:
87+
"""Demonstrate single_level combined with other parameters."""
88+
print("\n=== Combined Parameters ===")
89+
90+
# Combine single_level with other query parameters
91+
print("\nFetching limited single-level folders with select fields:")
92+
folders = client.folders.list(
93+
identifier=grant_id,
94+
query_params={
95+
"single_level": True,
96+
"limit": 5,
97+
"select": "id,name,parent_id,child_count",
98+
},
99+
)
100+
print_folders(folders.data, "Limited single-level folders with selected fields")
101+
102+
103+
def compare_hierarchies(client: Client, grant_id: str) -> None:
104+
"""Compare single-level vs multi-level folder counts."""
105+
print("\n=== Hierarchy Comparison ===")
106+
107+
# Get multi-level count
108+
multi_level_folders = client.folders.list(
109+
identifier=grant_id, query_params={"single_level": False}
110+
)
111+
multi_level_count = len(multi_level_folders.data)
112+
113+
# Get single-level count
114+
single_level_folders = client.folders.list(
115+
identifier=grant_id, query_params={"single_level": True}
116+
)
117+
single_level_count = len(single_level_folders.data)
118+
119+
print(f"\nFolder count comparison:")
120+
print(f" Multi-level hierarchy: {multi_level_count} folders")
121+
print(f" Single-level hierarchy: {single_level_count} folders")
122+
123+
if multi_level_count > single_level_count:
124+
print(
125+
f" Difference: {multi_level_count - single_level_count} folders in sub-hierarchies"
126+
)
127+
elif single_level_count == multi_level_count:
128+
print(" No nested folders detected in this account")
129+
130+
131+
def main():
132+
"""Main function demonstrating single_level parameter usage for folders."""
133+
# Get required environment variables
134+
api_key = get_env_or_exit("NYLAS_API_KEY")
135+
grant_id = get_env_or_exit("NYLAS_GRANT_ID")
136+
137+
# Initialize Nylas client
138+
client = Client(api_key=api_key)
139+
140+
print("\nDemonstrating Single Level Parameter for Folders")
141+
print("===============================================")
142+
print("This parameter is Microsoft-only and controls folder hierarchy traversal")
143+
print(f"Using Grant ID: {grant_id}")
144+
145+
try:
146+
# Demonstrate different folder hierarchy options
147+
demonstrate_multi_level_folders(client, grant_id)
148+
demonstrate_single_level_folders(client, grant_id)
149+
demonstrate_combined_parameters(client, grant_id)
150+
compare_hierarchies(client, grant_id)
151+
152+
print("\n=== Summary ===")
153+
print("• single_level=True: Returns only top-level folders (Microsoft only)")
154+
print("• single_level=False: Returns folders from all levels (default)")
155+
print("• This parameter helps optimize performance for Microsoft accounts")
156+
print("• Can be combined with other query parameters like limit and select")
157+
158+
except Exception as e:
159+
print(f"\nError: {e}")
160+
print("\nNote: This example requires a Microsoft grant ID.")
161+
print("The single_level parameter only works with Microsoft accounts.")
162+
163+
print("\nExample completed!")
164+
165+
166+
if __name__ == "__main__":
167+
main()
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Include Hidden Folders Example
2+
3+
This example demonstrates how to use the `include_hidden_folders` query parameter when listing folders with the Nylas Python SDK.
4+
5+
## Overview
6+
7+
The `include_hidden_folders` parameter is Microsoft-specific and allows you to include hidden folders in the folder listing response. By default, this parameter is `False` and hidden folders are not included.
8+
9+
## Prerequisites
10+
11+
1. A Nylas application with Microsoft OAuth configured
12+
2. A valid Nylas API key
13+
3. A grant ID for a Microsoft account
14+
15+
## Setup
16+
17+
1. Set your environment variables:
18+
```bash
19+
export NYLAS_API_KEY="your_api_key_here"
20+
export NYLAS_GRANT_ID="your_grant_id_here"
21+
export NYLAS_API_URI="https://api.us.nylas.com" # Optional, defaults to US
22+
```
23+
24+
2. Install the Nylas Python SDK:
25+
```bash
26+
pip install nylas
27+
```
28+
29+
## Running the Example
30+
31+
```bash
32+
python include_hidden_folders_example.py
33+
```
34+
35+
## Code Explanation
36+
37+
The example demonstrates two scenarios:
38+
39+
1. **Default behavior**: Lists folders without hidden folders
40+
```python
41+
folders_response = nylas.folders.list(
42+
identifier=grant_id,
43+
query_params={"limit": 10}
44+
)
45+
```
46+
47+
2. **With hidden folders**: Lists folders including hidden folders (Microsoft only)
48+
```python
49+
folders_with_hidden_response = nylas.folders.list(
50+
identifier=grant_id,
51+
query_params={
52+
"include_hidden_folders": True,
53+
"limit": 10
54+
}
55+
)
56+
```
57+
58+
## Expected Output
59+
60+
The example will show:
61+
- List of regular folders
62+
- List of folders including hidden ones (if any)
63+
- Comparison showing how many additional hidden folders were found
64+
65+
## Note
66+
67+
This feature is **Microsoft-specific only**. For other providers (Google, IMAP), the `include_hidden_folders` parameter will be ignored.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import os
2+
from nylas import Client
3+
4+
5+
def main():
6+
"""
7+
This example demonstrates how to use the include_hidden_folders parameter
8+
when listing folders with the Nylas SDK.
9+
10+
The include_hidden_folders parameter is Microsoft-specific and when set to True,
11+
it includes hidden folders in the response.
12+
"""
13+
14+
# Initialize the client
15+
nylas = Client(
16+
api_key=os.environ.get("NYLAS_API_KEY"),
17+
api_uri=os.environ.get("NYLAS_API_URI", "https://api.us.nylas.com"),
18+
)
19+
20+
# Get the grant ID from environment variable
21+
grant_id = os.environ.get("NYLAS_GRANT_ID")
22+
23+
if not grant_id:
24+
print("Please set the NYLAS_GRANT_ID environment variable")
25+
return
26+
27+
try:
28+
print("Listing folders without hidden folders (default behavior):")
29+
print("=" * 60)
30+
31+
# List folders without hidden folders (default)
32+
folders_response = nylas.folders.list(
33+
identifier=grant_id, query_params={"limit": 10}
34+
)
35+
36+
for folder in folders_response.data:
37+
print(f"- {folder.name} (ID: {folder.id})")
38+
39+
print(f"\nTotal folders found: {len(folders_response.data)}")
40+
41+
# Now list folders WITH hidden folders (Microsoft only)
42+
print("\n\nListing folders with hidden folders included (Microsoft only):")
43+
print("=" * 70)
44+
45+
folders_with_hidden_response = nylas.folders.list(
46+
identifier=grant_id,
47+
query_params={"include_hidden_folders": True, "limit": 10},
48+
)
49+
50+
for folder in folders_with_hidden_response.data:
51+
print(f"- {folder.name} (ID: {folder.id})")
52+
53+
print(
54+
f"\nTotal folders found (including hidden): {len(folders_with_hidden_response.data)}"
55+
)
56+
57+
# Compare the counts
58+
hidden_count = len(folders_with_hidden_response.data) - len(
59+
folders_response.data
60+
)
61+
if hidden_count > 0:
62+
print(f"\nFound {hidden_count} additional hidden folder(s)")
63+
else:
64+
print("\nNo additional hidden folders found")
65+
66+
except Exception as e:
67+
print(f"Error: {e}")
68+
69+
70+
if __name__ == "__main__":
71+
main()

0 commit comments

Comments
 (0)