ayon-python-api 1.2.16.dev0__py3-none-any.whl → 1.2.17.dev0__py3-none-any.whl

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.
ayon_api/__init__.py CHANGED
@@ -69,6 +69,14 @@ from ._api import (
69
69
  patch,
70
70
  get,
71
71
  delete,
72
+ get_server_config,
73
+ set_server_config,
74
+ get_server_config_overrides,
75
+ get_server_config_value,
76
+ download_server_config_file,
77
+ download_server_config_file_to_stream,
78
+ upload_server_config_file,
79
+ upload_server_config_file_from_stream,
72
80
  download_file_to_stream,
73
81
  download_file,
74
82
  upload_project_file,
@@ -116,6 +124,14 @@ from ._api import (
116
124
  create_activity,
117
125
  update_activity,
118
126
  delete_activity,
127
+ get_raw_activity_categories,
128
+ get_activity_categories,
129
+ create_activity_reaction,
130
+ delete_activity_reaction,
131
+ suggest_entity_mention,
132
+ get_raw_entity_watchers,
133
+ get_entity_watchers,
134
+ set_entity_watchers,
119
135
  send_activities_batch_operations,
120
136
  get_bundles,
121
137
  create_bundle,
@@ -151,6 +167,7 @@ from ._api import (
151
167
  reset_attributes_cache,
152
168
  set_attributes_cache_timeout,
153
169
  set_attribute_config,
170
+ delete_attribute_config,
154
171
  remove_attribute_config,
155
172
  get_attributes_for_type,
156
173
  get_attributes_fields_for_type,
@@ -168,6 +185,13 @@ from ._api import (
168
185
  create_project,
169
186
  update_project,
170
187
  delete_project,
188
+ get_raw_project_folders,
189
+ get_project_folders,
190
+ create_project_folder,
191
+ update_project_folder,
192
+ set_project_folders_order,
193
+ assign_projects_to_project_folder,
194
+ delete_project_folder,
171
195
  get_project_root_overrides,
172
196
  get_project_roots_by_site,
173
197
  get_project_root_overrides_by_site_id,
@@ -356,6 +380,14 @@ __all__ = (
356
380
  "patch",
357
381
  "get",
358
382
  "delete",
383
+ "get_server_config",
384
+ "set_server_config",
385
+ "get_server_config_overrides",
386
+ "get_server_config_value",
387
+ "download_server_config_file",
388
+ "download_server_config_file_to_stream",
389
+ "upload_server_config_file",
390
+ "upload_server_config_file_from_stream",
359
391
  "download_file_to_stream",
360
392
  "download_file",
361
393
  "upload_project_file",
@@ -403,6 +435,14 @@ __all__ = (
403
435
  "create_activity",
404
436
  "update_activity",
405
437
  "delete_activity",
438
+ "get_raw_activity_categories",
439
+ "get_activity_categories",
440
+ "create_activity_reaction",
441
+ "delete_activity_reaction",
442
+ "suggest_entity_mention",
443
+ "get_raw_entity_watchers",
444
+ "get_entity_watchers",
445
+ "set_entity_watchers",
406
446
  "send_activities_batch_operations",
407
447
  "get_bundles",
408
448
  "create_bundle",
@@ -438,6 +478,7 @@ __all__ = (
438
478
  "reset_attributes_cache",
439
479
  "set_attributes_cache_timeout",
440
480
  "set_attribute_config",
481
+ "delete_attribute_config",
441
482
  "remove_attribute_config",
442
483
  "get_attributes_for_type",
443
484
  "get_attributes_fields_for_type",
@@ -455,6 +496,13 @@ __all__ = (
455
496
  "create_project",
456
497
  "update_project",
457
498
  "delete_project",
499
+ "get_raw_project_folders",
500
+ "get_project_folders",
501
+ "create_project_folder",
502
+ "update_project_folder",
503
+ "set_project_folders_order",
504
+ "assign_projects_to_project_folder",
505
+ "delete_project_folder",
458
506
  "get_project_root_overrides",
459
507
  "get_project_roots_by_site",
460
508
  "get_project_root_overrides_by_site_id",
ayon_api/_api.py CHANGED
@@ -41,7 +41,7 @@ from .server_api import (
41
41
  )
42
42
 
43
43
  if typing.TYPE_CHECKING:
44
- from typing import Union
44
+ from typing import Union, Literal
45
45
  from .typing import (
46
46
  ServerVersion,
47
47
  ActivityType,
@@ -926,6 +926,177 @@ def delete(
926
926
  )
927
927
 
928
928
 
929
+ def get_server_config():
930
+ con = get_server_api_connection()
931
+ return con.get_server_config()
932
+
933
+
934
+ def set_server_config(
935
+ studio_name: str | None = None,
936
+ customization: dict[str, Any] | None = None,
937
+ authentication: dict[str, Any] | None = None,
938
+ project_options: dict[str, Any] | None = None,
939
+ changelog: dict[str, Any] | None = None,
940
+ ) -> None:
941
+ con = get_server_api_connection()
942
+ return con.set_server_config(
943
+ studio_name=studio_name,
944
+ customization=customization,
945
+ authentication=authentication,
946
+ project_options=project_options,
947
+ changelog=changelog,
948
+ )
949
+
950
+
951
+ def get_server_config_overrides():
952
+ con = get_server_api_connection()
953
+ return con.get_server_config_overrides()
954
+
955
+
956
+ def get_server_config_value(
957
+ key: str,
958
+ ):
959
+ con = get_server_api_connection()
960
+ return con.get_server_config_value(
961
+ key=key,
962
+ )
963
+
964
+
965
+ def download_server_config_file(
966
+ file_type: Literal["login_background", "studio_logo"],
967
+ filepath: str,
968
+ *,
969
+ chunk_size: Optional[int] = None,
970
+ progress: Optional[TransferProgress] = None,
971
+ ) -> TransferProgress:
972
+ """Download server config file.
973
+
974
+ Validate if server has config file available first. Method crashes
975
+ if the file is not available.
976
+
977
+ Args:
978
+ file_type (Literal["login_background", "studio_logo"]): File to
979
+ download.
980
+ filepath (str): Target filepath.
981
+ chunk_size (int | None): Size of chunks used for download.
982
+ progress (TransferProgress | None): Object to track download
983
+ progress.
984
+
985
+ """
986
+ con = get_server_api_connection()
987
+ return con.download_server_config_file(
988
+ file_type=file_type,
989
+ filepath=filepath,
990
+ chunk_size=chunk_size,
991
+ progress=progress,
992
+ )
993
+
994
+
995
+ def download_server_config_file_to_stream(
996
+ file_type: Literal["login_background", "studio_logo"],
997
+ stream: StreamType,
998
+ *,
999
+ chunk_size: Optional[int] = None,
1000
+ progress: Optional[TransferProgress] = None,
1001
+ ) -> TransferProgress:
1002
+ """Download server config file to byte stream.
1003
+
1004
+ Validate if server has config file available first. Method crashes
1005
+ if the file is not available.
1006
+
1007
+ Args:
1008
+ file_type (Literal["login_background", "studio_logo"]): File to
1009
+ download.
1010
+ stream (StreamType): Stream where downloaded content is stored.
1011
+ chunk_size (int | None): Size of chunks used for download.
1012
+ progress (TransferProgress | None): Object to track download
1013
+ progress.
1014
+
1015
+ """
1016
+ con = get_server_api_connection()
1017
+ return con.download_server_config_file_to_stream(
1018
+ file_type=file_type,
1019
+ stream=stream,
1020
+ chunk_size=chunk_size,
1021
+ progress=progress,
1022
+ )
1023
+
1024
+
1025
+ def upload_server_config_file(
1026
+ file_type: Literal["login_background", "studio_logo"],
1027
+ filepath: str,
1028
+ *,
1029
+ content_type: str | None = None,
1030
+ filename: str | None = None,
1031
+ chunk_size: int | None = None,
1032
+ progress: TransferProgress | None = None,
1033
+ ) -> requests.Response:
1034
+ """Upload server config file from byte stream.
1035
+
1036
+ TODO create filename using file_type and extension from content_type
1037
+ if filename is not specified
1038
+
1039
+ Args:
1040
+ file_type (Literal["login_background", "studio_logo"]): File to
1041
+ download.
1042
+ filepath (str): Filepath used to store the file.
1043
+ chunk_size (int | None): Size of chunks used for download.
1044
+ progress (TransferProgress | None): Object to track download
1045
+ progress.
1046
+
1047
+ Returns:
1048
+ requests.Response: Response from upload.
1049
+
1050
+ """
1051
+ con = get_server_api_connection()
1052
+ return con.upload_server_config_file(
1053
+ file_type=file_type,
1054
+ filepath=filepath,
1055
+ content_type=content_type,
1056
+ filename=filename,
1057
+ chunk_size=chunk_size,
1058
+ progress=progress,
1059
+ )
1060
+
1061
+
1062
+ def upload_server_config_file_from_stream(
1063
+ file_type: Literal["login_background", "studio_logo"],
1064
+ stream: StreamType,
1065
+ filename: str,
1066
+ *,
1067
+ content_type: str | None = None,
1068
+ chunk_size: int | None = None,
1069
+ progress: TransferProgress | None = None,
1070
+ ) -> requests.Response:
1071
+ """Upload server config file from byte stream.
1072
+
1073
+ TODO create filename using file_type and extension from content_type
1074
+ if filename is not specified
1075
+
1076
+ Args:
1077
+ file_type (Literal["login_background", "studio_logo"]): File to
1078
+ download.
1079
+ stream (StreamType): Stream where downloaded content is stored.
1080
+ filename (str): Filename used to store the file.
1081
+ chunk_size (int | None): Size of chunks used for download.
1082
+ progress (TransferProgress | None): Object to track download
1083
+ progress.
1084
+
1085
+ Returns:
1086
+ requests.Response: Response from upload.
1087
+
1088
+ """
1089
+ con = get_server_api_connection()
1090
+ return con.upload_server_config_file_from_stream(
1091
+ file_type=file_type,
1092
+ stream=stream,
1093
+ filename=filename,
1094
+ content_type=content_type,
1095
+ chunk_size=chunk_size,
1096
+ progress=progress,
1097
+ )
1098
+
1099
+
929
1100
  def download_file_to_stream(
930
1101
  endpoint: str,
931
1102
  stream: StreamType,
@@ -2370,6 +2541,144 @@ def delete_activity(
2370
2541
  )
2371
2542
 
2372
2543
 
2544
+ def get_raw_activity_categories(
2545
+ project_name: str,
2546
+ ) -> dict[str, Any]:
2547
+ """Get activity categories available on server (raw response).
2548
+
2549
+ Args:
2550
+ project_name (str): Project name to get categories for.
2551
+
2552
+ Returns:
2553
+ list[str]: Available activity categories.
2554
+
2555
+ """
2556
+ con = get_server_api_connection()
2557
+ return con.get_raw_activity_categories(
2558
+ project_name=project_name,
2559
+ )
2560
+
2561
+
2562
+ def get_activity_categories(
2563
+ project_name: str,
2564
+ ) -> list[str]:
2565
+ """Get activity categories available on server.
2566
+
2567
+ Args:
2568
+ project_name (str): Project name to get categories for.
2569
+
2570
+ Returns:
2571
+ list[str]: Available activity categories.
2572
+
2573
+ """
2574
+ con = get_server_api_connection()
2575
+ return con.get_activity_categories(
2576
+ project_name=project_name,
2577
+ )
2578
+
2579
+
2580
+ def create_activity_reaction(
2581
+ project_name: str,
2582
+ activity_id: str,
2583
+ reaction: str,
2584
+ ) -> None:
2585
+ """React to activity.
2586
+ """
2587
+ con = get_server_api_connection()
2588
+ return con.create_activity_reaction(
2589
+ project_name=project_name,
2590
+ activity_id=activity_id,
2591
+ reaction=reaction,
2592
+ )
2593
+
2594
+
2595
+ def delete_activity_reaction(
2596
+ project_name: str,
2597
+ activity_id: str,
2598
+ reaction: str,
2599
+ ) -> None:
2600
+ con = get_server_api_connection()
2601
+ return con.delete_activity_reaction(
2602
+ project_name=project_name,
2603
+ activity_id=activity_id,
2604
+ reaction=reaction,
2605
+ )
2606
+
2607
+
2608
+ def suggest_entity_mention(
2609
+ project_name: str,
2610
+ entity_id: str,
2611
+ entity_type: Literal["folder", "task", "version"],
2612
+ ) -> dict[str, dict[str, Any]]:
2613
+ """Suggest entities for mention in activity body.
2614
+
2615
+ At this moment does not change data only returns suggestions.
2616
+
2617
+ Args:
2618
+ project_name (str): Project name to search in.
2619
+ entity_id (str): Entity id.
2620
+ entity_type (str): Entity type of the entity.
2621
+
2622
+ Returns:
2623
+ list[dict[str, Any]]: List of suggested entities with
2624
+ their details.
2625
+
2626
+ """
2627
+ con = get_server_api_connection()
2628
+ return con.suggest_entity_mention(
2629
+ project_name=project_name,
2630
+ entity_id=entity_id,
2631
+ entity_type=entity_type,
2632
+ )
2633
+
2634
+
2635
+ def get_raw_entity_watchers(
2636
+ project_name: str,
2637
+ entity_id: str,
2638
+ entity_type: str,
2639
+ ) -> dict[str, Any]:
2640
+ """Get entity watchers (raw response).
2641
+ """
2642
+ con = get_server_api_connection()
2643
+ return con.get_raw_entity_watchers(
2644
+ project_name=project_name,
2645
+ entity_id=entity_id,
2646
+ entity_type=entity_type,
2647
+ )
2648
+
2649
+
2650
+ def get_entity_watchers(
2651
+ project_name: str,
2652
+ entity_id: str,
2653
+ entity_type: str,
2654
+ ) -> list[str]:
2655
+ """List watchers of an entity.
2656
+ """
2657
+ con = get_server_api_connection()
2658
+ return con.get_entity_watchers(
2659
+ project_name=project_name,
2660
+ entity_id=entity_id,
2661
+ entity_type=entity_type,
2662
+ )
2663
+
2664
+
2665
+ def set_entity_watchers(
2666
+ project_name: str,
2667
+ entity_id: str,
2668
+ entity_type: str,
2669
+ watchers: list[str],
2670
+ ):
2671
+ """Change watchers of an entity.
2672
+ """
2673
+ con = get_server_api_connection()
2674
+ return con.set_entity_watchers(
2675
+ project_name=project_name,
2676
+ entity_id=entity_id,
2677
+ entity_type=entity_type,
2678
+ watchers=watchers,
2679
+ )
2680
+
2681
+
2373
2682
  def send_activities_batch_operations(
2374
2683
  project_name: str,
2375
2684
  operations: list[dict[str, Any]],
@@ -3622,13 +3931,30 @@ def set_attribute_config(
3622
3931
  )
3623
3932
 
3624
3933
 
3625
- def remove_attribute_config(
3934
+ def delete_attribute_config(
3626
3935
  attribute_name: str,
3627
3936
  ) -> None:
3628
3937
  """Remove attribute from server.
3629
3938
 
3630
3939
  This can't be un-done, please use carefully.
3631
3940
 
3941
+ Args:
3942
+ attribute_name (str): Name of attribute to remove.
3943
+
3944
+ """
3945
+ con = get_server_api_connection()
3946
+ return con.delete_attribute_config(
3947
+ attribute_name=attribute_name,
3948
+ )
3949
+
3950
+
3951
+ def remove_attribute_config(
3952
+ attribute_name: str,
3953
+ ) -> None:
3954
+ """Remove attribute from server.
3955
+
3956
+ DEPRECATED: Use 'delete_attribute_config' instead.
3957
+
3632
3958
  Args:
3633
3959
  attribute_name (str): Name of attribute to remove.
3634
3960
 
@@ -3803,6 +4129,7 @@ def get_rest_project(
3803
4129
  def get_rest_projects(
3804
4130
  active: Optional[bool] = True,
3805
4131
  library: Optional[bool] = None,
4132
+ include_skeleton: bool = False,
3806
4133
  ) -> Generator[ProjectDict, None, None]:
3807
4134
  """Query available project entities.
3808
4135
 
@@ -3813,6 +4140,7 @@ def get_rest_projects(
3813
4140
  are returned if 'None' is passed.
3814
4141
  library (Optional[bool]): Filter standard/library projects. Both
3815
4142
  are returned if 'None' is passed.
4143
+ include_skeleton (bool): Include skeleton projects.
3816
4144
 
3817
4145
  Returns:
3818
4146
  Generator[ProjectDict, None, None]: Available projects.
@@ -3822,12 +4150,14 @@ def get_rest_projects(
3822
4150
  return con.get_rest_projects(
3823
4151
  active=active,
3824
4152
  library=library,
4153
+ include_skeleton=include_skeleton,
3825
4154
  )
3826
4155
 
3827
4156
 
3828
4157
  def get_rest_projects_list(
3829
4158
  active: Optional[bool] = True,
3830
4159
  library: Optional[bool] = None,
4160
+ include_skeleton: bool = False,
3831
4161
  ) -> list[ProjectListDict]:
3832
4162
  """Receive available projects.
3833
4163
 
@@ -3838,6 +4168,7 @@ def get_rest_projects_list(
3838
4168
  are returned if 'None' is passed.
3839
4169
  library (Optional[bool]): Filter standard/library projects. Both
3840
4170
  are returned if 'None' is passed.
4171
+ include_skeleton (bool): Include skeleton projects.
3841
4172
 
3842
4173
  Returns:
3843
4174
  list[ProjectListDict]: List of available projects.
@@ -3847,12 +4178,14 @@ def get_rest_projects_list(
3847
4178
  return con.get_rest_projects_list(
3848
4179
  active=active,
3849
4180
  library=library,
4181
+ include_skeleton=include_skeleton,
3850
4182
  )
3851
4183
 
3852
4184
 
3853
4185
  def get_project_names(
3854
4186
  active: Optional[bool] = True,
3855
4187
  library: Optional[bool] = None,
4188
+ include_skeleton: bool = False,
3856
4189
  ) -> list[str]:
3857
4190
  """Receive available project names.
3858
4191
 
@@ -3863,6 +4196,7 @@ def get_project_names(
3863
4196
  are returned if 'None' is passed.
3864
4197
  library (Optional[bool]): Filter standard/library projects. Both
3865
4198
  are returned if 'None' is passed.
4199
+ include_skeleton (bool): Include skeleton projects.
3866
4200
 
3867
4201
  Returns:
3868
4202
  list[str]: List of available project names.
@@ -3872,12 +4206,14 @@ def get_project_names(
3872
4206
  return con.get_project_names(
3873
4207
  active=active,
3874
4208
  library=library,
4209
+ include_skeleton=include_skeleton,
3875
4210
  )
3876
4211
 
3877
4212
 
3878
4213
  def get_projects(
3879
4214
  active: Optional[bool] = True,
3880
4215
  library: Optional[bool] = None,
4216
+ include_skeleton: bool = False,
3881
4217
  fields: Optional[Iterable[str]] = None,
3882
4218
  own_attributes: bool = False,
3883
4219
  ) -> Generator[ProjectDict, None, None]:
@@ -3888,6 +4224,7 @@ def get_projects(
3888
4224
  Filter is disabled when 'None' is passed.
3889
4225
  library (Optional[bool]): Filter library projects. Filter is
3890
4226
  disabled when 'None' is passed.
4227
+ include_skeleton (bool): Include skeleton projects.
3891
4228
  fields (Optional[Iterable[str]]): fields to be queried
3892
4229
  for project.
3893
4230
  own_attributes (Optional[bool]): Attribute values that are
@@ -3901,6 +4238,7 @@ def get_projects(
3901
4238
  return con.get_projects(
3902
4239
  active=active,
3903
4240
  library=library,
4241
+ include_skeleton=include_skeleton,
3904
4242
  fields=fields,
3905
4243
  own_attributes=own_attributes,
3906
4244
  )
@@ -3938,6 +4276,8 @@ def create_project(
3938
4276
  project_code: str,
3939
4277
  library_project: bool = False,
3940
4278
  preset_name: Optional[str] = None,
4279
+ data: dict[str, Any] | None = None,
4280
+ skeleton: bool = False,
3941
4281
  ) -> ProjectDict:
3942
4282
  """Create project using AYON settings.
3943
4283
 
@@ -3957,6 +4297,8 @@ def create_project(
3957
4297
  library_project (Optional[bool]): Project is library project.
3958
4298
  preset_name (Optional[str]): Name of anatomy preset. Default is
3959
4299
  used if not passed.
4300
+ data (dict[str, Any]): Project data.
4301
+ skeleton (bool): Project is skeleton project.
3960
4302
 
3961
4303
  Raises:
3962
4304
  ValueError: When project name already exists.
@@ -3971,6 +4313,8 @@ def create_project(
3971
4313
  project_code=project_code,
3972
4314
  library_project=library_project,
3973
4315
  preset_name=preset_name,
4316
+ data=data,
4317
+ skeleton=skeleton,
3974
4318
  )
3975
4319
 
3976
4320
 
@@ -4049,6 +4393,83 @@ def delete_project(
4049
4393
  )
4050
4394
 
4051
4395
 
4396
+ def get_raw_project_folders() -> dict[str, Any]:
4397
+ """Get project folders (raw data).
4398
+ """
4399
+ con = get_server_api_connection()
4400
+ return con.get_raw_project_folders()
4401
+
4402
+
4403
+ def get_project_folders() -> list[dict[str, Any]]:
4404
+ con = get_server_api_connection()
4405
+ return con.get_project_folders()
4406
+
4407
+
4408
+ def create_project_folder(
4409
+ label: str,
4410
+ parent_id: str | None = None,
4411
+ data: dict[str, Any] | None = None,
4412
+ ) -> str:
4413
+ """Create project folder.
4414
+ """
4415
+ con = get_server_api_connection()
4416
+ return con.create_project_folder(
4417
+ label=label,
4418
+ parent_id=parent_id,
4419
+ data=data,
4420
+ )
4421
+
4422
+
4423
+ def update_project_folder(
4424
+ folder_id: str,
4425
+ label: str | None = None,
4426
+ parent_id: str | None = None,
4427
+ data: dict[str, Any] | None = None,
4428
+ ) -> None:
4429
+ con = get_server_api_connection()
4430
+ return con.update_project_folder(
4431
+ folder_id=folder_id,
4432
+ label=label,
4433
+ parent_id=parent_id,
4434
+ data=data,
4435
+ )
4436
+
4437
+
4438
+ def set_project_folders_order(
4439
+ folder_ids: list[str],
4440
+ ) -> None:
4441
+ """Set project folders order.
4442
+ """
4443
+ con = get_server_api_connection()
4444
+ return con.set_project_folders_order(
4445
+ folder_ids=folder_ids,
4446
+ )
4447
+
4448
+
4449
+ def assign_projects_to_project_folder(
4450
+ folder_id: str,
4451
+ project_names: list[str],
4452
+ ) -> None:
4453
+ """Assign project folder to project.
4454
+ """
4455
+ con = get_server_api_connection()
4456
+ return con.assign_projects_to_project_folder(
4457
+ folder_id=folder_id,
4458
+ project_names=project_names,
4459
+ )
4460
+
4461
+
4462
+ def delete_project_folder(
4463
+ folder_id: str,
4464
+ ):
4465
+ """Delete project folder.
4466
+ """
4467
+ con = get_server_api_connection()
4468
+ return con.delete_project_folder(
4469
+ folder_id=folder_id,
4470
+ )
4471
+
4472
+
4052
4473
  def get_project_root_overrides(
4053
4474
  project_name: str,
4054
4475
  ) -> dict[str, dict[str, str]]:
@@ -7710,6 +8131,7 @@ def set_entity_list_attribute_definitions(
7710
8131
  def create_entity_list_item(
7711
8132
  project_name: str,
7712
8133
  list_id: str,
8134
+ entity_id: str,
7713
8135
  *,
7714
8136
  position: Optional[int] = None,
7715
8137
  label: Optional[str] = None,
@@ -7723,6 +8145,7 @@ def create_entity_list_item(
7723
8145
  Args:
7724
8146
  project_name (str): Project name where entity list lives.
7725
8147
  list_id (str): Entity list id where item will be added.
8148
+ entity_id (str): Id of entity added to the list.
7726
8149
  position (Optional[int]): Position of item in entity list.
7727
8150
  label (Optional[str]): Label of item in entity list.
7728
8151
  attrib (Optional[dict[str, Any]]): Item attribute values.
@@ -7738,6 +8161,7 @@ def create_entity_list_item(
7738
8161
  return con.create_entity_list_item(
7739
8162
  project_name=project_name,
7740
8163
  list_id=list_id,
8164
+ entity_id=entity_id,
7741
8165
  position=position,
7742
8166
  label=label,
7743
8167
  attrib=attrib,