Skip to content

Commit 1cd3bca

Browse files
committed
Update CHANGELOG for version 0.1.3; fix typing for nullable model fields in update() methods across multiple resources to allow passing None without type errors.
1 parent 235cc44 commit 1cd3bca

16 files changed

Lines changed: 153 additions & 134 deletions

‎CHANGELOG.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@ All notable changes to this project are documented here. Format follows
77

88
## [Unreleased]
99

10+
## [0.1.3] - 2026-07-23
11+
12+
### Fixed
13+
14+
- `update()` parameters that correspond to nullable (`T | None`) model fields were typed
15+
as `T | NotGiven`, dropping the `None` branch the model itself allows. This didn't
16+
affect runtime behavior (`None` already passed through and serialized as JSON `null`,
17+
correctly clearing the field), but callers who legitimately wanted to clear a nullable
18+
field (e.g. `accounts.update(..., signature=None)`, `campaigns.update(..., daily_limit=None)`)
19+
got a static type error. Corrected across every resource's `update()` (sync and async):
20+
`accounts`, `campaigns`, `custom_tags`, `emails`, `inbox_placement_tests`, `lead_labels`,
21+
`lead_lists`, `leads`, `subsequences`, `webhooks`, `workspace_members`, `workspaces`.
22+
1023
## [0.1.2] - 2026-07-23
1124

1225
### Fixed

‎skills/SKILL.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ Keep retry, auth, serialization, pagination, and error mapping in shared infrast
8585

8686
Use `NOT_GIVEN` for omitted optional arguments. Omit a kwarg to leave a field unchanged. Pass `None` only when the API intentionally distinguishes explicit null from omission.
8787

88+
If the corresponding model field is typed `T | None` (nullable in the read model), the parameter must be typed `T | None | NotGiven`, not just `T | NotGiven` — otherwise callers clearing the field with `None` get a static type error even though it works at runtime.
89+
8890
## Use the Project Tooling
8991

9092
Run local checks before finishing SDK changes:

‎skills/references/development.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ For create/update methods:
4343

4444
1. Prefer keyword-only arguments.
4545
2. Use generated model types for nested request bodies.
46-
3. Default optional omitted fields to `NOT_GIVEN`.
46+
3. Default optional omitted fields to `NOT_GIVEN`. If the field is nullable on the generated model (`T | None`), type the parameter `T | None | NotGiven`, not just `T | NotGiven`, so callers can pass `None` to clear it without a type error.
4747
4. Build a body mapping.
4848
5. Let `_base.py` and `_transport.py` omit `NOT_GIVEN` and serialize models/enums.
4949

