linkedapi 1.3.5__tar.gz → 1.3.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. {linkedapi-1.3.5 → linkedapi-1.3.6}/PKG-INFO +1 -1
  2. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/__init__.py +1 -1
  3. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/core/operation.py +1 -0
  4. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/errors.py +4 -0
  5. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/__init__.py +2 -0
  6. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/workflow.py +5 -0
  7. {linkedapi-1.3.5 → linkedapi-1.3.6}/pyproject.toml +1 -1
  8. {linkedapi-1.3.5 → linkedapi-1.3.6}/tests/test_errors.py +2 -0
  9. linkedapi-1.3.6/tests/test_working_hours_contract.py +108 -0
  10. {linkedapi-1.3.5 → linkedapi-1.3.6}/.github/workflows/publish.yaml +0 -0
  11. {linkedapi-1.3.5 → linkedapi-1.3.6}/.gitignore +0 -0
  12. {linkedapi-1.3.5 → linkedapi-1.3.6}/LICENSE +0 -0
  13. {linkedapi-1.3.5 → linkedapi-1.3.6}/README.md +0 -0
  14. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/admin/__init__.py +0 -0
  15. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/admin/accounts.py +0 -0
  16. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/admin/admin.py +0 -0
  17. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/admin/http_client.py +0 -0
  18. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/admin/limits.py +0 -0
  19. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/admin/subscription.py +0 -0
  20. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/admin/webhooks.py +0 -0
  21. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/client.py +0 -0
  22. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/config.py +0 -0
  23. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/core/__init__.py +0 -0
  24. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/core/polling.py +0 -0
  25. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/http/__init__.py +0 -0
  26. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/http/base.py +0 -0
  27. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/http/linked_api_http_client.py +0 -0
  28. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/mappers/__init__.py +0 -0
  29. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/mappers/array.py +0 -0
  30. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/mappers/base.py +0 -0
  31. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/mappers/send_message.py +0 -0
  32. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/mappers/simple.py +0 -0
  33. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/mappers/then.py +0 -0
  34. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/mappers/void.py +0 -0
  35. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/__init__.py +0 -0
  36. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/accept_invitation.py +0 -0
  37. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/check_connection_status.py +0 -0
  38. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/comment_on_post.py +0 -0
  39. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/create_post.py +0 -0
  40. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/custom_workflow.py +0 -0
  41. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/fetch_company.py +0 -0
  42. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/fetch_job.py +0 -0
  43. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/fetch_person.py +0 -0
  44. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/fetch_post.py +0 -0
  45. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/ignore_invitation.py +0 -0
  46. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/manage_conversation.py +0 -0
  47. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/nv_fetch_company.py +0 -0
  48. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/nv_fetch_person.py +0 -0
  49. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/nv_manage_conversation.py +0 -0
  50. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/nv_search_companies.py +0 -0
  51. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/nv_search_people.py +0 -0
  52. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/nv_send_message.py +0 -0
  53. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/nv_sync_conversation.py +0 -0
  54. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/nv_sync_inbox.py +0 -0
  55. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/react_to_comment.py +0 -0
  56. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/react_to_post.py +0 -0
  57. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/remove_connection.py +0 -0
  58. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/reply_to_comment.py +0 -0
  59. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/retrieve_connections.py +0 -0
  60. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/retrieve_feed.py +0 -0
  61. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/retrieve_invitations.py +0 -0
  62. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/retrieve_pending_requests.py +0 -0
  63. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/retrieve_performance.py +0 -0
  64. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/retrieve_ssi.py +0 -0
  65. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/search_companies.py +0 -0
  66. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/search_jobs.py +0 -0
  67. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/search_people.py +0 -0
  68. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/send_connection_request.py +0 -0
  69. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/send_message.py +0 -0
  70. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/sync_conversation.py +0 -0
  71. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/sync_inbox.py +0 -0
  72. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/sync_network.py +0 -0
  73. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/operations/withdraw_connection_request.py +0 -0
  74. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/py.typed +0 -0
  75. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/account.py +0 -0
  76. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/admin/__init__.py +0 -0
  77. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/admin/accounts.py +0 -0
  78. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/admin/config.py +0 -0
  79. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/admin/limits.py +0 -0
  80. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/admin/subscription.py +0 -0
  81. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/base.py +0 -0
  82. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/company.py +0 -0
  83. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/connection.py +0 -0
  84. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/feed.py +0 -0
  85. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/jobs.py +0 -0
  86. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/message.py +0 -0
  87. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/network.py +0 -0
  88. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/params.py +0 -0
  89. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/person.py +0 -0
  90. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/post.py +0 -0
  91. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/responses.py +0 -0
  92. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/search_companies.py +0 -0
  93. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/search_people.py +0 -0
  94. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/statistics.py +0 -0
  95. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/types/webhooks.py +0 -0
  96. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/webhooks/__init__.py +0 -0
  97. {linkedapi-1.3.5 → linkedapi-1.3.6}/linkedapi/webhooks/parse.py +0 -0
  98. {linkedapi-1.3.5 → linkedapi-1.3.6}/tests/conftest.py +0 -0
  99. {linkedapi-1.3.5 → linkedapi-1.3.6}/tests/test_admin.py +0 -0
  100. {linkedapi-1.3.5 → linkedapi-1.3.6}/tests/test_direct_methods.py +0 -0
  101. {linkedapi-1.3.5 → linkedapi-1.3.6}/tests/test_http_client.py +0 -0
  102. {linkedapi-1.3.5 → linkedapi-1.3.6}/tests/test_mappers.py +0 -0
  103. {linkedapi-1.3.5 → linkedapi-1.3.6}/tests/test_models.py +0 -0
  104. {linkedapi-1.3.5 → linkedapi-1.3.6}/tests/test_operations.py +0 -0
  105. {linkedapi-1.3.5 → linkedapi-1.3.6}/tests/test_polling.py +0 -0
  106. {linkedapi-1.3.5 → linkedapi-1.3.6}/tests/test_webhooks.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: linkedapi
