feat: add Actor task publication endpoints - #985
Conversation
apify-service-account
commented
Aug 2, 2026
- Updates the auto-generated Pydantic models and TypedDicts based on the proposed OpenAPI specification changes.
- Based on apify-docs PR #2840.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #985 +/- ##
==========================================
+ Coverage 94.71% 94.75% +0.03%
==========================================
Files 58 58
Lines 5337 5374 +37
==========================================
+ Hits 5055 5092 +37
Misses 282 282
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
vdusek
left a comment
There was a problem hiding this comment.
Thanks. Let's merge this once the PRs in apify-core and apify-docs are merged.
|
Please resolve the failing CI |
The models committed earlier came from a superseded revision of the spec PR that used dedicated publish/unpublish endpoints. The current revision puts `isPublic` on the update request instead, which is what the client code and tests were written against. Also merges master and syncs the async create docstring. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6GXQXFZK4XoGwNgXHkk1n
|
|
||
|
|
||
| @docs_group('Models') | ||
| class TaskPublicConfig(BaseModel): |
There was a problem hiding this comment.
These models come from a spec that is not merged and deployed - Let's wait for the merge of apify/apify-docs#2840.
| _TASK_RESPONSE = { | ||
| 'data': { | ||
| 'id': _MOCKED_TASK_ID, | ||
| 'userId': 'test_user_id', | ||
| 'actId': 'test_actor_id', | ||
| 'name': 'test-task', | ||
| 'createdAt': '2026-08-01T10:00:00.000Z', | ||
| 'modifiedAt': '2026-08-01T10:00:00.000Z', | ||
| } | ||
| } |
There was a problem hiding this comment.
Note: the response half of the feature has no coverage. This fixture carries no isPublic and no publicConfig, and none of the 12 tests looks at the returned Task - every assertion inspects the captured request body. So Task.is_public, Task.public_config and TaskPublicConfig deserialization (including published_at: AwareDatetime) ship unexercised, even though publish()'s whole contract is "returns the published task". Adding 'isPublic': True and a publicConfig block here, then asserting on the returned object, costs two lines.
| # Aliased at module scope so that `list` resolves to the builtin - inside the client classes below, | ||
| # a bare `list[str]` annotation would resolve to their own `list` method instead. | ||
| InputSchemaFields = list[str] |
There was a problem hiding this comment.
Could we rather resolve this shadowing problem in the same way as in the rest of the code base (e.g. actor_version_collection.py:86,89,192,195) via an inline # ty: ignore[invalid-type-form] on a bare list[str].
| _client(httpserver).task(_MOCKED_TASK_ID).unpublish() | ||
|
|
||
| assert len(captured) == 1 | ||
| # `False` must survive rather than being dropped as falsy - it is what unpublishes the task. |
There was a problem hiding this comment.
Nit: nothing in the payload path drops falsy values - model_dump(..., exclude_none=True) (task.py:168) drops only None, and _clean_json_payload (_resource_client.py:151-181) drops only None and empty dicts. The invariant is worth stating, but state the real one.
| # `False` must survive rather than being dropped as falsy - it is what unpublishes the task. | |
| # `False` must survive `exclude_none` - it is what unpublishes the task. |
| assert len(captured) == 1 | ||
| body = _body_of(captured[0]) | ||
| assert body['publicConfig'] == {'seoTitle': 'Scrape a website'} | ||
| # Publication is never part of a create - it only happens through the update. |
There was a problem hiding this comment.
Nit: this comment restates the assert directly below it - worth dropping.
| """Create a new task. | ||
|
|
||
| The `public_config_*` arguments set the public display configuration of the task's landing page, which | ||
| requires write access to the task's Actor and the Task itself. Use `TaskClient.publish` for publishing. |
There was a problem hiding this comment.
Nit: "Task" is capitalized as if it were an Apify proper noun - only "Actor" is. The same sentence already uses lowercase "task's".
| requires write access to the task's Actor and the Task itself. Use `TaskClient.publish` for publishing. | |
| requires write access to the task's Actor and the task itself. Use `TaskClient.publish` for publishing. |
| """Create a new task. | ||
|
|
||
| The `public_config_*` arguments set the public display configuration of the task's landing page, which | ||
| requires write access to the task's Actor and the Task itself. Use `TaskClientAsync.publish` for publishing. |
There was a problem hiding this comment.
Nit: same capitalization as in the sync twin - only "Actor" is an Apify proper noun.
| requires write access to the task's Actor and the Task itself. Use `TaskClientAsync.publish` for publishing. | |
| requires write access to the task's Actor and the task itself. Use `TaskClientAsync.publish` for publishing. |
| return ApifyClientAsync(token='test_token', api_url=httpserver.url_for('/').removesuffix('/')) | ||
|
|
||
|
|
||
| def test_publish_sets_is_public_true(httpserver: HTTPServer) -> None: |
There was a problem hiding this comment.
Nit: only test_update_sends_only_the_requested_fields has a docstring, 1 of 12. A one-line docstring per test is the convention worth following here. (The one that does exist is a good one and earns its four lines.)
| } | ||
|
|
||
|
|
||
| def test_update_can_configure_and_publish_at_once(httpserver: HTTPServer) -> None: |
There was a problem hiding this comment.
Nit: this test and test_create_sends_only_the_requested_fields (line 138) have no _async twin, while the other five pairs are mirrored - odd in a repo whose central design rule is sync/async parity.
| def _client(httpserver: HTTPServer) -> ApifyClient: | ||
| return ApifyClient(token='test_token', api_url=httpserver.url_for('/').removesuffix('/')) | ||
|
|
||
|
|
||
| def _async_client(httpserver: HTTPServer) -> ApifyClientAsync: | ||
| return ApifyClientAsync(token='test_token', api_url=httpserver.url_for('/').removesuffix('/')) |
There was a problem hiding this comment.
Nit: test_client_errors.py:87-95 already offers these as sync_client / async_client pytest fixtures. This is the second copy of the token=..., api_url=httpserver.url_for('/').removesuffix('/') incantation; a third would justify moving it to tests/unit/conftest.py.