workos 5.37.0__tar.gz → 5.38.0__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 (169) hide show
  1. {workos-5.37.0 → workos-5.38.0}/PKG-INFO +1 -1
  2. workos-5.38.0/tests/test_pipes.py +167 -0
  3. {workos-5.37.0 → workos-5.38.0}/tests/test_vault.py +28 -0
  4. {workos-5.37.0 → workos-5.38.0}/workos/__about__.py +1 -1
  5. {workos-5.37.0 → workos-5.38.0}/workos/_base_client.py +5 -0
  6. {workos-5.37.0 → workos-5.38.0}/workos/async_client.py +7 -0
  7. {workos-5.37.0 → workos-5.38.0}/workos/client.py +7 -0
  8. workos-5.38.0/workos/pipes.py +93 -0
  9. workos-5.38.0/workos/types/pipes/__init__.py +6 -0
  10. workos-5.38.0/workos/types/pipes/pipes.py +34 -0
  11. {workos-5.37.0 → workos-5.38.0}/workos/vault.py +29 -0
  12. {workos-5.37.0 → workos-5.38.0}/workos.egg-info/PKG-INFO +1 -1
  13. {workos-5.37.0 → workos-5.38.0}/workos.egg-info/SOURCES.txt +4 -0
  14. {workos-5.37.0 → workos-5.38.0}/LICENSE +0 -0
  15. {workos-5.37.0 → workos-5.38.0}/README.md +0 -0
  16. {workos-5.37.0 → workos-5.38.0}/setup.cfg +0 -0
  17. {workos-5.37.0 → workos-5.38.0}/setup.py +0 -0
  18. {workos-5.37.0 → workos-5.38.0}/tests/test_api_keys.py +0 -0
  19. {workos-5.37.0 → workos-5.38.0}/tests/test_async_http_client.py +0 -0
  20. {workos-5.37.0 → workos-5.38.0}/tests/test_audit_logs.py +0 -0
  21. {workos-5.37.0 → workos-5.38.0}/tests/test_client.py +0 -0
  22. {workos-5.37.0 → workos-5.38.0}/tests/test_directory_sync.py +0 -0
  23. {workos-5.37.0 → workos-5.38.0}/tests/test_events.py +0 -0
  24. {workos-5.37.0 → workos-5.38.0}/tests/test_fga.py +0 -0
  25. {workos-5.37.0 → workos-5.38.0}/tests/test_mfa.py +0 -0
  26. {workos-5.37.0 → workos-5.38.0}/tests/test_organization_domains.py +0 -0
  27. {workos-5.37.0 → workos-5.38.0}/tests/test_organizations.py +0 -0
  28. {workos-5.37.0 → workos-5.38.0}/tests/test_passwordless.py +0 -0
  29. {workos-5.37.0 → workos-5.38.0}/tests/test_portal.py +0 -0
  30. {workos-5.37.0 → workos-5.38.0}/tests/test_session.py +0 -0
  31. {workos-5.37.0 → workos-5.38.0}/tests/test_sso.py +0 -0
  32. {workos-5.37.0 → workos-5.38.0}/tests/test_sync_http_client.py +0 -0
  33. {workos-5.37.0 → workos-5.38.0}/tests/test_user_management.py +0 -0
  34. {workos-5.37.0 → workos-5.38.0}/tests/test_user_management_list_sessions.py +0 -0
  35. {workos-5.37.0 → workos-5.38.0}/tests/test_user_management_revoke_session.py +0 -0
  36. {workos-5.37.0 → workos-5.38.0}/tests/test_webhooks.py +0 -0
  37. {workos-5.37.0 → workos-5.38.0}/tests/test_widgets.py +0 -0
  38. {workos-5.37.0 → workos-5.38.0}/workos/__init__.py +0 -0
  39. {workos-5.37.0 → workos-5.38.0}/workos/_client_configuration.py +0 -0
  40. {workos-5.37.0 → workos-5.38.0}/workos/api_keys.py +0 -0
  41. {workos-5.37.0 → workos-5.38.0}/workos/audit_logs.py +0 -0
  42. {workos-5.37.0 → workos-5.38.0}/workos/directory_sync.py +0 -0
  43. {workos-5.37.0 → workos-5.38.0}/workos/events.py +0 -0
  44. {workos-5.37.0 → workos-5.38.0}/workos/exceptions.py +0 -0
  45. {workos-5.37.0 → workos-5.38.0}/workos/fga.py +0 -0
  46. {workos-5.37.0 → workos-5.38.0}/workos/mfa.py +0 -0
  47. {workos-5.37.0 → workos-5.38.0}/workos/organization_domains.py +0 -0
  48. {workos-5.37.0 → workos-5.38.0}/workos/organizations.py +0 -0
  49. {workos-5.37.0 → workos-5.38.0}/workos/passwordless.py +0 -0
  50. {workos-5.37.0 → workos-5.38.0}/workos/portal.py +0 -0
  51. {workos-5.37.0 → workos-5.38.0}/workos/py.typed +0 -0
  52. {workos-5.37.0 → workos-5.38.0}/workos/session.py +0 -0
  53. {workos-5.37.0 → workos-5.38.0}/workos/sso.py +0 -0
  54. {workos-5.37.0 → workos-5.38.0}/workos/types/__init__.py +0 -0
  55. {workos-5.37.0 → workos-5.38.0}/workos/types/api_keys/__init__.py +0 -0
  56. {workos-5.37.0 → workos-5.38.0}/workos/types/api_keys/api_keys.py +0 -0
  57. {workos-5.37.0 → workos-5.38.0}/workos/types/audit_logs/__init__.py +0 -0
  58. {workos-5.37.0 → workos-5.38.0}/workos/types/audit_logs/audit_log_event.py +0 -0
  59. {workos-5.37.0 → workos-5.38.0}/workos/types/audit_logs/audit_log_event_actor.py +0 -0
  60. {workos-5.37.0 → workos-5.38.0}/workos/types/audit_logs/audit_log_event_context.py +0 -0
  61. {workos-5.37.0 → workos-5.38.0}/workos/types/audit_logs/audit_log_event_target.py +0 -0
  62. {workos-5.37.0 → workos-5.38.0}/workos/types/audit_logs/audit_log_export.py +0 -0
  63. {workos-5.37.0 → workos-5.38.0}/workos/types/audit_logs/audit_log_metadata.py +0 -0
  64. {workos-5.37.0 → workos-5.38.0}/workos/types/directory_sync/__init__.py +0 -0
  65. {workos-5.37.0 → workos-5.38.0}/workos/types/directory_sync/directory.py +0 -0
  66. {workos-5.37.0 → workos-5.38.0}/workos/types/directory_sync/directory_group.py +0 -0
  67. {workos-5.37.0 → workos-5.38.0}/workos/types/directory_sync/directory_state.py +0 -0
  68. {workos-5.37.0 → workos-5.38.0}/workos/types/directory_sync/directory_type.py +0 -0
  69. {workos-5.37.0 → workos-5.38.0}/workos/types/directory_sync/directory_user.py +0 -0
  70. {workos-5.37.0 → workos-5.38.0}/workos/types/directory_sync/list_filters.py +0 -0
  71. {workos-5.37.0 → workos-5.38.0}/workos/types/events/__init__.py +0 -0
  72. {workos-5.37.0 → workos-5.38.0}/workos/types/events/authentication_payload.py +0 -0
  73. {workos-5.37.0 → workos-5.38.0}/workos/types/events/connection_payload_with_legacy_fields.py +0 -0
  74. {workos-5.37.0 → workos-5.38.0}/workos/types/events/directory_group_membership_payload.py +0 -0
  75. {workos-5.37.0 → workos-5.38.0}/workos/types/events/directory_group_with_previous_attributes.py +0 -0
  76. {workos-5.37.0 → workos-5.38.0}/workos/types/events/directory_payload.py +0 -0
  77. {workos-5.37.0 → workos-5.38.0}/workos/types/events/directory_payload_with_legacy_fields.py +0 -0
  78. {workos-5.37.0 → workos-5.38.0}/workos/types/events/directory_user_with_previous_attributes.py +0 -0
  79. {workos-5.37.0 → workos-5.38.0}/workos/types/events/event.py +0 -0
  80. {workos-5.37.0 → workos-5.38.0}/workos/types/events/event_model.py +0 -0
  81. {workos-5.37.0 → workos-5.38.0}/workos/types/events/event_type.py +0 -0
  82. {workos-5.37.0 → workos-5.38.0}/workos/types/events/list_filters.py +0 -0
  83. {workos-5.37.0 → workos-5.38.0}/workos/types/events/organization_domain_verification_failed_payload.py +0 -0
  84. {workos-5.37.0 → workos-5.38.0}/workos/types/events/previous_attributes.py +0 -0
  85. {workos-5.37.0 → workos-5.38.0}/workos/types/events/session_payload.py +0 -0
  86. {workos-5.37.0 → workos-5.38.0}/workos/types/feature_flags/__init__.py +0 -0
  87. {workos-5.37.0 → workos-5.38.0}/workos/types/feature_flags/feature_flag.py +0 -0
  88. {workos-5.37.0 → workos-5.38.0}/workos/types/feature_flags/list_filters.py +0 -0
  89. {workos-5.37.0 → workos-5.38.0}/workos/types/fga/__init__.py +0 -0
  90. {workos-5.37.0 → workos-5.38.0}/workos/types/fga/authorization_resource_types.py +0 -0
  91. {workos-5.37.0 → workos-5.38.0}/workos/types/fga/authorization_resources.py +0 -0
  92. {workos-5.37.0 → workos-5.38.0}/workos/types/fga/check.py +0 -0
  93. {workos-5.37.0 → workos-5.38.0}/workos/types/fga/list_filters.py +0 -0
  94. {workos-5.37.0 → workos-5.38.0}/workos/types/fga/warnings.py +0 -0
  95. {workos-5.37.0 → workos-5.38.0}/workos/types/fga/warrant.py +0 -0
  96. {workos-5.37.0 → workos-5.38.0}/workos/types/list_resource.py +0 -0
  97. {workos-5.37.0 → workos-5.38.0}/workos/types/metadata.py +0 -0
  98. {workos-5.37.0 → workos-5.38.0}/workos/types/mfa/__init__.py +0 -0
  99. {workos-5.37.0 → workos-5.38.0}/workos/types/mfa/authentication_challenge.py +0 -0
  100. {workos-5.37.0 → workos-5.38.0}/workos/types/mfa/authentication_challenge_verification_response.py +0 -0
  101. {workos-5.37.0 → workos-5.38.0}/workos/types/mfa/authentication_factor.py +0 -0
  102. {workos-5.37.0 → workos-5.38.0}/workos/types/mfa/authentication_factor_totp_and_challenge_response.py +0 -0
  103. {workos-5.37.0 → workos-5.38.0}/workos/types/mfa/enroll_authentication_factor_type.py +0 -0
  104. {workos-5.37.0 → workos-5.38.0}/workos/types/organization_domains/__init__.py +0 -0
  105. {workos-5.37.0 → workos-5.38.0}/workos/types/organization_domains/organization_domain.py +0 -0
  106. {workos-5.37.0 → workos-5.38.0}/workos/types/organizations/__init__.py +0 -0
  107. {workos-5.37.0 → workos-5.38.0}/workos/types/organizations/domain_data_input.py +0 -0
  108. {workos-5.37.0 → workos-5.38.0}/workos/types/organizations/list_filters.py +0 -0
  109. {workos-5.37.0 → workos-5.38.0}/workos/types/organizations/organization.py +0 -0
  110. {workos-5.37.0 → workos-5.38.0}/workos/types/organizations/organization_common.py +0 -0
  111. {workos-5.37.0 → workos-5.38.0}/workos/types/passwordless/__init__.py +0 -0
  112. {workos-5.37.0 → workos-5.38.0}/workos/types/passwordless/passwordless_session.py +0 -0
  113. {workos-5.37.0 → workos-5.38.0}/workos/types/passwordless/passwordless_session_type.py +0 -0
  114. {workos-5.37.0 → workos-5.38.0}/workos/types/portal/__init__.py +0 -0
  115. {workos-5.37.0 → workos-5.38.0}/workos/types/portal/portal_link.py +0 -0
  116. {workos-5.37.0 → workos-5.38.0}/workos/types/portal/portal_link_intent.py +0 -0
  117. {workos-5.37.0 → workos-5.38.0}/workos/types/portal/portal_link_intent_options.py +0 -0
  118. {workos-5.37.0 → workos-5.38.0}/workos/types/roles/__init__.py +0 -0
  119. {workos-5.37.0 → workos-5.38.0}/workos/types/roles/role.py +0 -0
  120. {workos-5.37.0 → workos-5.38.0}/workos/types/sso/__init__.py +0 -0
  121. {workos-5.37.0 → workos-5.38.0}/workos/types/sso/connection.py +0 -0
  122. {workos-5.37.0 → workos-5.38.0}/workos/types/sso/connection_domain.py +0 -0
  123. {workos-5.37.0 → workos-5.38.0}/workos/types/sso/profile.py +0 -0
  124. {workos-5.37.0 → workos-5.38.0}/workos/types/sso/sso_provider_type.py +0 -0
  125. {workos-5.37.0 → workos-5.38.0}/workos/types/user_management/__init__.py +0 -0
  126. {workos-5.37.0 → workos-5.38.0}/workos/types/user_management/authenticate_with_common.py +0 -0
  127. {workos-5.37.0 → workos-5.38.0}/workos/types/user_management/authentication_response.py +0 -0
  128. {workos-5.37.0 → workos-5.38.0}/workos/types/user_management/email_verification.py +0 -0
  129. {workos-5.37.0 → workos-5.38.0}/workos/types/user_management/impersonator.py +0 -0
  130. {workos-5.37.0 → workos-5.38.0}/workos/types/user_management/invitation.py +0 -0
  131. {workos-5.37.0 → workos-5.38.0}/workos/types/user_management/list_filters.py +0 -0
  132. {workos-5.37.0 → workos-5.38.0}/workos/types/user_management/magic_auth.py +0 -0
  133. {workos-5.37.0 → workos-5.38.0}/workos/types/user_management/oauth_tokens.py +0 -0
  134. {workos-5.37.0 → workos-5.38.0}/workos/types/user_management/organization_membership.py +0 -0
  135. {workos-5.37.0 → workos-5.38.0}/workos/types/user_management/password_hash_type.py +0 -0
  136. {workos-5.37.0 → workos-5.38.0}/workos/types/user_management/password_reset.py +0 -0
  137. {workos-5.37.0 → workos-5.38.0}/workos/types/user_management/screen_hint.py +0 -0
  138. {workos-5.37.0 → workos-5.38.0}/workos/types/user_management/session.py +0 -0
  139. {workos-5.37.0 → workos-5.38.0}/workos/types/user_management/user.py +0 -0
  140. {workos-5.37.0 → workos-5.38.0}/workos/types/user_management/user_management_provider_type.py +0 -0
  141. {workos-5.37.0 → workos-5.38.0}/workos/types/vault/__init__.py +0 -0
  142. {workos-5.37.0 → workos-5.38.0}/workos/types/vault/key.py +0 -0
  143. {workos-5.37.0 → workos-5.38.0}/workos/types/vault/object.py +0 -0
  144. {workos-5.37.0 → workos-5.38.0}/workos/types/webhooks/__init__.py +0 -0
  145. {workos-5.37.0 → workos-5.38.0}/workos/types/webhooks/webhook.py +0 -0
  146. {workos-5.37.0 → workos-5.38.0}/workos/types/webhooks/webhook_model.py +0 -0
  147. {workos-5.37.0 → workos-5.38.0}/workos/types/webhooks/webhook_payload.py +0 -0
  148. {workos-5.37.0 → workos-5.38.0}/workos/types/widgets/__init__.py +0 -0
  149. {workos-5.37.0 → workos-5.38.0}/workos/types/widgets/widget_scope.py +0 -0
  150. {workos-5.37.0 → workos-5.38.0}/workos/types/widgets/widget_token_response.py +0 -0
  151. {workos-5.37.0 → workos-5.38.0}/workos/types/workos_model.py +0 -0
  152. {workos-5.37.0 → workos-5.38.0}/workos/typing/__init__.py +0 -0
  153. {workos-5.37.0 → workos-5.38.0}/workos/typing/literals.py +0 -0
  154. {workos-5.37.0 → workos-5.38.0}/workos/typing/sync_or_async.py +0 -0
  155. {workos-5.37.0 → workos-5.38.0}/workos/typing/untyped_literal.py +0 -0
  156. {workos-5.37.0 → workos-5.38.0}/workos/typing/webhooks.py +0 -0
  157. {workos-5.37.0 → workos-5.38.0}/workos/user_management.py +0 -0
  158. {workos-5.37.0 → workos-5.38.0}/workos/utils/__init__.py +0 -0
  159. {workos-5.37.0 → workos-5.38.0}/workos/utils/_base_http_client.py +0 -0
  160. {workos-5.37.0 → workos-5.38.0}/workos/utils/crypto_provider.py +0 -0
  161. {workos-5.37.0 → workos-5.38.0}/workos/utils/http_client.py +0 -0
  162. {workos-5.37.0 → workos-5.38.0}/workos/utils/pagination_order.py +0 -0
  163. {workos-5.37.0 → workos-5.38.0}/workos/utils/request_helper.py +0 -0
  164. {workos-5.37.0 → workos-5.38.0}/workos/webhooks.py +0 -0
  165. {workos-5.37.0 → workos-5.38.0}/workos/widgets.py +0 -0
  166. {workos-5.37.0 → workos-5.38.0}/workos.egg-info/dependency_links.txt +0 -0
  167. {workos-5.37.0 → workos-5.38.0}/workos.egg-info/not-zip-safe +0 -0
  168. {workos-5.37.0 → workos-5.38.0}/workos.egg-info/requires.txt +0 -0
  169. {workos-5.37.0 → workos-5.38.0}/workos.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: workos
3
- Version: 5.37.0
3
+ Version: 5.38.0
4
4
  Summary: WorkOS Python Client
5
5
  Home-page: https://github.com/workos-inc/workos-python
6
6
  Author: WorkOS
@@ -0,0 +1,167 @@
1
+ import pytest
2
+
3
+ from tests.utils.syncify import syncify
4
+ from workos.pipes import AsyncPipes, Pipes
5
+
6
+
7
+ @pytest.mark.sync_and_async(Pipes, AsyncPipes)
8
+ class TestPipes:
9
+ @pytest.fixture
10
+ def mock_access_token(self):
11
+ return {
12
+ "object": "access_token",
13
+ "access_token": "test_access_token_123",
14
+ "expires_at": "2026-01-09T12:00:00.000Z",
15
+ "scopes": ["read:users", "write:users"],
16
+ "missing_scopes": [],
17
+ }
18
+
19
+ def test_get_access_token_success_with_expiry(
20
+ self,
21
+ module_instance,
22
+ mock_access_token,
23
+ capture_and_mock_http_client_request,
24
+ ):
25
+ response_body = {
26
+ "active": True,
27
+ "access_token": mock_access_token,
28
+ }
29
+ request_kwargs = capture_and_mock_http_client_request(
30
+ module_instance._http_client, response_body, 200
31
+ )
32
+
33
+ result = syncify(
34
+ module_instance.get_access_token(
35
+ provider="test-provider",
36
+ user_id="user_123",
37
+ )
38
+ )
39
+
40
+ assert request_kwargs["url"].endswith("data-integrations/test-provider/token")
41
+ assert request_kwargs["method"] == "post"
42
+ assert request_kwargs["json"]["user_id"] == "user_123"
43
+ assert result.active is True
44
+ assert result.access_token.access_token == mock_access_token["access_token"]
45
+ assert result.access_token.scopes == mock_access_token["scopes"]
46
+
47
+ def test_get_access_token_success_without_expiry(
48
+ self,
49
+ module_instance,
50
+ capture_and_mock_http_client_request,
51
+ ):
52
+ response_body = {
53
+ "active": True,
54
+ "access_token": {
55
+ "object": "access_token",
56
+ "access_token": "test_token",
57
+ "expires_at": None,
58
+ "scopes": ["read"],
59
+ "missing_scopes": [],
60
+ },
61
+ }
62
+ capture_and_mock_http_client_request(
63
+ module_instance._http_client, response_body, 200
64
+ )
65
+
66
+ result = syncify(
67
+ module_instance.get_access_token(
68
+ provider="test-provider",
69
+ user_id="user_123",
70
+ )
71
+ )
72
+
73
+ assert result.active is True
74
+ assert result.access_token.expires_at is None
75
+
76
+ def test_get_access_token_with_organization_id(
77
+ self,
78
+ module_instance,
79
+ mock_access_token,
80
+ capture_and_mock_http_client_request,
81
+ ):
82
+ response_body = {
83
+ "active": True,
84
+ "access_token": mock_access_token,
85
+ }
86
+ request_kwargs = capture_and_mock_http_client_request(
87
+ module_instance._http_client, response_body, 200
88
+ )
89
+
90
+ syncify(
91
+ module_instance.get_access_token(
92
+ provider="test-provider",
93
+ user_id="user_123",
94
+ organization_id="org_456",
95
+ )
96
+ )
97
+
98
+ assert request_kwargs["json"]["organization_id"] == "org_456"
99
+
100
+ def test_get_access_token_without_organization_id(
101
+ self,
102
+ module_instance,
103
+ mock_access_token,
104
+ capture_and_mock_http_client_request,
105
+ ):
106
+ response_body = {
107
+ "active": True,
108
+ "access_token": mock_access_token,
109
+ }
110
+ request_kwargs = capture_and_mock_http_client_request(
111
+ module_instance._http_client, response_body, 200
112
+ )
113
+
114
+ syncify(
115
+ module_instance.get_access_token(
116
+ provider="test-provider",
117
+ user_id="user_123",
118
+ )
119
+ )
120
+
121
+ assert "organization_id" not in request_kwargs["json"]
122
+
123
+ def test_get_access_token_not_installed(
124
+ self,
125
+ module_instance,
126
+ capture_and_mock_http_client_request,
127
+ ):
128
+ response_body = {
129
+ "active": False,
130
+ "error": "not_installed",
131
+ }
132
+ capture_and_mock_http_client_request(
133
+ module_instance._http_client, response_body, 200
134
+ )
135
+
136
+ result = syncify(
137
+ module_instance.get_access_token(
138
+ provider="test-provider",
139
+ user_id="user_123",
140
+ )
141
+ )
142
+
143
+ assert result.active is False
144
+ assert result.error == "not_installed"
145
+
146
+ def test_get_access_token_needs_reauthorization(
147
+ self,
148
+ module_instance,
149
+ capture_and_mock_http_client_request,
150
+ ):
151
+ response_body = {
152
+ "active": False,
153
+ "error": "needs_reauthorization",
154
+ }
155
+ capture_and_mock_http_client_request(
156
+ module_instance._http_client, response_body, 200
157
+ )
158
+
159
+ result = syncify(
160
+ module_instance.get_access_token(
161
+ provider="test-provider",
162
+ user_id="user_123",
163
+ )
164
+ )
165
+
166
+ assert result.active is False
167
+ assert result.error == "needs_reauthorization"
@@ -107,6 +107,34 @@ class TestVault:
107
107
  ):