3
- Version: 1.3.5
3
+ Version: 1.3.6
4
4
  Summary: Official synchronous Python SDK for Linked API.
5
5
  Project-URL: Homepage, https://linkedapi.io
6
6
  Project-URL: Repository, https://github.com/Linked-API/linkedapi-python
@@ -78,7 +78,7 @@ from linkedapi.types import * # noqa: F403
78
78
  from linkedapi.types import __all__ as _types_all
79
79
  from linkedapi.webhooks import parse_webhook_event
80
80
 
81
- __version__ = "1.3.5"
81
+ __version__ = "1.3.6"
82
82
  PredefinedOperation = Operation
83
83
 
84
84
  __all__ = [
@@ -60,6 +60,7 @@ class Operation(ABC, Generic[TParams, TResult]):
60
60
  workflow_id=workflow_id,
61
61
  workflow_status=workflow_result.workflow_status,
62
62
  message=workflow_result.message,
63
+ pending_reason=workflow_result.pending_reason,
63
64
  )
64
65
 
65
66
  completion = self._get_completion(workflow_result)
@@ -66,6 +66,8 @@ LinkedApiErrorType = Literal[
66
66
  "linkedinAccountSignedOut",
67
67
  "languageNotSupported",
68
68
  "workflowTimeout",
69
+ "outsideWorkingHours",
70
+ "workingHoursWaitExpired",
69
71
  "httpError",
70
72
  "tooManyRequests",
71
73
  "accountNotFound",
@@ -87,6 +89,8 @@ LINKED_API_ERROR_TYPES: tuple[str, ...] = (
87
89
  "linkedinAccountSignedOut",
88
90
  "languageNotSupported",
89
91
  "workflowTimeout",
92
+ "outsideWorkingHours",
93
+ "workingHoursWaitExpired",
90
94
  "httpError",
91
95
  "tooManyRequests",
92
96
  "accountNotFound",
@@ -235,6 +235,7 @@ from linkedapi.types.workflow import (
235
235
  WorkflowFailure,
236
236
  WorkflowInProgressResponse,
237
237
  WorkflowInProgressStatus,
238
+ WorkflowPendingReason,
238
239
  WorkflowResponse,
239
240
  WorkflowStartedResponse,
240
241
  WorkflowStatus,
@@ -448,6 +449,7 @@ __all__ = [
448
449
  "WorkflowFailure",
449
450
  "WorkflowInProgressResponse",
450
451
  "WorkflowInProgressStatus",
452
+ "WorkflowPendingReason",
451
453
  "WorkflowResponse",
452
454
  "WorkflowStartedResponse",
453
455
  "WorkflowStatus",
@@ -9,6 +9,7 @@ WorkflowPendingStatus = Literal["pending"]
9
9
  WorkflowRunningStatus = Literal["running"]
10
10
  WorkflowInProgressStatus = Literal["pending", "running"]
11
11
  WorkflowStatus = Literal["pending", "running", "completed", "failed"]
12
+ WorkflowPendingReason = Literal["queued", "outsideWorkingHours"]
12
13
  WorkflowDefinition = dict[str, Any] | list[dict[str, Any]]
13
14
  WorkflowCompletion = dict[str, Any] | list[dict[str, Any]]
14
15
 
@@ -22,12 +23,15 @@ class WorkflowStartedResponse(LinkedApiModel):
22
23
  workflow_id: str
23
24
  workflow_status: WorkflowInProgressStatus
24
25
  message: str | None = None
26
+ # Optional so an older API that does not send it still parses.
27
+ pending_reason: WorkflowPendingReason | None = None
25
28
 
26
29
 
27
30
  class WorkflowInProgressResponse(LinkedApiModel):
28
31
  workflow_id: str
29
32
  workflow_status: WorkflowInProgressStatus
30
33
  message: str | None = None
34
+ pending_reason: WorkflowPendingReason | None = None
31
35
 
32
36
 
33
37
  class WorkflowFailure(LinkedApiModel):
@@ -43,6 +47,7 @@ class WorkflowResponse(LinkedApiModel):
43
47
  workflow_id: str
44
48
  workflow_status: WorkflowStatus
45
49
  message: str | None = None
50
+ pending_reason: WorkflowPendingReason | None = None
46
51
  completion: WorkflowCompletion | None = None
47
52
  failure: WorkflowFailure | None = None
48
53
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "linkedapi"
7
- version = "1.3.5"
7
+ version = "1.3.6"
8
8
  description = "Official synchronous Python SDK for Linked API."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -21,6 +21,8 @@ def test_error_type_sets_match_node_contract() -> None:
21
21
  "linkedinAccountSignedOut",
22
22
  "languageNotSupported",
23
23
  "workflowTimeout",
24
+ "outsideWorkingHours",
25
+ "workingHoursWaitExpired",
24
26
  "httpError",
25
27
  "tooManyRequests",
26
28
  "accountNotFound",
@@ -0,0 +1,108 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+ from unittest.mock import Mock
5
+
6
+ import pytest
7
+
8
+ from linkedapi.core.operation import Operation
9
+ from linkedapi.errors import LINKED_API_ERROR_TYPES
10
+ from linkedapi.types import (
11
+ WorkflowInProgressResponse,
12
+ WorkflowResponse,
13
+ WorkflowStartedResponse,
14
+ )
15
+
16
+
17
+ class _StubMapper:
18
+ def map_request(self, params: Any) -> Any:
19
+ return params
20
+
21
+ def map_response(self, completion: Any) -> Any:
22
+ return completion
23
+
24
+
25
+ class _StubOperation(Operation): # type: ignore[type-arg]
26
+ operation_name = "fetchPerson"
27
+
28
+ def __init__(self, http_client: Any) -> None:
29
+ super().__init__(http_client)
30
+ self.mapper = _StubMapper() # type: ignore[assignment]
31
+
32
+
33
+ def _operation(workflow_result: dict[str, Any]) -> _StubOperation:
34
+ http_client = Mock()
35
+ http_client.get.return_value = Mock(
36
+ error=None,
37
+ result=WorkflowResponse.model_validate(workflow_result),
38
+ )
39
+ return _StubOperation(http_client)
40
+
41
+
42
+ class TestPendingReasonModels:
43
+ def test_in_progress_response_accepts_a_pending_reason(self) -> None:
44
+ response = WorkflowInProgressResponse(
45
+ workflowId="wf-1",
46
+ workflowStatus="pending",
47
+ pendingReason="outsideWorkingHours",
48
+ )
49
+
50
+ assert response.pending_reason == "outsideWorkingHours"
51
+
52
+ def test_started_response_accepts_a_pending_reason(self) -> None:
53
+ response = WorkflowStartedResponse(
54
+ workflowId="wf-1",
55
+ workflowStatus="pending",
56
+ pendingReason="queued",
57
+ )
58
+
59
+ assert response.pending_reason == "queued"
60
+
61
+ @pytest.mark.parametrize(
62
+ "model",
63
+ [WorkflowInProgressResponse, WorkflowStartedResponse, WorkflowResponse],
64
+ )
65
+ def test_field_is_optional_for_back_compat(self, model: Any) -> None:
66
+ response = model(workflowId="wf-1", workflowStatus="running")
67
+
68
+ assert response.pending_reason is None
69
+
70
+
71
+ class TestStatusCarriesPendingReason:
72
+ def test_carries_the_outside_working_hours_reason(self) -> None:
73
+ operation = _operation(
74
+ {
75
+ "workflowId": "wf-1",
76
+ "workflowStatus": "pending",
77
+ "pendingReason": "outsideWorkingHours",
78
+ }
79
+ )
80
+
81
+ result = operation.status("wf-1")
82
+
83
+ assert isinstance(result, WorkflowInProgressResponse)
84
+ assert result.pending_reason == "outsideWorkingHours"
85
+
86
+ def test_carries_the_queued_reason(self) -> None:
87
+ operation = _operation(
88
+ {"workflowId": "wf-1", "workflowStatus": "pending", "pendingReason": "queued"}
89
+ )
90
+
91
+ result = operation.status("wf-1")
92
+
93
+ assert isinstance(result, WorkflowInProgressResponse)
94
+ assert result.pending_reason == "queued"
95
+
96
+ def test_keeps_none_when_the_api_sends_nothing(self) -> None:
97
+ operation = _operation({"workflowId": "wf-1", "workflowStatus": "running"})
98
+
99
+ result = operation.status("wf-1")
100
+
101
+ assert isinstance(result, WorkflowInProgressResponse)
102
+ assert result.pending_reason is None
103
+
104
+
105
+ class TestWorkingHoursErrorTypes:
106
+ @pytest.mark.parametrize("error_type", ["outsideWorkingHours", "workingHoursWaitExpired"])
107
+ def test_error_type_is_known(self, error_type: str) -> None:
108
+ assert error_type in LINKED_API_ERROR_TYPES
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes