unique_sdk 0.10.61__tar.gz → 0.10.64__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 (46) hide show
  1. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/CHANGELOG.md +9 -0
  2. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/PKG-INFO +10 -1
  3. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/pyproject.toml +1 -1
  4. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_content.py +54 -1
  5. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_folder.py +134 -0
  6. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_space.py +194 -9
  7. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_user.py +46 -0
  8. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/LICENSE +0 -0
  9. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/README.md +0 -0
  10. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/__init__.py +0 -0
  11. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/_api_requestor.py +0 -0
  12. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/_api_resource.py +0 -0
  13. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/_api_version.py +0 -0
  14. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/_error.py +0 -0
  15. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/_http_client.py +0 -0
  16. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/_list_object.py +0 -0
  17. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/_object_classes.py +0 -0
  18. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/_request_options.py +0 -0
  19. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/_unique_object.py +0 -0
  20. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/_unique_ql.py +0 -0
  21. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/_unique_response.py +0 -0
  22. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/_util.py +0 -0
  23. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/_version.py +0 -0
  24. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/_webhook.py +0 -0
  25. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/__init__.py +0 -0
  26. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_acronyms.py +0 -0
  27. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_agentic_table.py +0 -0
  28. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_chat_completion.py +0 -0
  29. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_embedding.py +0 -0
  30. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_event.py +0 -0
  31. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_group.py +0 -0
  32. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_integrated.py +0 -0
  33. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_llm_models.py +0 -0
  34. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_mcp.py +0 -0
  35. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_message.py +0 -0
  36. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_message_assessment.py +0 -0
  37. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_message_execution.py +0 -0
  38. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_message_log.py +0 -0
  39. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_search.py +0 -0
  40. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_search_string.py +0 -0
  41. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/api_resources/_short_term_memory.py +0 -0
  42. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/utils/chat_history.py +0 -0
  43. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/utils/chat_in_space.py +0 -0
  44. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/utils/file_io.py +0 -0
  45. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/utils/sources.py +0 -0
  46. {unique_sdk-0.10.61 → unique_sdk-0.10.64}/unique_sdk/utils/token.py +0 -0
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.10.64] - 2025-12-31
9
+ - Add create path functionality to theupsert function and allow getinfo(s) to query by parentfolderpath.
10
+
11
+ ## [0.10.63] - 2025-12-23
12
+ - Add functions to create a space and manage its access.
13
+
14
+ ## [0.10.62] - 2025-12-23
15
+ - Add get user groups function and allow the get users function to filter by username.
16
+
8
17
  ## [0.10.61] - 2025-12-22
9
18
  - Add `displayInChat` field to ingestion config, allowing silent uploads to chat.
10
19
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unique_sdk
3
- Version: 0.10.61
3
+ Version: 0.10.64
4
4
  Summary:
5
5
  License: MIT
6
6
  Author: Martin Fadler
@@ -28,6 +28,15 @@ All notable changes to this project will be documented in this file.
28
28
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
29
29
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
30
30
 
31
+ ## [0.10.64] - 2025-12-31
32
+ - Add create path functionality to theupsert function and allow getinfo(s) to query by parentfolderpath.
33
+
34
+ ## [0.10.63] - 2025-12-23
35
+ - Add functions to create a space and manage its access.
36
+
37
+ ## [0.10.62] - 2025-12-23
38
+ - Add get user groups function and allow the get users function to filter by username.
39
+
31
40
  ## [0.10.61] - 2025-12-22
32
41
  - Add `displayInChat` field to ingestion config, allowing silent uploads to chat.
33
42
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "unique_sdk"
3
- version = "0.10.61"
3
+ version = "0.10.64"
4
4
  description = ""