108
108
  self.vault.read_object(object_id=None)
109
109
 
110
+ def test_read_object_by_name_success(
111
+ self, mock_vault_object, capture_and_mock_http_client_request
112
+ ):
113
+ request_kwargs = capture_and_mock_http_client_request(
114
+ self.http_client, mock_vault_object, 200
115
+ )
116
+
117
+ vault_object = self.vault.read_object_by_name(name="test-secret")
118
+
119
+ assert request_kwargs["method"] == "get"
120
+ assert request_kwargs["url"].endswith("/vault/v1/kv/name/test-secret")
121
+ assert vault_object.id == "vault_01234567890abcdef"
122
+ assert vault_object.name == "test-secret"
123
+ assert vault_object.value == "secret-value"
124
+ assert vault_object.metadata.environment_id == "env_01234567890abcdef"
125
+
126
+ def test_read_object_by_name_missing_name(self):
127
+ with pytest.raises(
128
+ ValueError, match="Incomplete arguments: 'name' is a required argument"
129
+ ):
130
+ self.vault.read_object_by_name(name="")
131
+
132
+ def test_read_object_by_name_none_name(self):
133
+ with pytest.raises(
134
+ ValueError, match="Incomplete arguments: 'name' is a required argument"
135
+ ):
136
+ self.vault.read_object_by_name(name=None)
137
+
110
138
  def test_list_objects_default_params(
111
139
  self, mock_vault_objects_list, capture_and_mock_http_client_request
112
140
  ):