‎src/instantlyai/_version.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
build backend (``pyproject.toml`` -> ``[tool.hatch.version]``).
55
"""
66

7-
__version__ = "0.1.2"
7+
__version__ = "0.1.3"

‎src/instantlyai/resources/accounts.py‎

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,15 @@ def update(
9595
*,
9696
first_name: str | NotGiven = NOT_GIVEN,
9797
last_name: str | NotGiven = NOT_GIVEN,
98-
warmup: Warmup | NotGiven = NOT_GIVEN,
99-
daily_limit: float | NotGiven = NOT_GIVEN,
100-
tracking_domain_name: str | NotGiven = NOT_GIVEN,
101-
tracking_domain_status: str | NotGiven = NOT_GIVEN,
102-
enable_slow_ramp: bool | NotGiven = NOT_GIVEN,
103-
inbox_placement_test_limit: float | NotGiven = NOT_GIVEN,
104-
sending_gap: float | NotGiven = NOT_GIVEN,
105-
signature: str | NotGiven = NOT_GIVEN,
106-
reply_to: str | NotGiven = NOT_GIVEN,
98+
warmup: Warmup | None | NotGiven = NOT_GIVEN,
99+
daily_limit: float | None | NotGiven = NOT_GIVEN,
100+
tracking_domain_name: str | None | NotGiven = NOT_GIVEN,
101+
tracking_domain_status: str | None | NotGiven = NOT_GIVEN,
102+
enable_slow_ramp: bool | None | NotGiven = NOT_GIVEN,
103+
inbox_placement_test_limit: float | None | NotGiven = NOT_GIVEN,
104+
sending_gap: float | None | NotGiven = NOT_GIVEN,
105+
signature: str | None | NotGiven = NOT_GIVEN,
106+
reply_to: str | None | NotGiven = NOT_GIVEN,
107107
skip_cname_check: bool | NotGiven = NOT_GIVEN,
108108
remove_tracking_domain: bool | NotGiven = NOT_GIVEN,
109109
) -> Account:
@@ -325,15 +325,15 @@ async def update(
325325
*,
326326
first_name: str | NotGiven = NOT_GIVEN,
327327
last_name: str | NotGiven = NOT_GIVEN,
328-
warmup: Warmup | NotGiven = NOT_GIVEN,
329-
daily_limit: float | NotGiven = NOT_GIVEN,
330-
tracking_domain_name: str | NotGiven = NOT_GIVEN,
331-
tracking_domain_status: str | NotGiven = NOT_GIVEN,
332-
enable_slow_ramp: bool | NotGiven = NOT_GIVEN,
333-
inbox_placement_test_limit: float | NotGiven = NOT_GIVEN,
334-
sending_gap: float | NotGiven = NOT_GIVEN,
335-
signature: str | NotGiven = NOT_GIVEN,
336-
reply_to: str | NotGiven = NOT_GIVEN,
328+
warmup: Warmup | None | NotGiven = NOT_GIVEN,
329+
daily_limit: float | None | NotGiven = NOT_GIVEN,
330+
tracking_domain_name: str | None | NotGiven = NOT_GIVEN,
331+
tracking_domain_status: str | None | NotGiven = NOT_GIVEN,
332+
enable_slow_ramp: bool | None | NotGiven = NOT_GIVEN,
333+
inbox_placement_test_limit: float | None | NotGiven = NOT_GIVEN,
334+
sending_gap: float | None | NotGiven = NOT_GIVEN,
335+
signature: str | None | NotGiven = NOT_GIVEN,
336+
reply_to: str | None | NotGiven = NOT_GIVEN,
337337
skip_cname_check: bool | NotGiven = NOT_GIVEN,
338338
remove_tracking_domain: bool | NotGiven = NOT_GIVEN,
339339
) -> Account:

‎src/instantlyai/resources/campaigns.py‎

Lines changed: 58 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -106,34 +106,36 @@ def update(
106106
id: str,
107107
*,
108108
name: str | NotGiven = NOT_GIVEN,
109-
pl_value: float | NotGiven = NOT_GIVEN,
110-
is_evergreen: bool | NotGiven = NOT_GIVEN,
109+
pl_value: float | None | NotGiven = NOT_GIVEN,
110+
is_evergreen: bool | None | NotGiven = NOT_GIVEN,
111111
campaign_schedule: CampaignSchedule | NotGiven = NOT_GIVEN,
112-
sequences: _list[Sequence] | NotGiven = NOT_GIVEN,
113-
email_gap: float | NotGiven = NOT_GIVEN,
114-
random_wait_max: float | NotGiven = NOT_GIVEN,
115-
text_only: bool | NotGiven = NOT_GIVEN,
116-
first_email_text_only: bool | NotGiven = NOT_GIVEN,
117-
email_list: _list[str] | NotGiven = NOT_GIVEN,
118-
daily_limit: float | NotGiven = NOT_GIVEN,
119-
stop_on_reply: bool | NotGiven = NOT_GIVEN,
120-
email_tag_list: _list[str] | NotGiven = NOT_GIVEN,
121-
link_tracking: bool | NotGiven = NOT_GIVEN,
122-
open_tracking: bool | NotGiven = NOT_GIVEN,
123-
stop_on_auto_reply: bool | NotGiven = NOT_GIVEN,
124-
daily_max_leads: int | NotGiven = NOT_GIVEN,
125-
prioritize_new_leads: bool | NotGiven = NOT_GIVEN,
126-
auto_variant_select: AutoVariantSelect | NotGiven = NOT_GIVEN,
127-
match_lead_esp: bool | NotGiven = NOT_GIVEN,
128-
stop_for_company: bool | NotGiven = NOT_GIVEN,
129-
insert_unsubscribe_header: bool | NotGiven = NOT_GIVEN,
130-
allow_risky_contacts: bool | NotGiven = NOT_GIVEN,
131-
disable_bounce_protect: bool | NotGiven = NOT_GIVEN,
132-
limit_emails_per_company_override: LimitEmailsPerCompanyOverride | NotGiven = NOT_GIVEN,
133-
cc_list: _list[str] | NotGiven = NOT_GIVEN,
134-
bcc_list: _list[str] | NotGiven = NOT_GIVEN,
135-
owned_by: str | NotGiven = NOT_GIVEN,
136-
provider_routing_rules: _list[ProviderRoutingRule] | NotGiven = NOT_GIVEN,
112+
sequences: _list[Sequence] | None | NotGiven = NOT_GIVEN,
113+
email_gap: float | None | NotGiven = NOT_GIVEN,
114+
random_wait_max: float | None | NotGiven = NOT_GIVEN,
115+
text_only: bool | None | NotGiven = NOT_GIVEN,
116+
first_email_text_only: bool | None | NotGiven = NOT_GIVEN,
117+
email_list: _list[str] | None | NotGiven = NOT_GIVEN,
118+
daily_limit: float | None | NotGiven = NOT_GIVEN,
119+
stop_on_reply: bool | None | NotGiven = NOT_GIVEN,
120+
email_tag_list: _list[str] | None | NotGiven = NOT_GIVEN,
121+
link_tracking: bool | None | NotGiven = NOT_GIVEN,
122+
open_tracking: bool | None | NotGiven = NOT_GIVEN,
123+
stop_on_auto_reply: bool | None | NotGiven = NOT_GIVEN,
124+
daily_max_leads: int | None | NotGiven = NOT_GIVEN,
125+
prioritize_new_leads: bool | None | NotGiven = NOT_GIVEN,
126+
auto_variant_select: AutoVariantSelect | None | NotGiven = NOT_GIVEN,
127+
match_lead_esp: bool | None | NotGiven = NOT_GIVEN,
128+
stop_for_company: bool | None | NotGiven = NOT_GIVEN,
129+
insert_unsubscribe_header: bool | None | NotGiven = NOT_GIVEN,
130+
allow_risky_contacts: bool | None | NotGiven = NOT_GIVEN,
131+
disable_bounce_protect: bool | None | NotGiven = NOT_GIVEN,
132+
limit_emails_per_company_override: LimitEmailsPerCompanyOverride
133+
| None
134+
| NotGiven = NOT_GIVEN,
135+
cc_list: _list[str] | None | NotGiven = NOT_GIVEN,
136+
bcc_list: _list[str] | None | NotGiven = NOT_GIVEN,
137+
owned_by: str | None | NotGiven = NOT_GIVEN,
138+
provider_routing_rules: _list[ProviderRoutingRule] | None | NotGiven = NOT_GIVEN,
137139
) -> Campaign:
138140
"""Partially update a campaign. Omitted fields are left unchanged."""
139141
body = {
@@ -419,34 +421,36 @@ async def update(
419421
id: str,
420422
*,
421423
name: str | NotGiven = NOT_GIVEN,
422-
pl_value: float | NotGiven = NOT_GIVEN,
423-
is_evergreen: bool | NotGiven = NOT_GIVEN,
424+
pl_value: float | None | NotGiven = NOT_GIVEN,
425+
is_evergreen: bool | None | NotGiven = NOT_GIVEN,
424426
campaign_schedule: CampaignSchedule | NotGiven = NOT_GIVEN,
425-
sequences: _list[Sequence] | NotGiven = NOT_GIVEN,
426-
email_gap: float | NotGiven = NOT_GIVEN,
427-
random_wait_max: float | NotGiven = NOT_GIVEN,
428-
text_only: bool | NotGiven = NOT_GIVEN,
429-
first_email_text_only: bool | NotGiven = NOT_GIVEN,
430-
email_list: _list[str] | NotGiven = NOT_GIVEN,
431-
daily_limit: float | NotGiven = NOT_GIVEN,
432-
stop_on_reply: bool | NotGiven = NOT_GIVEN,
433-
email_tag_list: _list[str] | NotGiven = NOT_GIVEN,
434-
link_tracking: bool | NotGiven = NOT_GIVEN,
435-
open_tracking: bool | NotGiven = NOT_GIVEN,
436-
stop_on_auto_reply: bool | NotGiven = NOT_GIVEN,
437-
daily_max_leads: int | NotGiven = NOT_GIVEN,
438-
prioritize_new_leads: bool | NotGiven = NOT_GIVEN,
439-
auto_variant_select: AutoVariantSelect | NotGiven = NOT_GIVEN,
440-
match_lead_esp: bool | NotGiven = NOT_GIVEN,
441-
stop_for_company: bool | NotGiven = NOT_GIVEN,
442-
insert_unsubscribe_header: bool | NotGiven = NOT_GIVEN,
443-
allow_risky_contacts: bool | NotGiven = NOT_GIVEN,
444-
disable_bounce_protect: bool | NotGiven = NOT_GIVEN,
445-
limit_emails_per_company_override: LimitEmailsPerCompanyOverride | NotGiven = NOT_GIVEN,
446-
cc_list: _list[str] | NotGiven = NOT_GIVEN,
447-
bcc_list: _list[str] | NotGiven = NOT_GIVEN,
448-
owned_by: str | NotGiven = NOT_GIVEN,
449-
provider_routing_rules: _list[ProviderRoutingRule] | NotGiven = NOT_GIVEN,
427+
sequences: _list[Sequence] | None | NotGiven = NOT_GIVEN,
428+
email_gap: float | None | NotGiven = NOT_GIVEN,
429+
random_wait_max: float | None | NotGiven = NOT_GIVEN,
430+
text_only: bool | None | NotGiven = NOT_GIVEN,
431+
first_email_text_only: bool | None | NotGiven = NOT_GIVEN,
432+
email_list: _list[str] | None | NotGiven = NOT_GIVEN,
433+
daily_limit: float | None | NotGiven = NOT_GIVEN,
434+
stop_on_reply: bool | None | NotGiven = NOT_GIVEN,
435+
email_tag_list: _list[str] | None | NotGiven = NOT_GIVEN,
436+
link_tracking: bool | None | NotGiven = NOT_GIVEN,
437+
open_tracking: bool | None | NotGiven = NOT_GIVEN,
438+
stop_on_auto_reply: bool | None | NotGiven = NOT_GIVEN,
439+
daily_max_leads: int | None | NotGiven = NOT_GIVEN,
440+
prioritize_new_leads: bool | None | NotGiven = NOT_GIVEN,
441+
auto_variant_select: AutoVariantSelect | None | NotGiven = NOT_GIVEN,
442+
match_lead_esp: bool | None | NotGiven = NOT_GIVEN,
443+
stop_for_company: bool | None | NotGiven = NOT_GIVEN,
444+
insert_unsubscribe_header: bool | None | NotGiven = NOT_GIVEN,
445+
allow_risky_contacts: bool | None | NotGiven = NOT_GIVEN,
446+
disable_bounce_protect: bool | None | NotGiven = NOT_GIVEN,
447+
limit_emails_per_company_override: LimitEmailsPerCompanyOverride
448+
| None
449+
| NotGiven = NOT_GIVEN,
450+
cc_list: _list[str] | None | NotGiven = NOT_GIVEN,
451+
bcc_list: _list[str] | None | NotGiven = NOT_GIVEN,
452+
owned_by: str | None | NotGiven = NOT_GIVEN,
453+
provider_routing_rules: _list[ProviderRoutingRule] | None | NotGiven = NOT_GIVEN,
450454
) -> Campaign:
451455
"""Partially update a campaign. Omitted fields are left unchanged."""
452456
body = {

‎src/instantlyai/resources/custom_tags.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def update(
3636
id: str,
3737
*,
3838
label: str | NotGiven = NOT_GIVEN,
39-
description: str | NotGiven = NOT_GIVEN,
39+
description: str | None | NotGiven = NOT_GIVEN,
4040
) -> CustomTag:
4141
"""Patch custom tag."""
4242
return CustomTag.model_validate(
@@ -118,7 +118,7 @@ async def update(
118118
id: str,
119119
*,
120120
label: str | NotGiven = NOT_GIVEN,
121-
description: str | NotGiven = NOT_GIVEN,
121+
description: str | None | NotGiven = NOT_GIVEN,
122122
) -> CustomTag:
123123
"""Patch custom tag."""
124124
return CustomTag.model_validate(

‎src/instantlyai/resources/emails.py‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ def update(
111111
self,
112112
id: str,
113113
*,
114-
is_unread: float | NotGiven = NOT_GIVEN,
115-
reminder_ts: str | NotGiven = NOT_GIVEN,
114+
is_unread: float | None | NotGiven = NOT_GIVEN,
115+
reminder_ts: str | None | NotGiven = NOT_GIVEN,
116116
) -> Email:
117117
"""Patch email."""
118118
return Email.model_validate(
@@ -280,8 +280,8 @@ async def update(
280280
self,
281281
id: str,
282282
*,
283-
is_unread: float | NotGiven = NOT_GIVEN,
284-
reminder_ts: str | NotGiven = NOT_GIVEN,
283+
is_unread: float | None | NotGiven = NOT_GIVEN,
284+
reminder_ts: str | None | NotGiven = NOT_GIVEN,
285285
) -> Email:
286286
"""Patch email."""
287287
return Email.model_validate(

‎src/instantlyai/resources/inbox_placement_tests.py‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ def update(
8686
id: str,
8787
*,
8888
name: str | NotGiven = NOT_GIVEN,
89-
schedule: Schedule1 | NotGiven = NOT_GIVEN,
90-
automations: _list[Automation] | NotGiven = NOT_GIVEN,
91-
status: _TestStatus | NotGiven = NOT_GIVEN,
89+
schedule: Schedule1 | None | NotGiven = NOT_GIVEN,
90+
automations: _list[Automation] | None | NotGiven = NOT_GIVEN,
91+
status: _TestStatus | None | NotGiven = NOT_GIVEN,
9292
) -> InboxPlacementTest:
9393
"""Partially update an inbox placement test. Omitted fields are left unchanged."""
9494
body = {"name": name, "schedule": schedule, "automations": automations, "status": status}
@@ -193,9 +193,9 @@ async def update(
193193
id: str,
194194
*,
195195
name: str | NotGiven = NOT_GIVEN,
196-
schedule: Schedule1 | NotGiven = NOT_GIVEN,
197-
automations: _list[Automation] | NotGiven = NOT_GIVEN,
198-
status: _TestStatus | NotGiven = NOT_GIVEN,
196+
schedule: Schedule1 | None | NotGiven = NOT_GIVEN,
197+
automations: _list[Automation] | None | NotGiven = NOT_GIVEN,
198+
status: _TestStatus | None | NotGiven = NOT_GIVEN,
199199
) -> InboxPlacementTest:
200200
"""Partially update an inbox placement test. Omitted fields are left unchanged."""
201201
body = {"name": name, "schedule": schedule, "automations": automations, "status": status}

‎src/instantlyai/resources/lead_labels.py‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ def update(
5252
*,
5353
label: str | NotGiven = NOT_GIVEN,
5454
interest_status_label: _InterestStatusLabel | NotGiven = NOT_GIVEN,
55-
description: str | NotGiven = NOT_GIVEN,
56-
use_with_ai: bool | NotGiven = NOT_GIVEN,
55+
description: str | None | NotGiven = NOT_GIVEN,
56+
use_with_ai: bool | None | NotGiven = NOT_GIVEN,
5757
) -> LeadLabel:
5858
"""Patch lead label. Omitted fields are left unchanged."""
5959
return LeadLabel.model_validate(
@@ -134,8 +134,8 @@ async def update(
134134
*,
135135
label: str | NotGiven = NOT_GIVEN,
136136
interest_status_label: _InterestStatusLabel | NotGiven = NOT_GIVEN,
137-
description: str | NotGiven = NOT_GIVEN,
138-
use_with_ai: bool | NotGiven = NOT_GIVEN,
137+
description: str | None | NotGiven = NOT_GIVEN,
138+
use_with_ai: bool | None | NotGiven = NOT_GIVEN,
139139
) -> LeadLabel:
140140
"""Patch lead label. Omitted fields are left unchanged."""
141141
return LeadLabel.model_validate(

0 commit comments

Comments
 (0)