diff --git a/.mock/definition/__package__.yml b/.mock/definition/__package__.yml
index ca719a1e8..e1d997527 100644
--- a/.mock/definition/__package__.yml
+++ b/.mock/definition/__package__.yml
@@ -4103,6 +4103,17 @@ types:
workspace: optional
source:
openapi: openapi/openapi.yaml
+ LseProjectParams:
+ properties:
+ annotator_params: optional
+ use_kappa:
+ type: optional
+ docs: >-
+ If categorical variables are used in labeling (e.g. choices), Cohen's
+ Kappa statistic is computed to measure inter-rater reliability instead
+ of basic agreement
+ source:
+ openapi: openapi/openapi.yaml
LseProjectResponseSampling:
discriminated: false
union:
diff --git a/.mock/definition/projects.yml b/.mock/definition/projects.yml
index 3f029bf2e..78bf0f61e 100644
--- a/.mock/definition/projects.yml
+++ b/.mock/definition/projects.yml
@@ -1045,138 +1045,6 @@ service:
created: 1
audiences:
- public
- api_projects_members_create:
- path: /api/projects/{id}/members/
- method: POST
- auth: true
- docs: |-
-
-
-
- This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
-
-
- Add a member to a specific project.
- source:
- openapi: openapi/openapi.yaml
- path-parameters:
- id: integer
- display-name: Add project member
- request:
- name: ProjectMemberRequest
- body:
- properties:
- user: integer
- content-type: application/json
- response:
- docs: ''
- type: root.ProjectMember
- examples:
- - path-parameters:
- id: 1
- request:
- user: 1
- response:
- body:
- user: 1
- api_projects_members_destroy:
- path: /api/projects/{id}/members/
- method: DELETE
- auth: true
- docs: |-
-
-
-
- This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
-
-
- Remove a member from a specific project.
- source:
- openapi: openapi/openapi.yaml
- path-parameters:
- id: integer
- display-name: Remove member from project
- request:
- name: ApiProjectsMembersDestroyRequest
- query-parameters:
- project_member:
- type: optional
- docs: A unique integer value identifying this project member.
- examples:
- - path-parameters:
- id: 1
- api_projects_project_extra_params_retrieve:
- path: /api/projects/{id}/project-extra-params/
- method: GET
- auth: true
- docs: >-
-
-
-
- This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
-
-
- Retrieve the annotator weights for statistics and Cohen's Kappa for a
- specific project.
- source:
- openapi: openapi/openapi.yaml
- path-parameters:
- id: integer
- display-name: Get annotator weights
- response:
- docs: Annotator weights retrieved
- type: ApiProjectsProjectExtraParamsRetrieveResponse
- examples:
- - path-parameters:
- id: 1
- response:
- body:
- annotator_params:
- - key: value
- use_kappa: true
- api_projects_project_extra_params_create:
- path: /api/projects/{id}/project-extra-params/
- method: POST
- auth: true
- docs: >-
-
-
-
- This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
-
-
- Create annotator weights to be used in the annotation statistics for a
- project, such as when calculating kappa metrics for inter-annotator
- agreement.
- source:
- openapi: openapi/openapi.yaml
- path-parameters:
- id: integer
- display-name: Create annotator weights for statistics
- request:
- name: LseProjectParamsRequest
- body:
- properties:
- annotator_params: optional
- use_kappa:
- type: optional
- docs: >-
- If categorical variables are used in labeling (e.g. choices),
- Cohen's Kappa statistic is computed to measure inter-rater
- reliability instead of basic agreement
- content-type: application/json
- response:
- docs: Annotator weights created/updated
- type: ApiProjectsProjectExtraParamsCreateResponse
- examples:
- - path-parameters:
- id: 1
- request: {}
- response:
- body:
- annotator_params:
- - key: value
- use_kappa: true
api_projects_reimports_retrieve:
path: /api/projects/{id}/reimports/{reimport_pk}/
method: GET
@@ -1402,25 +1270,3 @@ types:
docs: Number of predictions created
source:
openapi: openapi/openapi.yaml
- ApiProjectsProjectExtraParamsRetrieveResponse:
- docs: Create or change annotator weights for statistics
- properties:
- annotator_params:
- type: optional>>
- docs: Dict of users with weights
- use_kappa:
- type: optional
- docs: If project uses Cohen's Kappa in calculation
- source:
- openapi: openapi/openapi.yaml
- ApiProjectsProjectExtraParamsCreateResponse:
- docs: Create or change annotator weights for statistics
- properties:
- annotator_params:
- type: optional>>
- docs: Dict of users with weights
- use_kappa:
- type: optional
- docs: If project uses Cohen's Kappa in calculation
- source:
- openapi: openapi/openapi.yaml
diff --git a/.mock/definition/projects/annotatorWeights.yml b/.mock/definition/projects/annotatorWeights.yml
new file mode 100644
index 000000000..af253a281
--- /dev/null
+++ b/.mock/definition/projects/annotatorWeights.yml
@@ -0,0 +1,89 @@
+imports:
+ root: ../__package__.yml
+service:
+ auth: false
+ base-path: ''
+ endpoints:
+ get:
+ path: /api/projects/{id}/project-extra-params/
+ method: GET
+ auth: true
+ docs: >-
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+ Retrieve the annotator weights for statistics and Cohen's Kappa for a
+ specific project. Affects dashboard-members stats, but old and unused.
+ source:
+ openapi: openapi/openapi.yaml
+ path-parameters:
+ id: integer
+ display-name: Get annotator weights
+ response:
+ docs: Annotator weights retrieved
+ type: root.LseProjectParams
+ examples:
+ - path-parameters:
+ id: 1
+ response:
+ body:
+ annotator_params:
+ key: value
+ use_kappa: true
+ audiences:
+ - internal
+ create:
+ path: /api/projects/{id}/project-extra-params/
+ method: POST
+ auth: true
+ docs: >-
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+ Create annotator weights to be used in the annotation statistics for a
+ project, such as when calculating kappa metrics for inter-annotator
+ agreement. Affects dashboard-members stats, but old and unused.
+ source:
+ openapi: openapi/openapi.yaml
+ path-parameters:
+ id: integer
+ display-name: Create annotator weights for statistics
+ request:
+ name: LseProjectParamsRequest
+ body:
+ properties:
+ annotator_params: optional
+ use_kappa:
+ type: optional
+ docs: >-
+ If categorical variables are used in labeling (e.g. choices),
+ Cohen's Kappa statistic is computed to measure inter-rater
+ reliability instead of basic agreement
+ content-type: application/json
+ response:
+ docs: Annotator weights created/updated
+ type: root.LseProjectParams
+ examples:
+ - name: payload format for annotator_params
+ path-parameters:
+ id: 1
+ request:
+ annotator_params:
+ '123': 1
+ '456': 0.75
+ use_kappa: true
+ response:
+ body:
+ annotator_params:
+ key: value
+ use_kappa: true
+ audiences:
+ - internal
+ source:
+ openapi: openapi/openapi.yaml
diff --git a/.mock/definition/projects/members.yml b/.mock/definition/projects/members.yml
index a75c582c9..d1353db6e 100644
--- a/.mock/definition/projects/members.yml
+++ b/.mock/definition/projects/members.yml
@@ -9,14 +9,11 @@ service:
method: GET
auth: true
docs: >-
-
-
-
- This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
-
-
Retrieve the members for a specific project. Optionally filter by user
IDs (comma-separated).
+
+
+ Does NOT include annotators. Deprecated; use paginated endpoint.
source:
openapi: openapi/openapi.yaml
path-parameters:
@@ -33,6 +30,7 @@ service:
response:
docs: List of users with membership information
type: list
+ availability: deprecated
examples:
- path-parameters:
id: 1
@@ -76,6 +74,64 @@ service:
pause: pause
phone: phone
username: username
+ audiences:
+ - internal
+ add:
+ path: /api/projects/{id}/members/
+ method: POST
+ auth: true
+ docs: |-
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+ Add a member to a specific project.
+ source:
+ openapi: openapi/openapi.yaml
+ path-parameters:
+ id: integer
+ display-name: Add project member
+ request:
+ name: ProjectMemberRequest
+ body:
+ properties:
+ user: integer
+ content-type: application/json
+ response:
+ docs: ''
+ type: root.ProjectMember
+ examples:
+ - path-parameters:
+ id: 1
+ request:
+ user: 1
+ response:
+ body:
+ user: 1
+ audiences:
+ - public
+ remove:
+ path: /api/projects/{id}/members/
+ method: DELETE
+ auth: true
+ docs: |-
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+ Remove a member from a specific project.
+ source:
+ openapi: openapi/openapi.yaml
+ path-parameters:
+ id: integer
+ display-name: Remove member from project
+ examples:
+ - path-parameters:
+ id: 1
audiences:
- public
source:
diff --git a/.mock/definition/projectRoles.yml b/.mock/definition/projects/roles.yml
similarity index 92%
rename from .mock/definition/projectRoles.yml
rename to .mock/definition/projects/roles.yml
index 5a7e176ed..2a29e4bdf 100644
--- a/.mock/definition/projectRoles.yml
+++ b/.mock/definition/projects/roles.yml
@@ -1,10 +1,10 @@
imports:
- root: __package__.yml
+ root: ../__package__.yml
service:
auth: false
base-path: ''
endpoints:
- api_projects_roles_list:
+ list:
path: /api/projects/roles/
method: GET
auth: true
@@ -22,7 +22,7 @@ service:
openapi: openapi/openapi.yaml
display-name: List project roles for current user
request:
- name: ApiProjectsRolesListRequest
+ name: RolesListRequest
query-parameters:
ids: optional
ordering:
@@ -38,7 +38,9 @@ service:
project: 1
role: OW
user: 1
- api_projects_roles_create:
+ audiences:
+ - public
+ add:
path: /api/projects/roles/
method: POST
auth: true
@@ -75,7 +77,7 @@ service:
user: integer
content-type: application/json
response:
- docs: ''
+ docs: Role created
type: root.ProjectRole
examples:
- request:
@@ -88,7 +90,9 @@ service:
project: 1
role: OW
user: 1
- api_projects_roles_destroy:
+ audiences:
+ - public
+ remove:
path: /api/projects/roles/{id}/
method: DELETE
auth: true
@@ -112,7 +116,9 @@ service:
examples:
- path-parameters:
id: 1
- api_projects_roles_retrieve:
+ audiences:
+ - public
+ get:
path: /api/projects/{id}/roles
method: GET
auth: true
@@ -134,15 +140,17 @@ service:
display-name: List project roles
response:
docs: ''
- type: root.ProjectRole
+ type: list
examples:
- path-parameters:
id: 1
response:
body:
- id: 1
- project: 1
- role: OW
- user: 1
+ - id: 1
+ project: 1
+ role: OW
+ user: 1
+ audiences:
+ - public
source:
openapi: openapi/openapi.yaml
diff --git a/.mock/definition/workspaces.yml b/.mock/definition/workspaces.yml
index 869917f07..df2461243 100644
--- a/.mock/definition/workspaces.yml
+++ b/.mock/definition/workspaces.yml
@@ -222,299 +222,5 @@ service:
title: title
audiences:
- public
- api_workspaces_projects_retrieve:
- path: /api/workspaces/{id}/projects/
- method: GET
- auth: true
- docs: |-
-
-
-
- This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
-
-
- Retrieve a list of all projects in a specific workspace.
- source:
- openapi: openapi/openapi.yaml
- path-parameters:
- id: integer
- display-name: List workspace projects
- response:
- docs: ''
- type: root.Project
- examples:
- - path-parameters:
- id: 1
- response:
- body:
- color: color
- config_has_control_tags: true
- config_suitable_for_bulk_annotation: true
- control_weights:
- key: value
- created_at: '2024-01-15T09:30:00Z'
- created_by:
- avatar: avatar
- email: email
- first_name: first_name
- id: 1
- last_name: last_name
- description: description
- enable_empty_annotation: true
- evaluate_predictions_automatically: true
- expert_instruction: expert_instruction
- finished_task_number: 1
- ground_truth_number: 1
- id: 1
- is_draft: true
- is_published: true
- label_config: label_config
- maximum_annotations: 1
- min_annotations_to_start_training: 1
- model_version: model_version
- num_tasks_with_annotations: 1
- organization: 1
- overlap_cohort_percentage: 1
- parsed_label_config:
- key: value
- pinned_at: '2024-01-15T09:30:00Z'
- queue_done: 1
- queue_total: 1
- reveal_preannotations_interactively: true
- sampling: Sequential sampling
- show_annotation_history: true
- show_collab_predictions: true
- show_ground_truth_first: true
- show_instruction: true
- show_overlap_first: true
- show_skip_button: true
- skip_queue: REQUEUE_FOR_ME
- skipped_annotations_number: 1
- start_training_on_annotation_update: true
- task_data_login: task_data_login
- task_data_password: task_data_password
- task_number: 1
- title: title
- total_annotations_number: 1
- total_predictions_number: 1
- useful_annotation_number: 1
- api_workspaces_projects_create:
- path: /api/workspaces/{id}/projects/
- method: POST
- auth: true
- docs: |-
-
-
-
- This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
-
-
- Create a project in a specific workspace.
- source:
- openapi: openapi/openapi.yaml
- path-parameters:
- id: integer
- display-name: Create workspace project
- request:
- name: ProjectRequest
- body:
- properties:
- color:
- type: optional
- validation:
- maxLength: 16
- control_weights: optional
- created_by:
- type: optional
- docs: Project owner
- description:
- type: optional
- docs: Project description
- enable_empty_annotation:
- type: optional
- docs: Allow annotators to submit empty annotations
- evaluate_predictions_automatically:
- type: optional
- docs: Retrieve and display predictions when loading a task
- expert_instruction:
- type: optional
- docs: Labeling instructions in HTML format
- is_draft:
- type: optional
- docs: Whether or not the project is in the middle of being created
- is_published:
- type: optional
- docs: Whether or not the project is published to annotators
- label_config:
- type: optional
- docs: Label config in XML format. See more about it in documentation
- maximum_annotations:
- type: optional
- docs: >-
- Maximum number of annotations for one task. If the number of
- annotations per task is equal or greater to this value, the task
- is completed (is_labeled=True)
- validation:
- min: -2147483648
- max: 2147483647
- min_annotations_to_start_training:
- type: optional
- docs: >-
- Minimum number of completed tasks after which model training is
- started
- validation:
- min: -2147483648
- max: 2147483647
- model_version:
- type: optional
- docs: Machine learning model version
- organization: optional
- overlap_cohort_percentage:
- type: optional
- validation:
- min: -2147483648
- max: 2147483647
- pinned_at:
- type: optional
- docs: Pinned date and time
- reveal_preannotations_interactively:
- type: optional
- docs: Reveal pre-annotations interactively
- sampling: optional
- show_annotation_history:
- type: optional
- docs: Show annotation history to annotator
- show_collab_predictions:
- type: optional
- docs: If set, the annotator can view model predictions
- show_ground_truth_first:
- type: optional
- docs: >-
- Onboarding mode (true): show ground truth tasks first in the
- labeling stream
- show_instruction:
- type: optional
- docs: Show instructions to the annotator before they start
- show_overlap_first: optional
- show_skip_button:
- type: optional
- docs: >-
- Show a skip button in interface and allow annotators to skip the
- task
- skip_queue: optional
- task_data_login:
- type: optional
- docs: 'Task data credentials: login'
- validation:
- maxLength: 256
- task_data_password:
- type: optional
- docs: 'Task data credentials: password'
- validation:
- maxLength: 256
- title:
- type: optional
- docs: Project name. Must be between 3 and 50 characters long.
- validation:
- minLength: 3
- maxLength: 50
- content-type: application/json
- response:
- docs: ''
- type: root.Project
- examples:
- - path-parameters:
- id: 1
- request: {}
- response:
- body:
- color: color
- config_has_control_tags: true
- config_suitable_for_bulk_annotation: true
- control_weights:
- key: value
- created_at: '2024-01-15T09:30:00Z'
- created_by:
- avatar: avatar
- email: email
- first_name: first_name
- id: 1
- last_name: last_name
- description: description
- enable_empty_annotation: true
- evaluate_predictions_automatically: true
- expert_instruction: expert_instruction
- finished_task_number: 1
- ground_truth_number: 1
- id: 1
- is_draft: true
- is_published: true
- label_config: label_config
- maximum_annotations: 1
- min_annotations_to_start_training: 1
- model_version: model_version
- num_tasks_with_annotations: 1
- organization: 1
- overlap_cohort_percentage: 1
- parsed_label_config:
- key: value
- pinned_at: '2024-01-15T09:30:00Z'
- queue_done: 1
- queue_total: 1
- reveal_preannotations_interactively: true
- sampling: Sequential sampling
- show_annotation_history: true
- show_collab_predictions: true
- show_ground_truth_first: true
- show_instruction: true
- show_overlap_first: true
- show_skip_button: true
- skip_queue: REQUEUE_FOR_ME
- skipped_annotations_number: 1
- start_training_on_annotation_update: true
- task_data_login: task_data_login
- task_data_password: task_data_password
- task_number: 1
- title: title
- total_annotations_number: 1
- total_predictions_number: 1
- useful_annotation_number: 1
- api_workspaces_projects_destroy:
- path: /api/workspaces/{id}/projects/
- method: DELETE
- auth: true
- docs: |-
-
-
-
- This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
-
-
- Delete projects from a specific workspace.
- source:
- openapi: openapi/openapi.yaml
- path-parameters:
- id: integer
- display-name: Remove workspace projects
- examples:
- - path-parameters:
- id: 1
source:
openapi: openapi/openapi.yaml
-types:
- ProjectRequestSampling:
- discriminated: false
- union:
- - root.SamplingDe5Enum
- - root.NullEnum
- source:
- openapi: openapi/openapi.yaml
- inline: true
- ProjectRequestSkipQueue:
- discriminated: false
- union:
- - root.SkipQueueEnum
- - root.NullEnum
- source:
- openapi: openapi/openapi.yaml
- inline: true
diff --git a/.mock/definition/workspaces/projects.yml b/.mock/definition/workspaces/projects.yml
new file mode 100644
index 000000000..ecc289dd7
--- /dev/null
+++ b/.mock/definition/workspaces/projects.yml
@@ -0,0 +1,138 @@
+imports:
+ root: ../__package__.yml
+service:
+ auth: false
+ base-path: ''
+ endpoints:
+ list:
+ path: /api/workspaces/{id}/projects/
+ method: GET
+ auth: true
+ docs: |-
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+ Retrieve a list of all projects in a specific workspace.
+ source:
+ openapi: openapi/openapi.yaml
+ path-parameters:
+ id: integer
+ display-name: List workspace projects
+ response:
+ docs: Projects list
+ type: list
+ examples:
+ - path-parameters:
+ id: 1
+ response:
+ body:
+ - color: color
+ config_has_control_tags: true
+ config_suitable_for_bulk_annotation: true
+ control_weights:
+ key: value
+ created_at: '2024-01-15T09:30:00Z'
+ created_by:
+ avatar: avatar
+ email: email
+ first_name: first_name
+ id: 1
+ last_name: last_name
+ description: description
+ enable_empty_annotation: true
+ evaluate_predictions_automatically: true
+ expert_instruction: expert_instruction
+ finished_task_number: 1
+ ground_truth_number: 1
+ id: 1
+ is_draft: true
+ is_published: true
+ label_config: label_config
+ maximum_annotations: 1
+ min_annotations_to_start_training: 1
+ model_version: model_version
+ num_tasks_with_annotations: 1
+ organization: 1
+ overlap_cohort_percentage: 1
+ parsed_label_config:
+ key: value
+ pinned_at: '2024-01-15T09:30:00Z'
+ queue_done: 1
+ queue_total: 1
+ reveal_preannotations_interactively: true
+ sampling: Sequential sampling
+ show_annotation_history: true
+ show_collab_predictions: true
+ show_ground_truth_first: true
+ show_instruction: true
+ show_overlap_first: true
+ show_skip_button: true
+ skip_queue: REQUEUE_FOR_ME
+ skipped_annotations_number: 1
+ start_training_on_annotation_update: true
+ task_data_login: task_data_login
+ task_data_password: task_data_password
+ task_number: 1
+ title: title
+ total_annotations_number: 1
+ total_predictions_number: 1
+ useful_annotation_number: 1
+ audiences:
+ - public
+ add:
+ path: /api/workspaces/{id}/projects/
+ method: POST
+ auth: true
+ docs: |-
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+ Add a project to a specific workspace.
+ source:
+ openapi: openapi/openapi.yaml
+ path-parameters:
+ id: integer
+ display-name: Add workspace project
+ request:
+ name: WorkspaceProjectsRequest
+ body:
+ properties:
+ project: integer
+ content-type: application/json
+ examples:
+ - path-parameters:
+ id: 1
+ request:
+ project: 1
+ audiences:
+ - public
+ remove:
+ path: /api/workspaces/{id}/projects/
+ method: DELETE
+ auth: true
+ docs: |-
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+ Remove a project from a specific workspace.
+ source:
+ openapi: openapi/openapi.yaml
+ path-parameters:
+ id: integer
+ display-name: Remove workspace project
+ examples:
+ - path-parameters:
+ id: 1
+ audiences:
+ - public
+ source:
+ openapi: openapi/openapi.yaml
diff --git a/.mock/openapi/openapi.yaml b/.mock/openapi/openapi.yaml
index ee37f1587..210803f0f 100644
--- a/.mock/openapi/openapi.yaml
+++ b/.mock/openapi/openapi.yaml
@@ -6990,6 +6990,12 @@ paths:
summary: List project roles for current user
tags:
- Project Roles
+ x-fern-audiences:
+ - public
+ x-fern-sdk-group-name:
+ - projects
+ - roles
+ x-fern-sdk-method-name: list
post:
description: "\n
\n \n This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)\n
\n \n\n Create project role for user allowing the user the same access level provided by organization role.\n "
operationId: api_projects_roles_create
@@ -7011,12 +7017,18 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/ProjectRole'
- description: ''
+ description: Role created
security:
- Token: []
summary: Create project role for user
tags:
- Project Roles
+ x-fern-audiences:
+ - public
+ x-fern-sdk-group-name:
+ - projects
+ - roles
+ x-fern-sdk-method-name: add
/api/projects/roles/{id}/:
delete:
description: "\n
\n \n This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)\n
\n \n\n Remove project role for user allowing the user the same access level provided by organization role.\n "
@@ -7030,12 +7042,18 @@ paths:
type: integer
responses:
'204':
- description: No response body
+ description: Role removed
security:
- Token: []
summary: Remove project role for user
tags:
- Project Roles
+ x-fern-audiences:
+ - public
+ x-fern-sdk-group-name:
+ - projects
+ - roles
+ x-fern-sdk-method-name: remove
/api/projects/validate/:
post:
description: Validate an arbitrary labeling configuration.
@@ -8220,28 +8238,26 @@ paths:
required: true
schema:
type: integer
- - description: A unique integer value identifying this project member.
- in: query
- name: project_member
- schema:
- type: integer
responses:
'204':
- description: No response body
+ description: Member removed
security:
- Token: []
summary: Remove member from project
tags:
- Projects
+ x-fern-audiences:
+ - public
+ x-fern-sdk-group-name:
+ - projects
+ - members
+ x-fern-sdk-method-name: remove
get:
+ deprecated: true
description: |-
-
-
-
- This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
-
-
Retrieve the members for a specific project. Optionally filter by user IDs (comma-separated).
+
+ Does NOT include annotators. Deprecated; use paginated endpoint.
operationId: api_projects_members_retrieve
parameters:
- in: path
@@ -8269,7 +8285,7 @@ paths:
tags:
- Projects
x-fern-audiences:
- - public
+ - internal
x-fern-sdk-group-name:
- projects
- members
@@ -8314,6 +8330,12 @@ paths:
summary: Add project member
tags:
- Projects
+ x-fern-audiences:
+ - public
+ x-fern-sdk-group-name:
+ - projects
+ - members
+ x-fern-sdk-method-name: add
/api/projects/{id}/members/bulk/:
delete:
description: |-
@@ -8724,7 +8746,7 @@ paths:
This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
- Retrieve the annotator weights for statistics and Cohen's Kappa for a specific project.
+ Retrieve the annotator weights for statistics and Cohen's Kappa for a specific project. Affects dashboard-members stats, but old and unused.
operationId: api_projects_project_extra_params_retrieve
parameters:
- in: path
@@ -8737,22 +8759,7 @@ paths:
content:
application/json:
schema:
- description: Create or change annotator weights for statistics
- properties:
- annotator_params:
- description: Dict of users with weights
- items:
- description: '{user_id: weight}'
- title: User_id and weight
- type: object
- title: annotator_params
- type: array
- use_kappa:
- description: If project uses Cohen's Kappa in calculation
- title: use_kappa
- type: boolean
- title: Change annotator weights for statistics
- type: object
+ $ref: '#/components/schemas/LseProjectParams'
description: Annotator weights retrieved
'204':
description: No annotator weights found
@@ -8761,6 +8768,12 @@ paths:
summary: Get annotator weights
tags:
- Projects
+ x-fern-audiences:
+ - internal
+ x-fern-sdk-group-name:
+ - projects
+ - annotator_weights
+ x-fern-sdk-method-name: get
post:
description: |-
@@ -8769,7 +8782,7 @@ paths:
This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
- Create annotator weights to be used in the annotation statistics for a project, such as when calculating kappa metrics for inter-annotator agreement.
+ Create annotator weights to be used in the annotation statistics for a project, such as when calculating kappa metrics for inter-annotator agreement. Affects dashboard-members stats, but old and unused.
operationId: api_projects_project_extra_params_create
parameters:
- in: path
@@ -8780,6 +8793,15 @@ paths:
requestBody:
content:
application/json:
+ examples:
+ AnnotatorWeightsMapping:
+ description: annotator_params must be a mapping of user_id to weight (0..1).
+ summary: payload format for annotator_params
+ value:
+ annotator_params:
+ 123: 1.0
+ 456: 0.75
+ use_kappa: true
schema:
$ref: '#/components/schemas/LseProjectParamsRequest'
application/x-www-form-urlencoded:
@@ -8793,28 +8815,19 @@ paths:
content:
application/json:
schema:
- description: Create or change annotator weights for statistics
- properties:
- annotator_params:
- description: Dict of users with weights
- items:
- description: '{user_id: weight}'
- title: User_id and weight
- type: object
- title: annotator_params
- type: array
- use_kappa:
- description: If project uses Cohen's Kappa in calculation
- title: use_kappa
- type: boolean
- title: Change annotator weights for statistics
- type: object
+ $ref: '#/components/schemas/LseProjectParams'
description: Annotator weights created/updated
security:
- Token: []
summary: Create annotator weights for statistics
tags:
- Projects
+ x-fern-audiences:
+ - internal
+ x-fern-sdk-group-name:
+ - projects
+ - annotator_weights
+ x-fern-sdk-method-name: create
/api/projects/{id}/reimports/{reimport_pk}/:
get:
description: Return data related to async project reimport operation
@@ -8860,13 +8873,21 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectRole'
+ items:
+ $ref: '#/components/schemas/ProjectRole'
+ type: array
description: ''
security:
- Token: []
summary: List project roles
tags:
- Project Roles
+ x-fern-audiences:
+ - public
+ x-fern-sdk-group-name:
+ - projects
+ - roles
+ x-fern-sdk-method-name: get
/api/projects/{id}/stats/IAA:
get:
description: |-
@@ -18523,7 +18544,7 @@ paths:
This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
- Delete projects from a specific workspace.
+ Remove a project from a specific workspace.
operationId: api_workspaces_projects_destroy
parameters:
- in: path
@@ -18533,12 +18554,18 @@ paths:
type: integer
responses:
'204':
- description: No response body
+ description: Project removed
security:
- Token: []
- summary: Remove workspace projects
+ summary: Remove workspace project
tags:
- Workspaces
+ x-fern-audiences:
+ - public
+ x-fern-sdk-group-name:
+ - workspaces
+ - projects
+ x-fern-sdk-method-name: remove
get:
description: |-
@@ -18560,13 +18587,21 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/Project'
- description: ''
+ items:
+ $ref: '#/components/schemas/Project'
+ type: array
+ description: Projects list
security:
- Token: []
summary: List workspace projects
tags:
- Workspaces
+ x-fern-audiences:
+ - public
+ x-fern-sdk-group-name:
+ - workspaces
+ - projects
+ x-fern-sdk-method-name: list
post:
description: |-
@@ -18575,7 +18610,7 @@ paths:
This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
- Create a project in a specific workspace.
+ Add a project to a specific workspace.
operationId: api_workspaces_projects_create
parameters:
- in: path
@@ -18587,25 +18622,28 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectRequest'
+ $ref: '#/components/schemas/WorkspaceProjectsRequest'
application/x-www-form-urlencoded:
schema:
- $ref: '#/components/schemas/ProjectRequest'
+ $ref: '#/components/schemas/WorkspaceProjectsRequest'
multipart/form-data:
schema:
- $ref: '#/components/schemas/ProjectRequest'
+ $ref: '#/components/schemas/WorkspaceProjectsRequest'
+ required: true
responses:
- '200':
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Project'
- description: ''
+ '201':
+ description: Project added
security:
- Token: []
- summary: Create workspace project
+ summary: Add workspace project
tags:
- Workspaces
+ x-fern-audiences:
+ - public
+ x-fern-sdk-group-name:
+ - workspaces
+ - projects
+ x-fern-sdk-method-name: add
/data/upload/{filename}:
get:
description: Download a specific uploaded file.
@@ -24238,6 +24276,15 @@ components:
workspace:
type: integer
type: object
+ LseProjectParams:
+ properties:
+ annotator_params:
+ description: 'user ID and user weight in score calculation. Format {user_id[int]: weight[Float[0..1]]}'
+ nullable: true
+ use_kappa:
+ description: If categorical variables are used in labeling (e.g. choices), Cohen's Kappa statistic is computed to measure inter-rater reliability instead of basic agreement
+ type: boolean
+ type: object
LseProjectParamsRequest:
properties:
annotator_params:
@@ -29849,122 +29896,6 @@ components:
required:
- id
type: object
- ProjectRequest:
- description: |-
- Serializer get numbers from project queryset annotation,
- make sure, that you use correct one(Project.objects.with_counts())
- properties:
- color:
- maxLength: 16
- nullable: true
- type: string
- control_weights:
- description: 'Dict of weights for each control tag in metric calculation. Each control tag (e.g. label or choice) will have it''s own key in control weight dict with weight for each label and overall weight.For example, if bounding box annotation with control tag named my_bbox should be included with 0.33 weight in agreement calculation, and the first label Car should be twice more important than Airplaine, then you have to need the specify: {''my_bbox'': {''type'': ''RectangleLabels'', ''labels'': {''Car'': 1.0, ''Airplaine'': 0.5}, ''overall'': 0.33}'
- nullable: true
- created_by:
- allOf:
- - $ref: '#/components/schemas/UserSimpleRequest'
- description: Project owner
- description:
- description: Project description
- nullable: true
- type: string
- enable_empty_annotation:
- description: Allow annotators to submit empty annotations
- type: boolean
- evaluate_predictions_automatically:
- description: Retrieve and display predictions when loading a task
- type: boolean
- expert_instruction:
- description: Labeling instructions in HTML format
- nullable: true
- type: string
- is_draft:
- description: Whether or not the project is in the middle of being created
- type: boolean
- is_published:
- description: Whether or not the project is published to annotators
- title: Published
- type: boolean
- label_config:
- description: Label config in XML format. See more about it in documentation
- nullable: true
- type: string
- maximum_annotations:
- description: Maximum number of annotations for one task. If the number of annotations per task is equal or greater to this value, the task is completed (is_labeled=True)
- maximum: 2147483647
- minimum: -2147483648
- title: Maximum annotation number
- type: integer
- min_annotations_to_start_training:
- description: Minimum number of completed tasks after which model training is started
- maximum: 2147483647
- minimum: -2147483648
- type: integer
- model_version:
- description: Machine learning model version
- nullable: true
- type: string
- organization:
- nullable: true
- type: integer
- overlap_cohort_percentage:
- maximum: 2147483647
- minimum: -2147483648
- type: integer
- pinned_at:
- description: Pinned date and time
- format: date-time
- nullable: true
- type: string
- reveal_preannotations_interactively:
- description: Reveal pre-annotations interactively
- type: boolean
- sampling:
- nullable: true
- oneOf:
- - $ref: '#/components/schemas/SamplingDe5Enum'
- - $ref: '#/components/schemas/NullEnum'
- show_annotation_history:
- description: Show annotation history to annotator
- type: boolean
- show_collab_predictions:
- description: If set, the annotator can view model predictions
- title: Show predictions to annotator
- type: boolean
- show_ground_truth_first:
- description: 'Onboarding mode (true): show ground truth tasks first in the labeling stream'
- type: boolean
- show_instruction:
- description: Show instructions to the annotator before they start
- type: boolean
- show_overlap_first:
- type: boolean
- show_skip_button:
- description: Show a skip button in interface and allow annotators to skip the task
- type: boolean
- skip_queue:
- nullable: true
- oneOf:
- - $ref: '#/components/schemas/SkipQueueEnum'
- - $ref: '#/components/schemas/NullEnum'
- task_data_login:
- description: 'Task data credentials: login'
- maxLength: 256
- nullable: true
- type: string
- task_data_password:
- description: 'Task data credentials: password'
- maxLength: 256
- nullable: true
- type: string
- title:
- description: Project name. Must be between 3 and 50 characters long.
- maxLength: 50
- minLength: 3
- nullable: true
- type: string
- type: object
ProjectRole:
properties:
id:
@@ -32381,6 +32312,13 @@ components:
required:
- user
type: object
+ WorkspaceProjectsRequest:
+ properties:
+ project:
+ type: integer
+ required:
+ - project
+ type: object
WorkspaceRequest:
description: |-
A ModelSerializer that takes additional arguments for
diff --git a/poetry.lock b/poetry.lock
index 68ffc20ee..9fae6af33 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -2102,43 +2102,53 @@ files = [
[[package]]
name = "tomli"
-version = "2.2.1"
+version = "2.3.0"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.8"
files = [
- {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
- {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
- {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"},
- {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"},
- {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"},
- {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"},
- {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"},
- {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"},
- {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"},
- {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"},
- {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"},
- {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"},
- {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"},
- {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"},
- {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"},
- {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"},
- {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"},
- {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"},
- {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"},
- {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"},
- {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"},
- {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"},
- {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"},
- {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"},
- {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"},
- {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"},
- {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"},
- {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"},
- {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"},
- {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"},
- {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"},
- {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
+ {file = "tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45"},
+ {file = "tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba"},
+ {file = "tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf"},
+ {file = "tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441"},
+ {file = "tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845"},
+ {file = "tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c"},
+ {file = "tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456"},
+ {file = "tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be"},
+ {file = "tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac"},
+ {file = "tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22"},
+ {file = "tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f"},
+ {file = "tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52"},
+ {file = "tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8"},
+ {file = "tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6"},
+ {file = "tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876"},
+ {file = "tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878"},
+ {file = "tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b"},
+ {file = "tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae"},
+ {file = "tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b"},
+ {file = "tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf"},
+ {file = "tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f"},
+ {file = "tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05"},
+ {file = "tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606"},
+ {file = "tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999"},
+ {file = "tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e"},
+ {file = "tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3"},
+ {file = "tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc"},
+ {file = "tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0"},
+ {file = "tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879"},
+ {file = "tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005"},
+ {file = "tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463"},
+ {file = "tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8"},
+ {file = "tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77"},
+ {file = "tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf"},
+ {file = "tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530"},
+ {file = "tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b"},
+ {file = "tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67"},
+ {file = "tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f"},
+ {file = "tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0"},
+ {file = "tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba"},
+ {file = "tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b"},
+ {file = "tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549"},
]
[[package]]
@@ -2164,13 +2174,13 @@ telegram = ["requests"]
[[package]]
name = "types-python-dateutil"
-version = "2.9.0.20250822"
+version = "2.9.0.20251008"
description = "Typing stubs for python-dateutil"
optional = false
python-versions = ">=3.9"
files = [
- {file = "types_python_dateutil-2.9.0.20250822-py3-none-any.whl", hash = "sha256:849d52b737e10a6dc6621d2bd7940ec7c65fcb69e6aa2882acf4e56b2b508ddc"},
- {file = "types_python_dateutil-2.9.0.20250822.tar.gz", hash = "sha256:84c92c34bd8e68b117bff742bc00b692a1e8531262d4507b33afcc9f7716cd53"},
+ {file = "types_python_dateutil-2.9.0.20251008-py3-none-any.whl", hash = "sha256:b9a5232c8921cf7661b29c163ccc56055c418ab2c6eabe8f917cbcc73a4c4157"},
+ {file = "types_python_dateutil-2.9.0.20251008.tar.gz", hash = "sha256:c3826289c170c93ebd8360c3485311187df740166dbab9dd3b792e69f2bc1f9c"},
]
[[package]]
diff --git a/reference.md b/reference.md
index 851c3c47f..d6018ab86 100644
--- a/reference.md
+++ b/reference.md
@@ -29985,6 +29985,354 @@ client.organizations.permissions.update(
+
+
+
+
+## Projects Roles
+client.projects.roles.list(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+
+ List project roles for requested IDs for the current user
+
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from label_studio_sdk import LabelStudio
+
+client = LabelStudio(
+ api_key="YOUR_API_KEY",
+)
+client.projects.roles.list()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**ids:** `typing.Optional[int]`
+
+
+
+
+
+-
+
+**ordering:** `typing.Optional[str]` — Which field to use when ordering the results.
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.projects.roles.add(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+
+ Create project role for user allowing the user the same access level provided by organization role.
+
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from label_studio_sdk import LabelStudio
+
+client = LabelStudio(
+ api_key="YOUR_API_KEY",
+)
+client.projects.roles.add(
+ project=1,
+ role="OW",
+ user=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**project:** `int`
+
+
+
+
+
+-
+
+**role:** `Role9E7Enum`
+
+User role in project
+
+* `OW` - Owner
+* `AD` - Administrator
+* `MA` - Manager
+* `RE` - Reviewer
+* `AN` - Annotator
+* `DI` - Deactivated
+* `NO` - Not Activated
+
+
+
+
+
+-
+
+**user:** `int`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.projects.roles.remove(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+
+ Remove project role for user allowing the user the same access level provided by organization role.
+
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from label_studio_sdk import LabelStudio
+
+client = LabelStudio(
+ api_key="YOUR_API_KEY",
+)
+client.projects.roles.remove(
+ id=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**id:** `int` — A unique integer value identifying this project role.
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.projects.roles.get(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+
+ List users and their project level roles for a given project.
+ If user is not listed here and is a member of the project then they would behave as assigned role in organization.
+
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from label_studio_sdk import LabelStudio
+
+client = LabelStudio(
+ api_key="YOUR_API_KEY",
+)
+client.projects.roles.get(
+ id=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**id:** `int`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
@@ -30498,23 +30846,109 @@ client.projects.exports.convert(
-
-**export_pk:** `int` — Primary key identifying the export file.
-
-
-
-
-
--
-
-**id:** `int` — A unique integer value identifying this project.
-
-
-
-
-
--
-
-**export_type:** `str` — Export file format.
+**export_pk:** `int` — Primary key identifying the export file.
+
+
+
+
+
+-
+
+**id:** `int` — A unique integer value identifying this project.
+
+
+
+
+
+-
+
+**export_type:** `str` — Export file format.
+
+
+
+
+
+-
+
+**download_resources:** `typing.Optional[bool]` — Download resources in converter.
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Projects Members
+client.projects.members.add(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+Add a member to a specific project.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from label_studio_sdk import LabelStudio
+
+client = LabelStudio(
+ api_key="YOUR_API_KEY",
+)
+client.projects.members.add(
+ id=1,
+ user=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**id:** `int`
@@ -30522,7 +30956,7 @@ client.projects.exports.convert(
-
-**download_resources:** `typing.Optional[bool]` — Download resources in converter.
+**user:** `int`
@@ -30542,8 +30976,7 @@ client.projects.exports.convert(
-## Projects Members
-client.projects.members.get(...)
+client.projects.members.remove(...)
-
@@ -30561,7 +30994,7 @@ client.projects.exports.convert(
This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
-Retrieve the members for a specific project. Optionally filter by user IDs (comma-separated).
+Remove a member from a specific project.
@@ -30581,7 +31014,7 @@ from label_studio_sdk import LabelStudio
client = LabelStudio(
api_key="YOUR_API_KEY",
)
-client.projects.members.get(
+client.projects.members.remove(
id=1,
)
@@ -30607,14 +31040,6 @@ client.projects.members.get(
-
-**user_ids:** `typing.Optional[str]` — Comma-separated list of user IDs to include. Example: user_ids=1,2,3
-
-
-
-
-
--
-
**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -35742,6 +36167,244 @@ client.workspaces.members.delete(
+
+
+
+
+## Workspaces Projects
+client.workspaces.projects.list(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+Retrieve a list of all projects in a specific workspace.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from label_studio_sdk import LabelStudio
+
+client = LabelStudio(
+ api_key="YOUR_API_KEY",
+)
+client.workspaces.projects.list(
+ id=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**id:** `int`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.workspaces.projects.add(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+Add a project to a specific workspace.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from label_studio_sdk import LabelStudio
+
+client = LabelStudio(
+ api_key="YOUR_API_KEY",
+)
+client.workspaces.projects.add(
+ id=1,
+ project=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**id:** `int`
+
+
+
+
+
+-
+
+**project:** `int`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.workspaces.projects.remove(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+Remove a project from a specific workspace.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from label_studio_sdk import LabelStudio
+
+client = LabelStudio(
+ api_key="YOUR_API_KEY",
+)
+client.workspaces.projects.remove(
+ id=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**id:** `int`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
diff --git a/src/label_studio_sdk/__init__.py b/src/label_studio_sdk/__init__.py
index ee514b2de..6a1deb922 100644
--- a/src/label_studio_sdk/__init__.py
+++ b/src/label_studio_sdk/__init__.py
@@ -162,13 +162,18 @@
PauseRequest,
Prediction,
PredictionRequest,
+ Project,
ProjectGroup,
ProjectGroupRequest,
ProjectGroupRoleEnum,
ProjectImport,
ProjectLabelConfig,
ProjectLabelConfigRequest,
+ ProjectMember,
ProjectMemberBulkAssignRolesRequest,
+ ProjectRole,
+ ProjectSampling,
+ ProjectSkipQueue,
ProjectSubsetEnum,
ProjectSubsetItem,
ProjectSubsetTaskItem,
@@ -549,13 +554,18 @@
"PauseRequest",
"Prediction",
"PredictionRequest",
+ "Project",
"ProjectGroup",
"ProjectGroupRequest",
"ProjectGroupRoleEnum",
"ProjectImport",
"ProjectLabelConfig",
"ProjectLabelConfigRequest",
+ "ProjectMember",
"ProjectMemberBulkAssignRolesRequest",
+ "ProjectRole",
+ "ProjectSampling",
+ "ProjectSkipQueue",
"ProjectSubsetEnum",
"ProjectSubsetItem",
"ProjectSubsetTaskItem",
diff --git a/src/label_studio_sdk/projects/__init__.py b/src/label_studio_sdk/projects/__init__.py
index ab0b4d253..7242173d3 100644
--- a/src/label_studio_sdk/projects/__init__.py
+++ b/src/label_studio_sdk/projects/__init__.py
@@ -9,7 +9,7 @@
ProjectsImportPredictionsResponse,
ProjectsImportTasksResponse,
)
-from . import assignments, exports, members, metrics, pauses, stats
+from . import assignments, exports, members, metrics, pauses, roles, stats
from .assignments import (
AssignmentsAssignRequestType,
AssignmentsBulkAssignRequestFilters,
@@ -108,5 +108,6 @@
"members",
"metrics",
"pauses",
+ "roles",
"stats",
]
diff --git a/src/label_studio_sdk/projects/client.py b/src/label_studio_sdk/projects/client.py
index 1f6bf9548..1fdb4adb1 100644
--- a/src/label_studio_sdk/projects/client.py
+++ b/src/label_studio_sdk/projects/client.py
@@ -2,6 +2,7 @@
import typing
from ..core.client_wrapper import SyncClientWrapper
+from .roles.client import RolesClient
from .exports.client import ExportsClient
from .members.client import MembersClient
from .metrics.client import MetricsClient
@@ -39,6 +40,7 @@
from .types.projects_import_predictions_response import ProjectsImportPredictionsResponse
from ..types.project_label_config import ProjectLabelConfig
from ..core.client_wrapper import AsyncClientWrapper
+from .roles.client import AsyncRolesClient
from .exports.client import AsyncExportsClient
from .members.client import AsyncMembersClient
from .metrics.client import AsyncMetricsClient
@@ -54,6 +56,7 @@
class ProjectsClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
self._client_wrapper = client_wrapper
+ self.roles = RolesClient(client_wrapper=self._client_wrapper)
self.exports = ExportsClient(client_wrapper=self._client_wrapper)
self.members = MembersClient(client_wrapper=self._client_wrapper)
self.metrics = MetricsClient(client_wrapper=self._client_wrapper)
@@ -1237,6 +1240,7 @@ def validate_label_config(
class AsyncProjectsClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
self._client_wrapper = client_wrapper
+ self.roles = AsyncRolesClient(client_wrapper=self._client_wrapper)
self.exports = AsyncExportsClient(client_wrapper=self._client_wrapper)
self.members = AsyncMembersClient(client_wrapper=self._client_wrapper)
self.metrics = AsyncMetricsClient(client_wrapper=self._client_wrapper)
diff --git a/src/label_studio_sdk/projects/members/client.py b/src/label_studio_sdk/projects/members/client.py
index e74d5e1d1..2d0ee38b5 100644
--- a/src/label_studio_sdk/projects/members/client.py
+++ b/src/label_studio_sdk/projects/members/client.py
@@ -1,11 +1,11 @@
# This file was auto-generated by Fern from our API Definition.
+import typing
from ...core.client_wrapper import SyncClientWrapper
from .bulk.client import BulkClient
from .paginated.client import PaginatedClient
-import typing
from ...core.request_options import RequestOptions
-from ...types.lse_user import LseUser
+from ...types.project_member import ProjectMember
from ...core.jsonable_encoder import jsonable_encoder
from ...core.unchecked_base_model import construct_type
from json.decoder import JSONDecodeError
@@ -14,6 +14,9 @@
from .bulk.client import AsyncBulkClient
from .paginated.client import AsyncPaginatedClient
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
class MembersClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
@@ -21,9 +24,7 @@ def __init__(self, *, client_wrapper: SyncClientWrapper):
self.bulk = BulkClient(client_wrapper=self._client_wrapper)
self.paginated = PaginatedClient(client_wrapper=self._client_wrapper)
- def get(
- self, id: int, *, user_ids: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None
- ) -> typing.List[LseUser]:
+ def add(self, id: int, *, user: int, request_options: typing.Optional[RequestOptions] = None) -> ProjectMember:
"""
@@ -31,22 +32,21 @@ def get(
This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
- Retrieve the members for a specific project. Optionally filter by user IDs (comma-separated).
+ Add a member to a specific project.
Parameters
----------
id : int
- user_ids : typing.Optional[str]
- Comma-separated list of user IDs to include. Example: user_ids=1,2,3
+ user : int
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- typing.List[LseUser]
- List of users with membership information
+ ProjectMember
+
Examples
--------
@@ -55,24 +55,29 @@ def get(
client = LabelStudio(
api_key="YOUR_API_KEY",
)
- client.projects.members.get(
+ client.projects.members.add(
id=1,
+ user=1,
)
"""
_response = self._client_wrapper.httpx_client.request(
f"api/projects/{jsonable_encoder(id)}/members/",
- method="GET",
- params={
- "user_ids": user_ids,
+ method="POST",
+ json={
+ "user": user,
+ },
+ headers={
+ "content-type": "application/json",
},
request_options=request_options,
+ omit=OMIT,
)
try:
if 200 <= _response.status_code < 300:
return typing.cast(
- typing.List[LseUser],
+ ProjectMember,
construct_type(
- type_=typing.List[LseUser], # type: ignore
+ type_=ProjectMember, # type: ignore
object_=_response.json(),
),
)
@@ -81,6 +86,51 @@ def get(
raise ApiError(status_code=_response.status_code, body=_response.text)
raise ApiError(status_code=_response.status_code, body=_response_json)
+ def remove(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> None:
+ """
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+ Remove a member from a specific project.
+
+ Parameters
+ ----------
+ id : int
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ from label_studio_sdk import LabelStudio
+
+ client = LabelStudio(
+ api_key="YOUR_API_KEY",
+ )
+ client.projects.members.remove(
+ id=1,
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/projects/{jsonable_encoder(id)}/members/",
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
class AsyncMembersClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
@@ -88,9 +138,9 @@ def __init__(self, *, client_wrapper: AsyncClientWrapper):
self.bulk = AsyncBulkClient(client_wrapper=self._client_wrapper)
self.paginated = AsyncPaginatedClient(client_wrapper=self._client_wrapper)
- async def get(
- self, id: int, *, user_ids: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None
- ) -> typing.List[LseUser]:
+ async def add(
+ self, id: int, *, user: int, request_options: typing.Optional[RequestOptions] = None
+ ) -> ProjectMember:
"""
@@ -98,22 +148,21 @@ async def get(
This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
- Retrieve the members for a specific project. Optionally filter by user IDs (comma-separated).
+ Add a member to a specific project.
Parameters
----------
id : int
- user_ids : typing.Optional[str]
- Comma-separated list of user IDs to include. Example: user_ids=1,2,3
+ user : int
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- typing.List[LseUser]
- List of users with membership information
+ ProjectMember
+
Examples
--------
@@ -127,8 +176,9 @@ async def get(
async def main() -> None:
- await client.projects.members.get(
+ await client.projects.members.add(
id=1,
+ user=1,
)
@@ -136,18 +186,22 @@ async def main() -> None:
"""
_response = await self._client_wrapper.httpx_client.request(
f"api/projects/{jsonable_encoder(id)}/members/",
- method="GET",
- params={
- "user_ids": user_ids,
+ method="POST",
+ json={
+ "user": user,
+ },
+ headers={
+ "content-type": "application/json",
},
request_options=request_options,
+ omit=OMIT,
)
try:
if 200 <= _response.status_code < 300:
return typing.cast(
- typing.List[LseUser],
+ ProjectMember,
construct_type(
- type_=typing.List[LseUser], # type: ignore
+ type_=ProjectMember, # type: ignore
object_=_response.json(),
),
)
@@ -155,3 +209,56 @@ async def main() -> None:
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, body=_response.text)
raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def remove(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> None:
+ """
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+ Remove a member from a specific project.
+
+ Parameters
+ ----------
+ id : int
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+
+ from label_studio_sdk import AsyncLabelStudio
+
+ client = AsyncLabelStudio(
+ api_key="YOUR_API_KEY",
+ )
+
+
+ async def main() -> None:
+ await client.projects.members.remove(
+ id=1,
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/projects/{jsonable_encoder(id)}/members/",
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
diff --git a/src/label_studio_sdk/projects/roles/__init__.py b/src/label_studio_sdk/projects/roles/__init__.py
new file mode 100644
index 000000000..f3ea2659b
--- /dev/null
+++ b/src/label_studio_sdk/projects/roles/__init__.py
@@ -0,0 +1,2 @@
+# This file was auto-generated by Fern from our API Definition.
+
diff --git a/src/label_studio_sdk/projects/roles/client.py b/src/label_studio_sdk/projects/roles/client.py
new file mode 100644
index 000000000..9ab519f0d
--- /dev/null
+++ b/src/label_studio_sdk/projects/roles/client.py
@@ -0,0 +1,555 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from ...core.client_wrapper import SyncClientWrapper
+from ...core.request_options import RequestOptions
+from ...types.project_role import ProjectRole
+from ...core.unchecked_base_model import construct_type
+from json.decoder import JSONDecodeError
+from ...core.api_error import ApiError
+from ...types.role9e7enum import Role9E7Enum
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.client_wrapper import AsyncClientWrapper
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RolesClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def list(
+ self,
+ *,
+ ids: typing.Optional[int] = None,
+ ordering: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> typing.List[ProjectRole]:
+ """
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+
+ List project roles for requested IDs for the current user
+
+
+ Parameters
+ ----------
+ ids : typing.Optional[int]
+
+ ordering : typing.Optional[str]
+ Which field to use when ordering the results.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ typing.List[ProjectRole]
+
+
+ Examples
+ --------
+ from label_studio_sdk import LabelStudio
+
+ client = LabelStudio(
+ api_key="YOUR_API_KEY",
+ )
+ client.projects.roles.list()
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "api/projects/roles/",
+ method="GET",
+ params={
+ "ids": ids,
+ "ordering": ordering,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return typing.cast(
+ typing.List[ProjectRole],
+ construct_type(
+ type_=typing.List[ProjectRole], # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def add(
+ self, *, project: int, role: Role9E7Enum, user: int, request_options: typing.Optional[RequestOptions] = None
+ ) -> ProjectRole:
+ """
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+
+ Create project role for user allowing the user the same access level provided by organization role.
+
+
+ Parameters
+ ----------
+ project : int
+
+ role : Role9E7Enum
+ User role in project
+
+ * `OW` - Owner
+ * `AD` - Administrator
+ * `MA` - Manager
+ * `RE` - Reviewer
+ * `AN` - Annotator
+ * `DI` - Deactivated
+ * `NO` - Not Activated
+
+ user : int
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ProjectRole
+ Role created
+
+ Examples
+ --------
+ from label_studio_sdk import LabelStudio
+
+ client = LabelStudio(
+ api_key="YOUR_API_KEY",
+ )
+ client.projects.roles.add(
+ project=1,
+ role="OW",
+ user=1,
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "api/projects/roles/",
+ method="POST",
+ json={
+ "project": project,
+ "role": role,
+ "user": user,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return typing.cast(
+ ProjectRole,
+ construct_type(
+ type_=ProjectRole, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def remove(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> None:
+ """
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+
+ Remove project role for user allowing the user the same access level provided by organization role.
+
+
+ Parameters
+ ----------
+ id : int
+ A unique integer value identifying this project role.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ from label_studio_sdk import LabelStudio
+
+ client = LabelStudio(
+ api_key="YOUR_API_KEY",
+ )
+ client.projects.roles.remove(
+ id=1,
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/projects/roles/{jsonable_encoder(id)}/",
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def get(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> typing.List[ProjectRole]:
+ """
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+
+ List users and their project level roles for a given project.
+ If user is not listed here and is a member of the project then they would behave as assigned role in organization.
+
+
+ Parameters
+ ----------
+ id : int
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ typing.List[ProjectRole]
+
+
+ Examples
+ --------
+ from label_studio_sdk import LabelStudio
+
+ client = LabelStudio(
+ api_key="YOUR_API_KEY",
+ )
+ client.projects.roles.get(
+ id=1,
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/projects/{jsonable_encoder(id)}/roles",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return typing.cast(
+ typing.List[ProjectRole],
+ construct_type(
+ type_=typing.List[ProjectRole], # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+
+class AsyncRolesClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def list(
+ self,
+ *,
+ ids: typing.Optional[int] = None,
+ ordering: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> typing.List[ProjectRole]:
+ """
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+
+ List project roles for requested IDs for the current user
+
+
+ Parameters
+ ----------
+ ids : typing.Optional[int]
+
+ ordering : typing.Optional[str]
+ Which field to use when ordering the results.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ typing.List[ProjectRole]
+
+
+ Examples
+ --------
+ import asyncio
+
+ from label_studio_sdk import AsyncLabelStudio
+
+ client = AsyncLabelStudio(
+ api_key="YOUR_API_KEY",
+ )
+
+
+ async def main() -> None:
+ await client.projects.roles.list()
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "api/projects/roles/",
+ method="GET",
+ params={
+ "ids": ids,
+ "ordering": ordering,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return typing.cast(
+ typing.List[ProjectRole],
+ construct_type(
+ type_=typing.List[ProjectRole], # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def add(
+ self, *, project: int, role: Role9E7Enum, user: int, request_options: typing.Optional[RequestOptions] = None
+ ) -> ProjectRole:
+ """
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+
+ Create project role for user allowing the user the same access level provided by organization role.
+
+
+ Parameters
+ ----------
+ project : int
+
+ role : Role9E7Enum
+ User role in project
+
+ * `OW` - Owner
+ * `AD` - Administrator
+ * `MA` - Manager
+ * `RE` - Reviewer
+ * `AN` - Annotator
+ * `DI` - Deactivated
+ * `NO` - Not Activated
+
+ user : int
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ProjectRole
+ Role created
+
+ Examples
+ --------
+ import asyncio
+
+ from label_studio_sdk import AsyncLabelStudio
+
+ client = AsyncLabelStudio(
+ api_key="YOUR_API_KEY",
+ )
+
+
+ async def main() -> None:
+ await client.projects.roles.add(
+ project=1,
+ role="OW",
+ user=1,
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "api/projects/roles/",
+ method="POST",
+ json={
+ "project": project,
+ "role": role,
+ "user": user,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return typing.cast(
+ ProjectRole,
+ construct_type(
+ type_=ProjectRole, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def remove(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> None:
+ """
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+
+ Remove project role for user allowing the user the same access level provided by organization role.
+
+
+ Parameters
+ ----------
+ id : int
+ A unique integer value identifying this project role.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+
+ from label_studio_sdk import AsyncLabelStudio
+
+ client = AsyncLabelStudio(
+ api_key="YOUR_API_KEY",
+ )
+
+
+ async def main() -> None:
+ await client.projects.roles.remove(
+ id=1,
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/projects/roles/{jsonable_encoder(id)}/",
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def get(
+ self, id: int, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> typing.List[ProjectRole]:
+ """
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+
+ List users and their project level roles for a given project.
+ If user is not listed here and is a member of the project then they would behave as assigned role in organization.
+
+
+ Parameters
+ ----------
+ id : int
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ typing.List[ProjectRole]
+
+
+ Examples
+ --------
+ import asyncio
+
+ from label_studio_sdk import AsyncLabelStudio
+
+ client = AsyncLabelStudio(
+ api_key="YOUR_API_KEY",
+ )
+
+
+ async def main() -> None:
+ await client.projects.roles.get(
+ id=1,
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/projects/{jsonable_encoder(id)}/roles",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return typing.cast(
+ typing.List[ProjectRole],
+ construct_type(
+ type_=typing.List[ProjectRole], # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
diff --git a/src/label_studio_sdk/types/__init__.py b/src/label_studio_sdk/types/__init__.py
index 9ddd92acf..d4610a8fc 100644
--- a/src/label_studio_sdk/types/__init__.py
+++ b/src/label_studio_sdk/types/__init__.py
@@ -163,13 +163,18 @@
from .pause_request import PauseRequest
from .prediction import Prediction
from .prediction_request import PredictionRequest
+from .project import Project
from .project_group import ProjectGroup
from .project_group_request import ProjectGroupRequest
from .project_group_role_enum import ProjectGroupRoleEnum
from .project_import import ProjectImport
from .project_label_config import ProjectLabelConfig
from .project_label_config_request import ProjectLabelConfigRequest
+from .project_member import ProjectMember
from .project_member_bulk_assign_roles_request import ProjectMemberBulkAssignRolesRequest
+from .project_role import ProjectRole
+from .project_sampling import ProjectSampling
+from .project_skip_queue import ProjectSkipQueue
from .project_subset_enum import ProjectSubsetEnum
from .project_subset_item import ProjectSubsetItem
from .project_subset_task_item import ProjectSubsetTaskItem
@@ -400,13 +405,18 @@
"PauseRequest",
"Prediction",
"PredictionRequest",
+ "Project",
"ProjectGroup",
"ProjectGroupRequest",
"ProjectGroupRoleEnum",
"ProjectImport",
"ProjectLabelConfig",
"ProjectLabelConfigRequest",
+ "ProjectMember",
"ProjectMemberBulkAssignRolesRequest",
+ "ProjectRole",
+ "ProjectSampling",
+ "ProjectSkipQueue",
"ProjectSubsetEnum",
"ProjectSubsetItem",
"ProjectSubsetTaskItem",
diff --git a/src/label_studio_sdk/types/project.py b/src/label_studio_sdk/types/project.py
new file mode 100644
index 000000000..8cc0d394a
--- /dev/null
+++ b/src/label_studio_sdk/types/project.py
@@ -0,0 +1,198 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from ..core.unchecked_base_model import UncheckedBaseModel
+import typing
+import pydantic
+import datetime as dt
+from .user_simple import UserSimple
+from .project_sampling import ProjectSampling
+from .project_skip_queue import ProjectSkipQueue
+from ..core.pydantic_utilities import IS_PYDANTIC_V2
+
+
+class Project(UncheckedBaseModel):
+ """
+ Serializer get numbers from project queryset annotation,
+ make sure, that you use correct one(Project.objects.with_counts())
+ """
+
+ color: typing.Optional[str] = None
+ config_has_control_tags: bool = pydantic.Field()
+ """
+ Flag to detect is project ready for labeling
+ """
+
+ config_suitable_for_bulk_annotation: bool = pydantic.Field()
+ """
+ Flag to detect is project ready for bulk annotation
+ """
+
+ control_weights: typing.Optional[typing.Optional[typing.Any]] = None
+ created_at: dt.datetime
+ created_by: typing.Optional[UserSimple] = pydantic.Field(default=None)
+ """
+ Project owner
+ """
+
+ description: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Project description
+ """
+
+ enable_empty_annotation: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ Allow annotators to submit empty annotations
+ """
+
+ evaluate_predictions_automatically: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ Retrieve and display predictions when loading a task
+ """
+
+ expert_instruction: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Labeling instructions in HTML format
+ """
+
+ finished_task_number: int = pydantic.Field()
+ """
+ Finished tasks
+ """
+
+ ground_truth_number: int = pydantic.Field()
+ """
+ Honeypot annotation number in project
+ """
+
+ id: int
+ is_draft: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ Whether or not the project is in the middle of being created
+ """
+
+ is_published: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ Whether or not the project is published to annotators
+ """
+
+ label_config: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Label config in XML format. See more about it in documentation
+ """
+
+ maximum_annotations: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ Maximum number of annotations for one task. If the number of annotations per task is equal or greater to this value, the task is completed (is_labeled=True)
+ """
+
+ min_annotations_to_start_training: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ Minimum number of completed tasks after which model training is started
+ """
+
+ model_version: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Machine learning model version
+ """
+
+ num_tasks_with_annotations: int = pydantic.Field()
+ """
+ Tasks with annotations count
+ """
+
+ organization: typing.Optional[int] = None
+ overlap_cohort_percentage: typing.Optional[int] = None
+ parsed_label_config: typing.Optional[typing.Any] = None
+ pinned_at: typing.Optional[dt.datetime] = pydantic.Field(default=None)
+ """
+ Pinned date and time
+ """
+
+ queue_done: int
+ queue_total: int
+ reveal_preannotations_interactively: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ Reveal pre-annotations interactively
+ """
+
+ sampling: typing.Optional[ProjectSampling] = None
+ show_annotation_history: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ Show annotation history to annotator
+ """
+
+ show_collab_predictions: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ If set, the annotator can view model predictions
+ """
+
+ show_ground_truth_first: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ Onboarding mode (true): show ground truth tasks first in the labeling stream
+ """
+
+ show_instruction: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ Show instructions to the annotator before they start
+ """
+
+ show_overlap_first: typing.Optional[bool] = None
+ show_skip_button: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ Show a skip button in interface and allow annotators to skip the task
+ """
+
+ skip_queue: typing.Optional[ProjectSkipQueue] = None
+ skipped_annotations_number: int = pydantic.Field()
+ """
+ Skipped by collaborators annotation number in project
+ """
+
+ start_training_on_annotation_update: bool = pydantic.Field()
+ """
+ Start model training after any annotations are submitted or updated
+ """
+
+ task_data_login: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Task data credentials: login
+ """
+
+ task_data_password: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Task data credentials: password
+ """
+
+ task_number: int = pydantic.Field()
+ """
+ Total task number in project
+ """
+
+ title: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Project name. Must be between 3 and 50 characters long.
+ """
+
+ total_annotations_number: int = pydantic.Field()
+ """
+ Total annotations number in project including skipped_annotations_number and ground_truth_number.
+ """
+
+ total_predictions_number: int = pydantic.Field()
+ """
+ Total predictions number in project including skipped_annotations_number, ground_truth_number, and useful_annotation_number.
+ """
+
+ useful_annotation_number: int = pydantic.Field()
+ """
+ Useful annotation number in project not including skipped_annotations_number and ground_truth_number. Total annotations = annotation_number + skipped_annotations_number + ground_truth_number
+ """
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/label_studio_sdk/types/project_member.py b/src/label_studio_sdk/types/project_member.py
new file mode 100644
index 000000000..352202892
--- /dev/null
+++ b/src/label_studio_sdk/types/project_member.py
@@ -0,0 +1,19 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from ..core.unchecked_base_model import UncheckedBaseModel
+from ..core.pydantic_utilities import IS_PYDANTIC_V2
+import typing
+import pydantic
+
+
+class ProjectMember(UncheckedBaseModel):
+ user: int
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/label_studio_sdk/types/project_role.py b/src/label_studio_sdk/types/project_role.py
new file mode 100644
index 000000000..5479cac28
--- /dev/null
+++ b/src/label_studio_sdk/types/project_role.py
@@ -0,0 +1,35 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from ..core.unchecked_base_model import UncheckedBaseModel
+from .role9e7enum import Role9E7Enum
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2
+import typing
+
+
+class ProjectRole(UncheckedBaseModel):
+ id: int
+ project: int
+ role: Role9E7Enum = pydantic.Field()
+ """
+ User role in project
+
+ * `OW` - Owner
+ * `AD` - Administrator
+ * `MA` - Manager
+ * `RE` - Reviewer
+ * `AN` - Annotator
+ * `DI` - Deactivated
+ * `NO` - Not Activated
+ """
+
+ user: int
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/label_studio_sdk/types/project_sampling.py b/src/label_studio_sdk/types/project_sampling.py
new file mode 100644
index 000000000..a3aab25e4
--- /dev/null
+++ b/src/label_studio_sdk/types/project_sampling.py
@@ -0,0 +1,7 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from .sampling_de5enum import SamplingDe5Enum
+from .null_enum import NullEnum
+
+ProjectSampling = typing.Union[SamplingDe5Enum, NullEnum]
diff --git a/src/label_studio_sdk/types/project_skip_queue.py b/src/label_studio_sdk/types/project_skip_queue.py
new file mode 100644
index 000000000..7ef691ccc
--- /dev/null
+++ b/src/label_studio_sdk/types/project_skip_queue.py
@@ -0,0 +1,7 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from .skip_queue_enum import SkipQueueEnum
+from .null_enum import NullEnum
+
+ProjectSkipQueue = typing.Union[SkipQueueEnum, NullEnum]
diff --git a/src/label_studio_sdk/workspaces/__init__.py b/src/label_studio_sdk/workspaces/__init__.py
index ff24acaa4..21c06996f 100644
--- a/src/label_studio_sdk/workspaces/__init__.py
+++ b/src/label_studio_sdk/workspaces/__init__.py
@@ -1,5 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-from . import members
+from . import members, projects
-__all__ = ["members"]
+__all__ = ["members", "projects"]
diff --git a/src/label_studio_sdk/workspaces/client.py b/src/label_studio_sdk/workspaces/client.py
index f918737ab..0b9a6d7c3 100644
--- a/src/label_studio_sdk/workspaces/client.py
+++ b/src/label_studio_sdk/workspaces/client.py
@@ -3,6 +3,7 @@
import typing
from ..core.client_wrapper import SyncClientWrapper
from .members.client import MembersClient
+from .projects.client import ProjectsClient
from ..core.request_options import RequestOptions
from ..types.workspace import Workspace
from ..core.unchecked_base_model import construct_type
@@ -11,6 +12,7 @@
from ..core.jsonable_encoder import jsonable_encoder
from ..core.client_wrapper import AsyncClientWrapper
from .members.client import AsyncMembersClient
+from .projects.client import AsyncProjectsClient
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
@@ -20,6 +22,7 @@ class WorkspacesClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
self._client_wrapper = client_wrapper
self.members = MembersClient(client_wrapper=self._client_wrapper)
+ self.projects = ProjectsClient(client_wrapper=self._client_wrapper)
def list(
self,
@@ -358,6 +361,7 @@ class AsyncWorkspacesClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
self._client_wrapper = client_wrapper
self.members = AsyncMembersClient(client_wrapper=self._client_wrapper)
+ self.projects = AsyncProjectsClient(client_wrapper=self._client_wrapper)
async def list(
self,
diff --git a/src/label_studio_sdk/workspaces/projects/__init__.py b/src/label_studio_sdk/workspaces/projects/__init__.py
new file mode 100644
index 000000000..f3ea2659b
--- /dev/null
+++ b/src/label_studio_sdk/workspaces/projects/__init__.py
@@ -0,0 +1,2 @@
+# This file was auto-generated by Fern from our API Definition.
+
diff --git a/src/label_studio_sdk/workspaces/projects/client.py b/src/label_studio_sdk/workspaces/projects/client.py
new file mode 100644
index 000000000..40a700e42
--- /dev/null
+++ b/src/label_studio_sdk/workspaces/projects/client.py
@@ -0,0 +1,352 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from ...core.client_wrapper import SyncClientWrapper
+from ...core.request_options import RequestOptions
+from ...types.project import Project
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.unchecked_base_model import construct_type
+from json.decoder import JSONDecodeError
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class ProjectsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def list(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> typing.List[Project]:
+ """
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+ Retrieve a list of all projects in a specific workspace.
+
+ Parameters
+ ----------
+ id : int
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ typing.List[Project]
+ Projects list
+
+ Examples
+ --------
+ from label_studio_sdk import LabelStudio
+
+ client = LabelStudio(
+ api_key="YOUR_API_KEY",
+ )
+ client.workspaces.projects.list(
+ id=1,
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/workspaces/{jsonable_encoder(id)}/projects/",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return typing.cast(
+ typing.List[Project],
+ construct_type(
+ type_=typing.List[Project], # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def add(self, id: int, *, project: int, request_options: typing.Optional[RequestOptions] = None) -> None:
+ """
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+ Add a project to a specific workspace.
+
+ Parameters
+ ----------
+ id : int
+
+ project : int
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ from label_studio_sdk import LabelStudio
+
+ client = LabelStudio(
+ api_key="YOUR_API_KEY",
+ )
+ client.workspaces.projects.add(
+ id=1,
+ project=1,
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/workspaces/{jsonable_encoder(id)}/projects/",
+ method="POST",
+ json={
+ "project": project,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def remove(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> None:
+ """
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+ Remove a project from a specific workspace.
+
+ Parameters
+ ----------
+ id : int
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ from label_studio_sdk import LabelStudio
+
+ client = LabelStudio(
+ api_key="YOUR_API_KEY",
+ )
+ client.workspaces.projects.remove(
+ id=1,
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/workspaces/{jsonable_encoder(id)}/projects/",
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+
+class AsyncProjectsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def list(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> typing.List[Project]:
+ """
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+ Retrieve a list of all projects in a specific workspace.
+
+ Parameters
+ ----------
+ id : int
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ typing.List[Project]
+ Projects list
+
+ Examples
+ --------
+ import asyncio
+
+ from label_studio_sdk import AsyncLabelStudio
+
+ client = AsyncLabelStudio(
+ api_key="YOUR_API_KEY",
+ )
+
+
+ async def main() -> None:
+ await client.workspaces.projects.list(
+ id=1,
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/workspaces/{jsonable_encoder(id)}/projects/",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return typing.cast(
+ typing.List[Project],
+ construct_type(
+ type_=typing.List[Project], # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def add(self, id: int, *, project: int, request_options: typing.Optional[RequestOptions] = None) -> None:
+ """
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+ Add a project to a specific workspace.
+
+ Parameters
+ ----------
+ id : int
+
+ project : int
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+
+ from label_studio_sdk import AsyncLabelStudio
+
+ client = AsyncLabelStudio(
+ api_key="YOUR_API_KEY",
+ )
+
+
+ async def main() -> None:
+ await client.workspaces.projects.add(
+ id=1,
+ project=1,
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/workspaces/{jsonable_encoder(id)}/projects/",
+ method="POST",
+ json={
+ "project": project,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def remove(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> None:
+ """
+
+
+
+ This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
+
+
+ Remove a project from a specific workspace.
+
+ Parameters
+ ----------
+ id : int
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+
+ from label_studio_sdk import AsyncLabelStudio
+
+ client = AsyncLabelStudio(
+ api_key="YOUR_API_KEY",
+ )
+
+
+ async def main() -> None:
+ await client.workspaces.projects.remove(
+ id=1,
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/workspaces/{jsonable_encoder(id)}/projects/",
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
diff --git a/tests/projects/test_members.py b/tests/projects/test_members.py
index bc984ef0c..f132deae0 100644
--- a/tests/projects/test_members.py
+++ b/tests/projects/test_members.py
@@ -6,84 +6,24 @@
from ..utilities import validate_response
-async def test_get(client: LabelStudio, async_client: AsyncLabelStudio) -> None:
- expected_response: typing.Any = [
- {
- "active_organization": 1,
- "active_organization_meta": "active_organization_meta",
- "allow_newsletters": True,
- "avatar": "avatar",
- "custom_hotkeys": {"key": "value"},
- "date_joined": "2024-01-15T09:30:00Z",
- "email": "email",
- "first_name": "first_name",
- "id": 1,
- "initials": "initials",
- "last_activity": "2024-01-15T09:30:00Z",
- "last_name": "last_name",
- "lse_fields": {
- "email_notification_settings": "email_notification_settings",
- "invite_activated": True,
- "invite_expired": "invite_expired",
- "invite_expired_at": "invite_expired_at",
- "invited_at": "2024-01-15T09:30:00Z",
- "invited_by": 1,
- "onboarding_state": "not_started",
- "social_auth_finished": True,
- "trial_company": "trial_company",
- "trial_experience_labeling": "trial_experience_labeling",
- "trial_license_enterprise": True,
- "trial_models_in_production": "trial_models_in_production",
- "trial_role": "annotator",
- },
- "org_membership": [{"active": "active", "organization_id": 1, "role": "role"}],
- "organization_membership": {"active": "active", "organization_id": 1, "role": "role"},
- "pause": "pause",
- "phone": "phone",
- "username": "username",
- }
- ]
- expected_types: typing.Tuple[typing.Any, typing.Any] = (
- "list",
- {
- 0: {
- "active_organization": "integer",
- "active_organization_meta": None,
- "allow_newsletters": None,
- "avatar": None,
- "custom_hotkeys": None,
- "date_joined": "datetime",
- "email": None,
- "first_name": None,
- "id": "integer",
- "initials": None,
- "last_activity": "datetime",
- "last_name": None,
- "lse_fields": {
- "email_notification_settings": None,
- "invite_activated": None,
- "invite_expired": None,
- "invite_expired_at": None,
- "invited_at": "datetime",
- "invited_by": "integer",
- "onboarding_state": None,
- "social_auth_finished": None,
- "trial_company": None,
- "trial_experience_labeling": None,
- "trial_license_enterprise": None,
- "trial_models_in_production": None,
- "trial_role": None,
- },
- "org_membership": ("list", {0: {"active": None, "organization_id": "integer", "role": None}}),
- "organization_membership": {"active": None, "organization_id": "integer", "role": None},
- "pause": None,
- "phone": None,
- "username": None,
- }
- },
- )
- response = client.projects.members.get(id=1)
+async def test_add(client: LabelStudio, async_client: AsyncLabelStudio) -> None:
+ expected_response: typing.Any = {"user": 1}
+ expected_types: typing.Any = {"user": "integer"}
+ response = client.projects.members.add(id=1, user=1)
validate_response(response, expected_response, expected_types)
- async_response = await async_client.projects.members.get(id=1)
+ async_response = await async_client.projects.members.add(id=1, user=1)
validate_response(async_response, expected_response, expected_types)
+
+
+async def test_remove(client: LabelStudio, async_client: AsyncLabelStudio) -> None:
+ # Type ignore to avoid mypy complaining about the function not being meant to return a value
+ assert (
+ client.projects.members.remove(id=1) # type: ignore[func-returns-value]
+ is None
+ )
+
+ assert (
+ await async_client.projects.members.remove(id=1) # type: ignore[func-returns-value]
+ is None
+ )
diff --git a/tests/projects/test_roles.py b/tests/projects/test_roles.py
new file mode 100644
index 000000000..26355e74d
--- /dev/null
+++ b/tests/projects/test_roles.py
@@ -0,0 +1,55 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from label_studio_sdk import LabelStudio
+from label_studio_sdk import AsyncLabelStudio
+import typing
+from ..utilities import validate_response
+
+
+async def test_list_(client: LabelStudio, async_client: AsyncLabelStudio) -> None:
+ expected_response: typing.Any = [{"id": 1, "project": 1, "role": "OW", "user": 1}]
+ expected_types: typing.Tuple[typing.Any, typing.Any] = (
+ "list",
+ {0: {"id": "integer", "project": "integer", "role": None, "user": "integer"}},
+ )
+ response = client.projects.roles.list()
+ validate_response(response, expected_response, expected_types)
+
+ async_response = await async_client.projects.roles.list()
+ validate_response(async_response, expected_response, expected_types)
+
+
+async def test_add(client: LabelStudio, async_client: AsyncLabelStudio) -> None:
+ expected_response: typing.Any = {"id": 1, "project": 1, "role": "OW", "user": 1}
+ expected_types: typing.Any = {"id": "integer", "project": "integer", "role": None, "user": "integer"}
+ response = client.projects.roles.add(project=1, role="OW", user=1)
+ validate_response(response, expected_response, expected_types)
+
+ async_response = await async_client.projects.roles.add(project=1, role="OW", user=1)
+ validate_response(async_response, expected_response, expected_types)
+
+
+async def test_remove(client: LabelStudio, async_client: AsyncLabelStudio) -> None:
+ # Type ignore to avoid mypy complaining about the function not being meant to return a value
+ assert (
+ client.projects.roles.remove(id=1) # type: ignore[func-returns-value]
+ is None
+ )
+
+ assert (
+ await async_client.projects.roles.remove(id=1) # type: ignore[func-returns-value]
+ is None
+ )
+
+
+async def test_get(client: LabelStudio, async_client: AsyncLabelStudio) -> None:
+ expected_response: typing.Any = [{"id": 1, "project": 1, "role": "OW", "user": 1}]
+ expected_types: typing.Tuple[typing.Any, typing.Any] = (
+ "list",
+ {0: {"id": "integer", "project": "integer", "role": None, "user": "integer"}},
+ )
+ response = client.projects.roles.get(id=1)
+ validate_response(response, expected_response, expected_types)
+
+ async_response = await async_client.projects.roles.get(id=1)
+ validate_response(async_response, expected_response, expected_types)
diff --git a/tests/workspaces/test_projects.py b/tests/workspaces/test_projects.py
new file mode 100644
index 000000000..4b900858f
--- /dev/null
+++ b/tests/workspaces/test_projects.py
@@ -0,0 +1,145 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from label_studio_sdk import LabelStudio
+from label_studio_sdk import AsyncLabelStudio
+import typing
+from ..utilities import validate_response
+
+
+async def test_list_(client: LabelStudio, async_client: AsyncLabelStudio) -> None:
+ expected_response: typing.Any = [
+ {
+ "color": "color",
+ "config_has_control_tags": True,
+ "config_suitable_for_bulk_annotation": True,
+ "control_weights": {"key": "value"},
+ "created_at": "2024-01-15T09:30:00Z",
+ "created_by": {
+ "avatar": "avatar",
+ "email": "email",
+ "first_name": "first_name",
+ "id": 1,
+ "last_name": "last_name",
+ },
+ "description": "description",
+ "enable_empty_annotation": True,
+ "evaluate_predictions_automatically": True,
+ "expert_instruction": "expert_instruction",
+ "finished_task_number": 1,
+ "ground_truth_number": 1,
+ "id": 1,
+ "is_draft": True,
+ "is_published": True,
+ "label_config": "label_config",
+ "maximum_annotations": 1,
+ "min_annotations_to_start_training": 1,
+ "model_version": "model_version",
+ "num_tasks_with_annotations": 1,
+ "organization": 1,
+ "overlap_cohort_percentage": 1,
+ "parsed_label_config": {"key": "value"},
+ "pinned_at": "2024-01-15T09:30:00Z",
+ "queue_done": 1,
+ "queue_total": 1,
+ "reveal_preannotations_interactively": True,
+ "sampling": "Sequential sampling",
+ "show_annotation_history": True,
+ "show_collab_predictions": True,
+ "show_ground_truth_first": True,
+ "show_instruction": True,
+ "show_overlap_first": True,
+ "show_skip_button": True,
+ "skip_queue": "REQUEUE_FOR_ME",
+ "skipped_annotations_number": 1,
+ "start_training_on_annotation_update": True,
+ "task_data_login": "task_data_login",
+ "task_data_password": "task_data_password",
+ "task_number": 1,
+ "title": "title",
+ "total_annotations_number": 1,
+ "total_predictions_number": 1,
+ "useful_annotation_number": 1,
+ }
+ ]
+ expected_types: typing.Tuple[typing.Any, typing.Any] = (
+ "list",
+ {
+ 0: {
+ "color": None,
+ "config_has_control_tags": None,
+ "config_suitable_for_bulk_annotation": None,
+ "control_weights": None,
+ "created_at": "datetime",
+ "created_by": {"avatar": None, "email": None, "first_name": None, "id": "integer", "last_name": None},
+ "description": None,
+ "enable_empty_annotation": None,
+ "evaluate_predictions_automatically": None,
+ "expert_instruction": None,
+ "finished_task_number": "integer",
+ "ground_truth_number": "integer",
+ "id": "integer",
+ "is_draft": None,
+ "is_published": None,
+ "label_config": None,
+ "maximum_annotations": "integer",
+ "min_annotations_to_start_training": "integer",
+ "model_version": None,
+ "num_tasks_with_annotations": "integer",
+ "organization": "integer",
+ "overlap_cohort_percentage": "integer",
+ "parsed_label_config": None,
+ "pinned_at": "datetime",
+ "queue_done": "integer",
+ "queue_total": "integer",
+ "reveal_preannotations_interactively": None,
+ "sampling": None,
+ "show_annotation_history": None,
+ "show_collab_predictions": None,
+ "show_ground_truth_first": None,
+ "show_instruction": None,
+ "show_overlap_first": None,
+ "show_skip_button": None,
+ "skip_queue": None,
+ "skipped_annotations_number": "integer",
+ "start_training_on_annotation_update": None,
+ "task_data_login": None,
+ "task_data_password": None,
+ "task_number": "integer",
+ "title": None,
+ "total_annotations_number": "integer",
+ "total_predictions_number": "integer",
+ "useful_annotation_number": "integer",
+ }
+ },
+ )
+ response = client.workspaces.projects.list(id=1)
+ validate_response(response, expected_response, expected_types)
+
+ async_response = await async_client.workspaces.projects.list(id=1)
+ validate_response(async_response, expected_response, expected_types)
+
+
+async def test_add(client: LabelStudio, async_client: AsyncLabelStudio) -> None:
+ # Type ignore to avoid mypy complaining about the function not being meant to return a value
+ assert (
+ client.workspaces.projects.add(id=1, project=1) # type: ignore[func-returns-value]
+ is None
+ )
+
+ assert (
+ await async_client.workspaces.projects.add(id=1, project=1) # type: ignore[func-returns-value]
+ is None
+ )
+
+
+async def test_remove(client: LabelStudio, async_client: AsyncLabelStudio) -> None:
+ # Type ignore to avoid mypy complaining about the function not being meant to return a value
+ assert (
+ client.workspaces.projects.remove(id=1) # type: ignore[func-returns-value]
+ is None
+ )
+
+ assert (
+ await async_client.workspaces.projects.remove(id=1) # type: ignore[func-returns-value]
+ is None
+ )