@@ -12,7 +12,7 @@ __package_name__ = "workos"
12
12
 
13
13
  __package_url__ = "https://github.com/workos-inc/workos-python"
14
14
 
15
- __version__ = "5.37.0"
15
+ __version__ = "5.38.0"
16
16
 
17
17
  __author__ = "WorkOS"
18
18
 
@@ -10,6 +10,7 @@ from workos.events import EventsModule
10
10
  from workos.fga import FGAModule
11
11
  from workos.mfa import MFAModule
12
12
  from workos.organization_domains import OrganizationDomainsModule
13
+ from workos.pipes import PipesModule
13
14
  from workos.organizations import OrganizationsModule
14
15
  from workos.passwordless import PasswordlessModule
15
16
  from workos.portal import PortalModule
@@ -101,6 +102,10 @@ class BaseClient(ClientConfiguration):
101
102
  @abstractmethod
102
103
  def passwordless(self) -> PasswordlessModule: ...
103
104
 
105
+ @property
106
+ @abstractmethod
107
+ def pipes(self) -> PipesModule: ...
108
+
104
109
  @property
105
110
  @abstractmethod
106
111
  def portal(self) -> PortalModule: ...
@@ -10,6 +10,7 @@ from workos.mfa import MFAModule
10
10
  from workos.organizations import AsyncOrganizations
