Skip to content

Commit d989d65

Browse files
authored
feat: Add server_tenancy parameter to Actor create and update (#1169)
1 parent 022041c commit d989d65

8 files changed

Lines changed: 82 additions & 41 deletions

File tree

‎pyproject.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ indent-style = "space"
168168
"TC003", # Move standard library import into a type-checking block
169169
]
170170
"src/apify_client/_literals.py" = [
171+
"E501", # Line too long
171172
"PYI051", # `Literal[...]` is redundant in a union with `str`; the open `Literal[...] | str` is deliberate — it keeps known members as hints while tolerating unknown API values (see scripts/postprocess_generated_models.py)
172173
]
173174

‎scripts/postprocess_generated_models.py‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,11 @@ def fix_discriminators(content: str) -> str:
114114

115115

116116
def convert_enums_to_literals(content: str) -> str:
117-
"""Rewrite every `class X(StrEnum): ...` into an open literal `X = Literal[...] | str` alias.
117+
"""Rewrite every `class X(StrEnum): ...` (or `Enum`) into an open literal `X = Literal[...] | str` alias.
118118
119119
Each member assignment (`NAME = 'value'`) contributes its string value to the literal in
120-
declaration order. The trailing `| str` widens the alias so unknown values (e.g. a new enum
120+
declaration order; a `None` member of a nullable enum is dropped, since the fields using it are already
121+
`X | None`. The trailing `| str` widens the alias so unknown values (e.g. a new enum
121122
member the platform introduces before this client is regenerated) still validate against the
122123
Pydantic models, while the known members remain as autocomplete hints. The class docstring, if
123124
present, is preserved as a trailing bare-string docstring after the alias — matching the
@@ -134,7 +135,7 @@ def convert_enums_to_literals(content: str) -> str:
134135
if not isinstance(node, ast.ClassDef):
135136
continue
136137
base_names = _base_names(node)
137-
if 'StrEnum' not in base_names:
138+
if 'StrEnum' not in base_names and 'Enum' not in base_names:
138139
continue
139140

140141
values: list[str] = [
@@ -148,9 +149,12 @@ def convert_enums_to_literals(content: str) -> str:
148149
]
149150
docstring = ast.get_docstring(node)
150151

151-
new_lines: list[str] = [f'{node.name} = Literal[']
152-
new_lines.extend(f' {v!r},' for v in values)
153-
new_lines.append('] | str')
152+
if len(values) == 1:
153+
new_lines: list[str] = [f'{node.name} = Literal[{values[0]!r}] | str']
154+
else:
155+
new_lines = [f'{node.name} = Literal[']
156+
new_lines.extend(f' {v!r},' for v in values)
157+
new_lines.append('] | str')
154158
if docstring is not None:
155159
if '\n' in docstring:
156160
new_lines.append('"""')

‎src/apify_client/_literals.py‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@
2020
"""Status of an Actor job (run or build)."""
2121

2222

23+
ActorNotice = (
24+
Literal[
25+
'NONE',
26+
'RESIDENTIAL_PROXY_REQUIRED',
27+
'UNDER_MAINTENANCE',
28+
]
29+
| str
30+
)
31+
"""A warning displayed on the Actor's page in Apify Store and Console. Can be set by the Actor's developer or automatically by Apify's quality checks."""
32+
33+
2334
ActorPermissionLevel = (
2435
Literal[
2536
'LIMITED_PERMISSIONS',
@@ -495,6 +506,10 @@
495506
)
496507

497508

509+
MonitoringLevel = Literal['STANDARD'] | str
510+
"""Level of monitoring services included in the plan. `null` or missing means the plan includes no monitoring service."""
511+
512+
498513
OAuthProviderType = (
499514
Literal[
500515
'CUSTOM',
@@ -550,6 +565,16 @@
550565
)
551566

552567

568+
Tenancy = (
569+
Literal[
570+
'SINGLE_TENANT',
571+
'MULTI_TENANT',
572+
]
573+
| str
574+
)
575+
"""Whether each user gets their own standby runs (`SINGLE_TENANT`) or runs are shared across users (`MULTI_TENANT`)."""
576+
577+
553578
VersionSourceType = (
554579
Literal[
555580
'SOURCE_FILES',

‎src/apify_client/_models.py‎

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

33
from __future__ import annotations
44

5-
from enum import Enum
65
from typing import Annotated, Any, Literal
76

87
from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict, EmailStr, Field, RootModel
@@ -11,16 +10,19 @@
1110
from apify_client._docs import docs_group
1211
from apify_client._literals import (
1312
ActorJobStatus,
13+
ActorNotice,
1414
ActorPermissionLevel,
1515
Deployment,
1616
Encoding,
1717
ErrorType,
1818
GeneralAccess,
1919
HttpMethod,
20+
MonitoringLevel,
2021
OAuthProviderType,
2122
Provider,
2223
RunOrigin,
2324
SourceCodeFileFormat,
25+
Tenancy,
2426
VersionSourceType,
2527
WebhookDispatchStatus,
2628
WebhookEventType,
@@ -250,16 +252,6 @@ class ActorListItem(BaseModel):
250252
stats: ActorStats | None = None
251253

252254

253-
@docs_group('Models')
254-
class ActorNotice(Enum):
255-
"""A warning displayed on the Actor's page in Apify Store and Console. Can be set by the Actor's developer or automatically by Apify's quality checks."""
256-
257-
NONE = 'NONE'
258-
RESIDENTIAL_PROXY_REQUIRED = 'RESIDENTIAL_PROXY_REQUIRED'
259-
UNDER_MAINTENANCE = 'UNDER_MAINTENANCE'
260-
NONE_TYPE_NONE = None
261-
262-
263255
@docs_group('Models')
264256
class ActorOAuthAccount(BaseModel):
265257
"""An account a user connected through an Actor OAuth connection."""
@@ -2511,14 +2503,6 @@ class LockedRequestQueueHeadResponse(BaseModel):
25112503
data: LockedRequestQueueHead
25122504

25132505

2514-
@docs_group('Models')
2515-
class MonitoringLevel(Enum):
2516-
"""Level of monitoring services included in the plan. `null` or missing means the plan includes no monitoring service."""
2517-
2518-
STANDARD = 'STANDARD'
2519-
NONE_TYPE_NONE = None
2520-
2521-
25222506
@docs_group('Models')
25232507
class MonthlyUsage(BaseModel):
25242508
model_config = ConfigDict(
@@ -4417,15 +4401,6 @@ class TaskStats(BaseModel):
44174401
"""
44184402

44194403

4420-
@docs_group('Models')
4421-
class Tenancy(Enum):
4422-
"""Whether each user gets their own standby runs (`SINGLE_TENANT`) or runs are shared across users (`MULTI_TENANT`)."""
4423-
4424-
SINGLE_TENANT = 'SINGLE_TENANT'
4425-
MULTI_TENANT = 'MULTI_TENANT'
4426-
NONE_TYPE_NONE = None
4427-
4428-
44294404
@docs_group('Models')
44304405
class TieredPricing(BaseModel):
44314406
model_config = ConfigDict(

‎src/apify_client/_resource_clients/actor.py‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
from decimal import Decimal
3939
from logging import Logger
4040

41-
from apify_client._literals import ActorJobStatus, ActorPermissionLevel, RunOrigin
41+
from apify_client._literals import ActorJobStatus, ActorPermissionLevel, RunOrigin, Tenancy
4242
from apify_client._resource_clients import (
4343
ActorServerClient,
4444
ActorServerClientAsync,
@@ -134,6 +134,7 @@ def update(
134134
server_memory_mbytes: int | None = None,
135135
server_disable_fields_override: bool | None = None,
136136
server_should_pass_actor_input: bool | None = None,
137+
server_tenancy: Tenancy | None = None,
137138
pricing_infos: list[dict[str, Any]] | None = None,
138139
actor_permission_level: ActorPermissionLevel | None = None,
139140
tagged_builds: dict[str, dict[str, str] | None] | None = None,
@@ -146,6 +147,7 @@ def update(
146147
actor_standby_memory_mbytes: int | None = None,
147148
actor_standby_disable_standby_fields_override: bool | None = None,
148149
actor_standby_should_pass_actor_input: bool | None = None,
150+
actor_standby_tenancy: Tenancy | None = None,
149151
) -> ActorResource:
150152
"""Update the Actor with the specified fields.
151153
@@ -186,6 +188,8 @@ def update(
186188
elsewhere.
187189
server_should_pass_actor_input: Whether to pass the Actor input to the runs of the Server Actor. If false,
188190
they start with no input.
191+
server_tenancy: Whether each user gets their own runs of the Server Actor (`SINGLE_TENANT`) or the runs are
192+
shared across users (`MULTI_TENANT`). `MULTI_TENANT` requires pay-per-event pricing.
189193
pricing_infos: A list of objects that describes the pricing of the Actor.
190194
actor_permission_level: The permission level of the Actor on Apify platform.
191195
tagged_builds: A dictionary mapping build tag names to their settings. Use it to create, update,
@@ -204,6 +208,7 @@ def update(
204208
removed in v4.
205209
actor_standby_should_pass_actor_input: Deprecated alias of `server_should_pass_actor_input`. Will be removed
206210
in v4.
211+
actor_standby_tenancy: Deprecated alias of `server_tenancy`. Will be removed in v4.
207212
208213
Returns:
209214
The updated Actor.
@@ -238,6 +243,7 @@ def update(
238243
'server_memory_mbytes': server_memory_mbytes,
239244
'server_disable_fields_override': server_disable_fields_override,
240245
'server_should_pass_actor_input': server_should_pass_actor_input,
246+
'server_tenancy': server_tenancy,
241247
},
242248
{
243249
'actor_standby_is_enabled': actor_standby_is_enabled,
@@ -248,6 +254,7 @@ def update(
248254
'actor_standby_memory_mbytes': actor_standby_memory_mbytes,
249255
'actor_standby_disable_standby_fields_override': actor_standby_disable_standby_fields_override,
250256
'actor_standby_should_pass_actor_input': actor_standby_should_pass_actor_input,
257+
'actor_standby_tenancy': actor_standby_tenancy,
251258
},
252259
),
253260
example_run_input=ExampleRunInput(
@@ -768,6 +775,7 @@ async def update(
768775
server_memory_mbytes: int | None = None,
769776
server_disable_fields_override: bool | None = None,
770777
server_should_pass_actor_input: bool | None = None,
778+
server_tenancy: Tenancy | None = None,
771779
pricing_infos: list[dict[str, Any]] | None = None,
772780
actor_permission_level: ActorPermissionLevel | None = None,
773781
tagged_builds: dict[str, dict[str, str] | None] | None = None,
@@ -780,6 +788,7 @@ async def update(
780788
actor_standby_memory_mbytes: int | None = None,
781789
actor_standby_disable_standby_fields_override: bool | None = None,
782790
actor_standby_should_pass_actor_input: bool | None = None,
791+
actor_standby_tenancy: Tenancy | None = None,
783792
) -> ActorResource:
784793
"""Update the Actor with the specified fields.
785794
@@ -820,6 +829,8 @@ async def update(
820829
elsewhere.
821830
server_should_pass_actor_input: Whether to pass the Actor input to the runs of the Server Actor. If false,
822831
they start with no input.
832+
server_tenancy: Whether each user gets their own runs of the Server Actor (`SINGLE_TENANT`) or the runs are
833+
shared across users (`MULTI_TENANT`). `MULTI_TENANT` requires pay-per-event pricing.
823834
pricing_infos: A list of objects that describes the pricing of the Actor.
824835
actor_permission_level: The permission level of the Actor on Apify platform.
825836
tagged_builds: A dictionary mapping build tag names to their settings. Use it to create, update,
@@ -838,6 +849,7 @@ async def update(
838849
removed in v4.
839850
actor_standby_should_pass_actor_input: Deprecated alias of `server_should_pass_actor_input`. Will be removed
840851
in v4.
852+
actor_standby_tenancy: Deprecated alias of `server_tenancy`. Will be removed in v4.
841853
842854
Returns:
843855
The updated Actor.
@@ -872,6 +884,7 @@ async def update(
872884
'server_memory_mbytes': server_memory_mbytes,
873885
'server_disable_fields_override': server_disable_fields_override,
874886
'server_should_pass_actor_input': server_should_pass_actor_input,
887+
'server_tenancy': server_tenancy,
875888
},
876889
{
877890
'actor_standby_is_enabled': actor_standby_is_enabled,
@@ -882,6 +895,7 @@ async def update(
882895
'actor_standby_memory_mbytes': actor_standby_memory_mbytes,
883896
'actor_standby_disable_standby_fields_override': actor_standby_disable_standby_fields_override,
884897
'actor_standby_should_pass_actor_input': actor_standby_should_pass_actor_input,
898+
'actor_standby_tenancy': actor_standby_tenancy,
885899
},
886900
),
887901
example_run_input=ExampleRunInput(

‎src/apify_client/_resource_clients/actor_collection.py‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from collections.abc import AsyncIterator, Iterator
2222
from datetime import timedelta
2323

24-
from apify_client._literals import ActorPermissionLevel
24+
from apify_client._literals import ActorPermissionLevel, Tenancy
2525
from apify_client._models import ActorListItem
2626
from apify_client.types import Timeout
2727

@@ -137,6 +137,7 @@ def create(
137137
server_memory_mbytes: int | None = None,
138138
server_disable_fields_override: bool | None = None,
139139
server_should_pass_actor_input: bool | None = None,
140+
server_tenancy: Tenancy | None = None,
140141
actor_permission_level: ActorPermissionLevel | None = None,
141142
timeout: Timeout = 'medium',
142143
actor_standby_is_enabled: bool | None = None,
@@ -147,6 +148,7 @@ def create(
147148
actor_standby_memory_mbytes: int | None = None,
148149
actor_standby_disable_standby_fields_override: bool | None = None,
149150
actor_standby_should_pass_actor_input: bool | None = None,
151+
actor_standby_tenancy: Tenancy | None = None,
150152
) -> ActorResource:
151153
"""Create a new Actor.
152154
@@ -187,6 +189,8 @@ def create(
187189
elsewhere.
188190
server_should_pass_actor_input: Whether to pass the Actor input to the runs of the Server Actor. If false,
189191
they start with no input.
192+
server_tenancy: Whether each user gets their own runs of the Server Actor (`SINGLE_TENANT`) or the runs are
193+
shared across users (`MULTI_TENANT`). `MULTI_TENANT` requires pay-per-event pricing.
190194
actor_permission_level: The permission level of the Actor on Apify platform.
191195
timeout: Timeout for the API HTTP request.
192196
actor_standby_is_enabled: Deprecated alias of `server_is_enabled`. Will be removed in v4.
@@ -201,6 +205,7 @@ def create(
201205
removed in v4.
202206
actor_standby_should_pass_actor_input: Deprecated alias of `server_should_pass_actor_input`. Will be removed
203207
in v4.
208+
actor_standby_tenancy: Deprecated alias of `server_tenancy`. Will be removed in v4.
204209
205210
Returns:
206211
The created Actor.
@@ -234,6 +239,7 @@ def create(
234239
'server_memory_mbytes': server_memory_mbytes,
235240
'server_disable_fields_override': server_disable_fields_override,
236241
'server_should_pass_actor_input': server_should_pass_actor_input,
242+
'server_tenancy': server_tenancy,
237243
},
238244
{
239245
'actor_standby_is_enabled': actor_standby_is_enabled,
@@ -244,6 +250,7 @@ def create(
244250
'actor_standby_memory_mbytes': actor_standby_memory_mbytes,
245251
'actor_standby_disable_standby_fields_override': actor_standby_disable_standby_fields_override,
246252
'actor_standby_should_pass_actor_input': actor_standby_should_pass_actor_input,
253+
'actor_standby_tenancy': actor_standby_tenancy,
247254
},
248255
),
249256
example_run_input=ExampleRunInput(
@@ -366,6 +373,7 @@ async def create(
366373
server_memory_mbytes: int | None = None,
367374
server_disable_fields_override: bool | None = None,
368375
server_should_pass_actor_input: bool | None = None,
376+
server_tenancy: Tenancy | None = None,
369377
actor_permission_level: ActorPermissionLevel | None = None,
370378
timeout: Timeout = 'medium',
371379
actor_standby_is_enabled: bool | None = None,
@@ -376,6 +384,7 @@ async def create(
376384
actor_standby_memory_mbytes: int | None = None,
377385
actor_standby_disable_standby_fields_override: bool | None = None,
378386
actor_standby_should_pass_actor_input: bool | None = None,
387+
actor_standby_tenancy: Tenancy | None = None,
379388
) -> ActorResource:
380389
"""Create a new Actor.
381390
@@ -416,6 +425,8 @@ async def create(
416425
elsewhere.
417426
server_should_pass_actor_input: Whether to pass the Actor input to the runs of the Server Actor. If false,
418427
they start with no input.
428+
server_tenancy: Whether each user gets their own runs of the Server Actor (`SINGLE_TENANT`) or the runs are
429+
shared across users (`MULTI_TENANT`). `MULTI_TENANT` requires pay-per-event pricing.
419430
actor_permission_level: The permission level of the Actor on Apify platform.
420431
timeout: Timeout for the API HTTP request.
421432
actor_standby_is_enabled: Deprecated alias of `server_is_enabled`. Will be removed in v4.
@@ -430,6 +441,7 @@ async def create(
430441
removed in v4.
431442
actor_standby_should_pass_actor_input: Deprecated alias of `server_should_pass_actor_input`. Will be removed
432443
in v4.
444+
actor_standby_tenancy: Deprecated alias of `server_tenancy`. Will be removed in v4.
433445
434446
Returns:
435447
The created Actor.
@@ -463,6 +475,7 @@ async def create(
463475
'server_memory_mbytes': server_memory_mbytes,
464476
'server_disable_fields_override': server_disable_fields_override,
465477
'server_should_pass_actor_input': server_should_pass_actor_input,
478+
'server_tenancy': server_tenancy,
466479
},
467480
{
468481
'actor_standby_is_enabled': actor_standby_is_enabled,
@@ -473,6 +486,7 @@ async def create(
473486
'actor_standby_memory_mbytes': actor_standby_memory_mbytes,
474487
'actor_standby_disable_standby_fields_override': actor_standby_disable_standby_fields_override,
475488
'actor_standby_should_pass_actor_input': actor_standby_should_pass_actor_input,
489+
'actor_standby_tenancy': actor_standby_tenancy,
476490
},
477491
),
478492
example_run_input=ExampleRunInput(

‎src/apify_client/_utils/server_args.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
'actor_standby_memory_mbytes': 'server_memory_mbytes',
1616
'actor_standby_disable_standby_fields_override': 'server_disable_fields_override',
1717
'actor_standby_should_pass_actor_input': 'server_should_pass_actor_input',
18+
'actor_standby_tenancy': 'server_tenancy',
1819
}
1920
"""Deprecated `actor_standby_*` arguments, named after Actor Standby (the former name of Server Actors), mapped to the
2021
`server_*` arguments that replace them."""
@@ -57,4 +58,5 @@ def build_actor_standby(server_args: dict[str, Any], deprecated_args: dict[str,
5758
memory_mbytes=args.get('server_memory_mbytes'),
5859
disable_standby_fields_override=args.get('server_disable_fields_override'),
5960
should_pass_actor_input=args.get('server_should_pass_actor_input'),
61+
tenancy=args.get('server_tenancy'),
6062
)

0 commit comments

Comments
 (0)