5
5
  authors = [
6
6
  "Martin Fadler <martin.fadler@unique.ch>",
@@ -110,6 +110,7 @@ class Content(APIResource["Content"]):
110
110
  skip: NotRequired[int | None]
111
111
  take: NotRequired[int | None]
112
112
  parentId: NotRequired[str | None]
113
+ parentFolderPath: NotRequired[str | None]
113
114
 
114
115
  class CustomApiOptions(TypedDict):
115
116
  apiIdentifier: str
@@ -149,6 +150,8 @@ class Content(APIResource["Content"]):
149
150
  class UpsertParams(RequestOptions):
150
151
  input: "Content.Input"
151
152
  scopeId: NotRequired[str | None]
153
+ parentFolderPath: NotRequired[str | None]
154
+ createFolderIfNotExists: NotRequired[bool | None]
152
155
  chatId: NotRequired[str | None]
153
156
  sourceOwnerType: NotRequired[str | None]
154
157
  storeInternally: NotRequired[bool | None]
@@ -315,6 +318,16 @@ class Content(APIResource["Content"]):
315
318
  company_id: str,
316
319
  **params: Unpack["Content.ContentInfosParams"],
317
320
  ) -> "Content.PaginatedContentInfos":
321
+ parent_id = unique_sdk.Folder.resolve_scope_id_from_folder_path(
322
+ user_id=user_id,
323
+ company_id=company_id,
324
+ scope_id=params.get("parentId"),
325
+ folder_path=params.get("parentFolderPath"),
326
+ )
327
+ params.pop("parentFolderPath", None)
328
+ if parent_id:
329
+ params["parentId"] = parent_id
330
+
318
331
  return cast(
319
332
  Content.PaginatedContentInfos,
320
333
  cls._static_request(
@@ -333,6 +346,16 @@ class Content(APIResource["Content"]):
333
346
  company_id: str,
334
347
  **params: Unpack["Content.ContentInfosParams"],
335
348
  ) -> "Content.PaginatedContentInfos":
349
+ parent_id = await unique_sdk.Folder.resolve_scope_id_from_folder_path_async(
350
+ user_id=user_id,
351
+ company_id=company_id,
352
+ scope_id=params.get("parentId"),
353
+ folder_path=params.get("parentFolderPath"),
354
+ )
355
+ params.pop("parentFolderPath", None)
356
+ if parent_id:
357
+ params["parentId"] = parent_id
358
+
336
359
  return cast(
337
360
  Content.PaginatedContentInfos,
338
361
  await cls._static_request_async(
@@ -359,6 +382,19 @@ class Content(APIResource["Content"]):
359
382
  if "description" in params["input"] and not params["input"]["description"]:
360
383
  params["input"].pop("description")
361
384
 
385
+ create_folder = params.get("createFolderIfNotExists")
386
+ scope_id = unique_sdk.Folder.resolve_scope_id_from_folder_path_with_create(
387
+ user_id=user_id,
388
+ company_id=company_id,
389
+ scope_id=params.get("scopeId"),
390
+ folder_path=params.get("parentFolderPath"),
391
+ create_if_not_exists=create_folder if create_folder is not None else True,
392
+ )
393
+ params.pop("parentFolderPath", None)
394
+ params.pop("createFolderIfNotExists", None)
395
+ if scope_id:
396
+ params["scopeId"] = scope_id
397
+
362
398
  return cast(
363
399
  "Content",
364
400
  cls._static_request(
@@ -385,6 +421,23 @@ class Content(APIResource["Content"]):
385
421
  if "description" in params["input"] and not params["input"]["description"]:
386
422
  params["input"].pop("description")
387
423
 
424
+ create_folder = params.get("createFolderIfNotExists")
425
+ scope_id = (
426
+ await unique_sdk.Folder.resolve_scope_id_from_folder_path_with_create_async(
427
+ user_id=user_id,
428
+ company_id=company_id,
429
+ scope_id=params.get("scopeId"),
430
+ folder_path=params.get("parentFolderPath"),
431
+ create_if_not_exists=create_folder
432
+ if create_folder is not None
433
+ else True,
434
+ )
435
+ )
436
+ params.pop("parentFolderPath", None)
437
+ params.pop("createFolderIfNotExists", None)
438
+ if scope_id:
439
+ params["scopeId"] = scope_id
440
+
388
441
  return cast(
389
442
  "Content",
390
443
  await cls._static_request_async(
@@ -481,7 +534,7 @@ class Content(APIResource["Content"]):
481
534
  params.get("contentId"),
482
535
  params.get("filePath"),
483
536
  )
484
- owner_id = unique_sdk.Folder.resolve_scope_id_from_folder_path(
537
+ owner_id = await unique_sdk.Folder.resolve_scope_id_from_folder_path_async(
485
538
  user_id,
486
539
  company_id,
487
540
  params.get("ownerId"),
@@ -157,6 +157,7 @@ class Folder(APIResource["Folder"]):
157
157
  """
158
158
 
159
159
  parentId: NotRequired[str]
160
+ parentFolderPath: NotRequired[str]
160
161
  take: NotRequired[int]
161
162
  skip: NotRequired[int]
162
163
 
@@ -268,6 +269,16 @@ class Folder(APIResource["Folder"]):
268
269
  """
269
270
  Get paginated folders based on parentId. If the parentId is not defined, the root folders will be returned.
270
271
  """
272
+ parent_id = cls.resolve_scope_id_from_folder_path(
273
+ user_id=user_id,
274
+ company_id=company_id,
275
+ scope_id=params.get("parentId"),
276
+ folder_path=params.get("parentFolderPath"),
277
+ )
278
+ params.pop("parentFolderPath", None)
279
+ if parent_id:
280
+ params["parentId"] = parent_id
281
+
271
282
  return cast(
272
283
  "Folder.FolderInfos",
273
284
  cls._static_request(
@@ -286,6 +297,16 @@ class Folder(APIResource["Folder"]):
286
297
  """
287
298
  Async get paginated folders based on parentId. If the parentId is not defined, the root folders will be returned.
288
299
  """
300
+ parent_id = await cls.resolve_scope_id_from_folder_path_async(
301
+ user_id=user_id,
302
+ company_id=company_id,
303
+ scope_id=params.get("parentId"),
304
+ folder_path=params.get("parentFolderPath"),
305
+ )
306
+ params.pop("parentFolderPath", None)
307
+ if parent_id:
308
+ params["parentId"] = parent_id
309
+
289
310
  return cast(
290
311
  "Folder.FolderInfos",
291
312
  await cls._static_request_async(
@@ -617,3 +638,116 @@ class Folder(APIResource["Folder"]):
617
638
  )
618
639
  return resolved_id
619
640
  return None
641
+
642
+ @classmethod
643
+ def resolve_scope_id_from_folder_path_with_create(
644
+ cls,
645
+ user_id: str,
646
+ company_id: str,
647
+ scope_id: str | None = None,
648
+ folder_path: str | None = None,
649
+ create_if_not_exists: bool = True,
650
+ ) -> str | None:
651
+ if scope_id:
652
+ return scope_id
653
+ if folder_path:
654
+ try:
655
+ folder_info = cls.get_info(
656
+ user_id=user_id,
657
+ company_id=company_id,
658
+ folderPath=folder_path,
659
+ )
660
+ resolved_id = folder_info.get("id")
661
+ if resolved_id:
662
+ return resolved_id
663
+ except Exception:
664
+ pass
665
+
666
+ if create_if_not_exists:
667
+ result = cls.create_paths(
668
+ user_id=user_id,
669
+ company_id=company_id,
670
+ paths=[folder_path],
671
+ )
672
+ created_folders = result.get("createdFolders", [])
673
+ if created_folders:
674
+ return created_folders[-1]["id"]
675
+ raise ValueError(
676
+ f"Failed to create folder with folderPath: {folder_path}"
677
+ )
678
+
679
+ raise ValueError(f"Could not find a folder with folderPath: {folder_path}")
680
+ return None
681
+
682
+ @classmethod
683
+ async def resolve_scope_id_from_folder_path_async(
684
+ cls,
685
+ user_id: str,
686
+ company_id: str,
687
+ scope_id: str | None = None,
688
+ folder_path: str | None = None,
689
+ ) -> str | None:
690
+ """
691
+ Async version of resolve_scope_id_from_folder_path.
692
+ Returns the scopeId to use: if scope_id is provided, returns it;
693
+ if not, but folder_path is provided, resolves and returns the id for that folder path.
694
+
695
+ Returns:
696
+ str: The resolved folder ID.
697
+ None: Failed to resolve a folder ID (e.g., folder_path not found or not provided).
698
+ """
699
+ if scope_id:
700
+ return scope_id
701
+ if folder_path:
702
+ folder_info = await cls.get_info_async(
703
+ user_id=user_id,
704
+ company_id=company_id,
705
+ folderPath=folder_path,
706
+ )
707
+ resolved_id = folder_info.get("id")
708
+ if not resolved_id:
709
+ raise ValueError(
710
+ f"Could not find a folder with folderPath: {folder_path}"
711
+ )
712
+ return resolved_id
713
+ return None
714
+
715
+ @classmethod
716
+ async def resolve_scope_id_from_folder_path_with_create_async(
717
+ cls,
718
+ user_id: str,
719
+ company_id: str,
720
+ scope_id: str | None = None,
721
+ folder_path: str | None = None,
722
+ create_if_not_exists: bool = True,
723
+ ) -> str | None:
724
+ if scope_id:
725
+ return scope_id
726
+ if folder_path:
727
+ try:
728
+ folder_info = await cls.get_info_async(
729
+ user_id=user_id,
730
+ company_id=company_id,
731
+ folderPath=folder_path,
732
+ )
733
+ resolved_id = folder_info.get("id")
734
+ if resolved_id:
735
+ return resolved_id
736
+ except Exception:
737
+ pass
738
+
739
+ if create_if_not_exists:
740
+ result = await cls.create_paths_async(
741
+ user_id=user_id,
742
+ company_id=company_id,
743
+ paths=[folder_path],
744
+ )
745
+ created_folders = result.get("createdFolders", [])
746
+ if created_folders:
747
+ return created_folders[-1]["id"]
748
+ raise ValueError(
749
+ f"Failed to create folder with folderPath: {folder_path}"
750
+ )
751
+
752
+ raise ValueError(f"Could not find a folder with folderPath: {folder_path}")
753
+ return None
@@ -18,6 +18,43 @@ from unique_sdk._request_options import RequestOptions
18
18
  class Space(APIResource["Space"]):
19
19
  OBJECT_NAME: ClassVar[Literal["space"]] = "space"
20
20
 
21
+ class ModuleParams(TypedDict):
22
+ name: str
23
+ description: NotRequired[Optional[str]]
24
+ weight: NotRequired[Optional[int]]
25
+ isExternal: NotRequired[Optional[bool]]
26
+ isCustomInstructionEnabled: NotRequired[Optional[bool]]
27
+ configuration: NotRequired[Optional[Dict[str, Any]]]
28
+ toolDefinition: NotRequired[Optional[Dict[str, Any]]]
29
+
30
+ class CreateSpaceParams(RequestOptions):
31
+ name: str
32
+ fallbackModule: str
33
+ modules: List["Space.ModuleParams"]
34
+ explanation: NotRequired[Optional[str]]
35
+ alert: NotRequired[Optional[str]]
36
+ chatUpload: NotRequired[Optional[Literal["ENABLED", "DISABLED"]]]
37
+ languageModel: NotRequired[Optional[str]]
38
+ isExternal: NotRequired[Optional[bool]]
39
+ isPinned: NotRequired[Optional[bool]]
40
+ uiType: NotRequired[
41
+ Optional[
42
+ Literal["MAGIC_TABLE", "UNIQUE_CUSTOM", "TRANSLATION", "UNIQUE_AI"]
43
+ ]
44
+ ]
45
+ settings: NotRequired[Optional[Dict[str, Any]]]
46
+
47
+ class AccessEntry(TypedDict):
48
+ entityId: str
49
+ entityType: Literal["USER", "GROUP"]
50
+ type: Literal["USE", "MANAGE", "UPLOAD"]
51
+
52
+ class AddSpaceAccessParams(RequestOptions):
53
+ access: List["Space.AccessEntry"]
54
+
55
+ class DeleteSpaceAccessParams(RequestOptions):
56
+ accessIds: List[str]
57
+
21
58
  class CreateMessageParams(RequestOptions):
22
59
  """
23
60
  Parameters for querying the assistant for a message.
@@ -104,9 +141,9 @@ class Space(APIResource["Space"]):
104
141
  messages: List["Space.Message"]
105
142
  totalCount: int
106
143
 
107
- class AssistantMcpServer(TypedDict):
144
+ class McpServer(TypedDict):
108
145
  """
109
- Represents an MCP server associated with an assistant.
146
+ Represents an MCP server associated with a space.
110
147
  """
111
148
 
112
149
  id: str
@@ -149,16 +186,18 @@ class Space(APIResource["Space"]):
149
186
  createdAt: str
150
187
  updatedAt: str
151
188
 
152
- class AssistantAccess(TypedDict):
153
- """
154
- Represents access control for a space.
155
- """
156
-
189
+ class Access(TypedDict):
157
190
  id: str
158
191
  entityId: str
159
192
  entityType: str
160
193
  type: str
161
194
 
195
+ class SpaceAccessResponse(TypedDict):
196
+ access: List["Space.Access"]
197
+
198
+ class DeleteSpaceAccessResponse(TypedDict):
199
+ success: bool
200
+
162
201
  id: str
163
202
  name: str
164
203
  defaultForCompanyId: Optional[str]
@@ -177,10 +216,10 @@ class Space(APIResource["Space"]):
177
216
  isPinned: bool
178
217
  uiType: str
179
218
  settings: Optional[Dict[str, Any]]
180
- assistantMcpServers: List["Space.AssistantMcpServer"]
219
+ assistantMcpServers: List["Space.McpServer"]
181
220
  modules: List["Space.Module"]
182
221
  scopeRules: List["Space.ScopeRule"]
183
- assistantAccess: List["Space.AssistantAccess"]
222
+ assistantAccess: List["Space.Access"]
184
223
  createdAt: str
185
224
  updatedAt: str
186
225
 
@@ -385,3 +424,149 @@ class Space(APIResource["Space"]):
385
424
  company_id,
386
425
  ),
387
426
  )
427
+
428
+ @classmethod
429
+ def create_space(
430
+ cls,
431
+ user_id: str,
432
+ company_id: str,
433
+ **params: Unpack["Space.CreateSpaceParams"],
434
+ ) -> "Space":
435
+ return cast(
436
+ "Space",
437
+ cls._static_request(
438
+ "post",
439
+ "/space",
440
+ user_id,
441
+ company_id,
442
+ params=params,
443
+ ),
444
+ )
445
+
446
+ @classmethod
447
+ async def create_space_async(
448
+ cls,
449
+ user_id: str,
450
+ company_id: str,
451
+ **params: Unpack["Space.CreateSpaceParams"],
452
+ ) -> "Space":
453
+ return cast(
454
+ "Space",
455
+ await cls._static_request_async(
456
+ "post",
457
+ "/space",
458
+ user_id,
459
+ company_id,
460
+ params=params,
461
+ ),
462
+ )
463
+
464
+ @classmethod
465
+ def get_space_access(
466
+ cls,
467
+ user_id: str,
468
+ company_id: str,
469
+ space_id: str,
470
+ ) -> "Space.SpaceAccessResponse":
471
+ return cast(
472
+ "Space.SpaceAccessResponse",
473
+ cls._static_request(
474
+ "get",
475
+ f"/space/{space_id}/access",
476
+ user_id,
477
+ company_id,
478
+ ),
479
+ )
480
+
481
+ @classmethod
482
+ async def get_space_access_async(
483
+ cls,
484
+ user_id: str,
485
+ company_id: str,
486
+ space_id: str,
487
+ ) -> "Space.SpaceAccessResponse":
488
+ return cast(
489
+ "Space.SpaceAccessResponse",
490
+ await cls._static_request_async(
491
+ "get",
492
+ f"/space/{space_id}/access",
493
+ user_id,
494
+ company_id,
495
+ ),
496
+ )
497
+
498
+ @classmethod
499
+ def add_space_access(
500
+ cls,
501
+ user_id: str,
502
+ company_id: str,
503
+ space_id: str,
504
+ **params: Unpack["Space.AddSpaceAccessParams"],
505
+ ) -> "Space.SpaceAccessResponse":
506
+ return cast(
507
+ "Space.SpaceAccessResponse",
508
+ cls._static_request(
509
+ "post",
510
+ f"/space/{space_id}/access",
511
+ user_id,
512
+ company_id,
513
+ params=params,
514
+ ),
515
+ )
516
+
517
+ @classmethod
518
+ async def add_space_access_async(
519
+ cls,
520
+ user_id: str,
521
+ company_id: str,
522
+ space_id: str,
523
+ **params: Unpack["Space.AddSpaceAccessParams"],
524
+ ) -> "Space.SpaceAccessResponse":
525
+ return cast(
526
+ "Space.SpaceAccessResponse",
527
+ await cls._static_request_async(
528
+ "post",
529
+ f"/space/{space_id}/access",
530
+ user_id,
531
+ company_id,
532
+ params=params,
533
+ ),
534
+ )
535
+
536
+ @classmethod
537
+ def delete_space_access(
538
+ cls,
539
+ user_id: str,
540
+ company_id: str,
541
+ space_id: str,
542
+ **params: Unpack["Space.DeleteSpaceAccessParams"],
543
+ ) -> "Space.DeleteSpaceAccessResponse":
544
+ return cast(
545
+ "Space.DeleteSpaceAccessResponse",
546
+ cls._static_request(
547
+ "delete",
548
+ f"/space/{space_id}/access",
549
+ user_id,
550
+ company_id,
551
+ params=params,
552
+ ),
553
+ )
554
+
555
+ @classmethod
556
+ async def delete_space_access_async(
557
+ cls,
558
+ user_id: str,
559
+ company_id: str,
560
+ space_id: str,
561
+ **params: Unpack["Space.DeleteSpaceAccessParams"],
562
+ ) -> "Space.DeleteSpaceAccessResponse":
563
+ return cast(
564
+ "Space.DeleteSpaceAccessResponse",
565
+ await cls._static_request_async(
566
+ "delete",
567
+ f"/space/{space_id}/access",
568
+ user_id,
569
+ company_id,
570
+ params=params,
571
+ ),
572
+ )
@@ -26,6 +26,7 @@ class User(APIResource["User"]):
26
26
  take: NotRequired[Optional[int]]
27
27
  email: NotRequired[Optional[str]]
28
28
  displayName: NotRequired[Optional[str]]
29
+ userName: NotRequired[Optional[str]]
29
30
 
30
31
  class UpdateUserConfigurationParams(RequestOptions):
31
32
  """
@@ -34,6 +35,17 @@ class User(APIResource["User"]):
34
35
 
35
36
  userConfiguration: Dict[str, Any]
36
37
 
38
+ class UserGroup(TypedDict):
39
+ id: str
40
+ name: str
41
+ externalId: Optional[str]
42
+ parentId: Optional[str]
43
+ createdAt: str
44
+ updatedAt: str
45
+
46
+ class UserGroupsResponse(TypedDict):
47
+ groups: List["User.UserGroup"]
48
+
37
49
  class User(TypedDict):
38
50
  """
39
51
  Represents a user in the company.
@@ -147,3 +159,37 @@ class User(APIResource["User"]):
147
159
  params=params,
148
160
  ),
149
161
  )
162
+
163
+ @classmethod
164
+ def get_user_groups(
165
+ cls,
166
+ user_id: str,
167
+ company_id: str,
168
+ target_user_id: str,
169
+ ) -> "User.UserGroupsResponse":
170
+ return cast(
171
+ "User.UserGroupsResponse",
172
+ cls._static_request(
173
+ "get",
174
+ f"/users/{target_user_id}/groups",
175
+ user_id,
176
+ company_id,
177
+ ),
178
+ )
179
+
180
+ @classmethod
181
+ async def get_user_groups_async(
182
+ cls,
183
+ user_id: str,
184
+ company_id: str,
185
+ target_user_id: str,
186
+ ) -> "User.UserGroupsResponse":
187
+ return cast(
188
+ "User.UserGroupsResponse",
189
+ await cls._static_request_async(
190
+ "get",
191
+ f"/users/{target_user_id}/groups",
192
+ user_id,
193
+ company_id,
194
+ ),
195
+ )
File without changes
File without changes