11
11
  from workos.organization_domains import AsyncOrganizationDomains
12
12
  from workos.passwordless import PasswordlessModule
13
+ from workos.pipes import AsyncPipes
13
14
  from workos.portal import PortalModule
14
15
  from workos.sso import AsyncSSO
15
16
  from workos.user_management import AsyncUserManagement
@@ -102,6 +103,12 @@ class AsyncClient(BaseClient):
102
103
  "Passwordless APIs are not yet supported in the async client."
103
104
  )
104
105
 
106
+ @property
107
+ def pipes(self) -> AsyncPipes:
108
+ if not getattr(self, "_pipes", None):
109
+ self._pipes = AsyncPipes(self._http_client)
110
+ return self._pipes
111
+
105
112
  @property
106
113
  def portal(self) -> PortalModule:
107
114
  raise NotImplementedError(
@@ -8,6 +8,7 @@ from workos.fga import FGA
8
8
  from workos.organizations import Organizations
9
9
  from workos.organization_domains import OrganizationDomains
10
10
  from workos.passwordless import Passwordless
11
+ from workos.pipes import Pipes
11
12
  from workos.portal import Portal
12
13
  from workos.sso import SSO
13
14
  from workos.webhooks import Webhooks
@@ -102,6 +103,12 @@ class SyncClient(BaseClient):
102
103
  self._passwordless = Passwordless(self._http_client)
103
104
  return self._passwordless
104
105
 
106
+ @property
107
+ def pipes(self) -> Pipes:
108
+ if not getattr(self, "_pipes", None):
109
+ self._pipes = Pipes(self._http_client)
110
+ return self._pipes
111
+
105
112
  @property
106
113
  def portal(self) -> Portal:
107
114
  if not getattr(self, "_portal", None):
@@ -0,0 +1,93 @@
1
+ from typing import Dict, Optional, Protocol
2
+
3
+ from workos.types.pipes import (
4
+ GetAccessTokenFailureResponse,
5
+ GetAccessTokenResponse,
6
+ GetAccessTokenSuccessResponse,
7
+ )
8
+ from workos.typing.sync_or_async import SyncOrAsync
9
+ from workos.utils.http_client import AsyncHTTPClient, SyncHTTPClient
10
+ from workos.utils.request_helper import REQUEST_METHOD_POST
11
+
12
+
13
+ class PipesModule(Protocol):
14
+ """Protocol defining the Pipes module interface."""
15
+
16
+ def get_access_token(
17
+ self,
18
+ *,
19
+ provider: str,
20
+ user_id: str,
21
+ organization_id: Optional[str] = None,
22
+ ) -> SyncOrAsync[GetAccessTokenResponse]:
23
+ """Retrieve an access token for a third-party provider.
24
+
25
+ Kwargs:
26
+ provider (str): The third-party provider identifier
27
+ user_id (str): The WorkOS user ID
28
+ organization_id (str, optional): The WorkOS organization ID
29
+
30
+ Returns:
31
+ GetAccessTokenResponse: Success response with token or failure response with error
32
+ """
33
+ ...
34
+
35
+
36
+ class Pipes(PipesModule):
37
+ """Sync implementation of the Pipes module."""
38
+
39
+ _http_client: SyncHTTPClient
40
+
41
+ def __init__(self, http_client: SyncHTTPClient):
42
+ self._http_client = http_client
43
+
44
+ def get_access_token(
45
+ self,
46
+ *,
47
+ provider: str,
48
+ user_id: str,
49
+ organization_id: Optional[str] = None,
50
+ ) -> GetAccessTokenResponse:
51
+ json_data: Dict[str, str] = {"user_id": user_id}
52
+ if organization_id is not None:
53
+ json_data["organization_id"] = organization_id
54
+
55
+ response = self._http_client.request(
56
+ f"data-integrations/{provider}/token",
57
+ method=REQUEST_METHOD_POST,
58
+ json=json_data,
59
+ )
60
+
61
+ if response.get("active") is True:
62
+ return GetAccessTokenSuccessResponse.model_validate(response)
63
+ return GetAccessTokenFailureResponse.model_validate(response)
64
+
65
+
66
+ class AsyncPipes(PipesModule):
67
+ """Async implementation of the Pipes module."""
68
+
69
+ _http_client: AsyncHTTPClient
70
+
71
+ def __init__(self, http_client: AsyncHTTPClient):
72
+ self._http_client = http_client
73
+
74
+ async def get_access_token(
75
+ self,
76
+ *,
77
+ provider: str,
78
+ user_id: str,
79
+ organization_id: Optional[str] = None,
80
+ ) -> GetAccessTokenResponse:
81
+ json_data: Dict[str, str] = {"user_id": user_id}
82
+ if organization_id is not None:
83
+ json_data["organization_id"] = organization_id
84
+
85
+ response = await self._http_client.request(
86
+ f"data-integrations/{provider}/token",
87
+ method=REQUEST_METHOD_POST,
88
+ json=json_data,
89
+ )
90
+
91
+ if response.get("active") is True:
92
+ return GetAccessTokenSuccessResponse.model_validate(response)
93
+ return GetAccessTokenFailureResponse.model_validate(response)
@@ -0,0 +1,6 @@
1
+ from workos.types.pipes.pipes import (
2
+ AccessToken as AccessToken,
3
+ GetAccessTokenFailureResponse as GetAccessTokenFailureResponse,
4
+ GetAccessTokenResponse as GetAccessTokenResponse,
5
+ GetAccessTokenSuccessResponse as GetAccessTokenSuccessResponse,
6
+ )
@@ -0,0 +1,34 @@
1
+ from datetime import datetime
2
+ from typing import Literal, Optional, Sequence, Union
3
+
4
+ from workos.types.workos_model import WorkOSModel
5
+
6
+
7
+ class AccessToken(WorkOSModel):
8
+ """Represents an OAuth access token for a third-party provider."""
9
+
10
+ object: Literal["access_token"]
11
+ access_token: str
12
+ expires_at: Optional[datetime] = None
13
+ scopes: Sequence[str]
14
+ missing_scopes: Sequence[str]
15
+
16
+
17
+ class GetAccessTokenSuccessResponse(WorkOSModel):
18
+ """Successful response containing the access token."""
19
+
20
+ active: Literal[True]
21
+ access_token: AccessToken
22
+
23
+
24
+ class GetAccessTokenFailureResponse(WorkOSModel):
25
+ """Failed response indicating why the token couldn't be retrieved."""
26
+
27
+ active: Literal[False]
28
+ error: Literal["not_installed", "needs_reauthorization"]
29
+
30
+
31
+ GetAccessTokenResponse = Union[
32
+ GetAccessTokenSuccessResponse,
33
+ GetAccessTokenFailureResponse,
34
+ ]
@@ -37,6 +37,17 @@ class VaultModule(Protocol):
37
37
  """
38
38
  ...
39
39
 
40
+ def read_object_by_name(self, *, name: str) -> VaultObject:
41
+ """
42
+ Get a Vault object by name with the value decrypted.
43
+
44
+ Kwargs:
45
+ name (str): The unique name of the object.
46
+ Returns:
47
+ VaultObject: A vault object with metadata, name and decrypted value.
48
+ """
49
+ ...
50
+
40
51
  def list_objects(
41
52
  self,
42
53
  *,
@@ -230,6 +241,24 @@ class Vault(VaultModule):
230
241
 
231
242
  return VaultObject.model_validate(response)
232
243
 
244
+ def read_object_by_name(
245
+ self,
246
+ *,
247
+ name: str,
248
+ ) -> VaultObject:
249
+ if not name:
250
+ raise ValueError("Incomplete arguments: 'name' is a required argument")
251
+
252
+ response = self._http_client.request(
253
+ RequestHelper.build_parameterized_url(
254
+ "vault/v1/kv/name/{name}",
255
+ name=name,
256
+ ),
257
+ method=REQUEST_METHOD_GET,
258
+ )
259
+
260
+ return VaultObject.model_validate(response)
261
+
233
262
  def list_objects(
234
263
  self,
235
264
  *,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: workos
3
- Version: 5.37.0
3
+ Version: 5.38.0
4
4
  Summary: WorkOS Python Client
5
5
  Home-page: https://github.com/workos-inc/workos-python
6
6
  Author: WorkOS
@@ -12,6 +12,7 @@ tests/test_mfa.py
12
12
  tests/test_organization_domains.py
13
13
  tests/test_organizations.py
14
14
  tests/test_passwordless.py
15
+ tests/test_pipes.py
15
16
  tests/test_portal.py
16
17
  tests/test_session.py
17
18
  tests/test_sso.py
@@ -38,6 +39,7 @@ workos/mfa.py
38
39
  workos/organization_domains.py
39
40
  workos/organizations.py
40
41
  workos/passwordless.py
42
+ workos/pipes.py
41
43
  workos/portal.py
42
44
  workos/py.typed
43
45
  workos/session.py
@@ -113,6 +115,8 @@ workos/types/organizations/organization_common.py
113
115
  workos/types/passwordless/__init__.py
114
116
  workos/types/passwordless/passwordless_session.py
115
117
  workos/types/passwordless/passwordless_session_type.py
118
+ workos/types/pipes/__init__.py
119
+ workos/types/pipes/pipes.py
116
120
  workos/types/portal/__init__.py
117
121
  workos/types/portal/portal_link.py
118
122
  workos/types/portal/portal_link_intent.py
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes