From 30ee6ec98c0c43325f8d879c1ccb9e11f89d17bb Mon Sep 17 00:00:00 2001 From: fern-api <115122769+fern-api[bot]@users.noreply.github.com> Date: Fri, 19 Sep 2025 19:18:15 +0000 Subject: [PATCH 1/6] SDK regeneration --- .mock/definition/__package__.yml | 89 +- .mock/definition/organizations.yml | 2 +- .../definition/organizations/permissions.yml | 267 --- .mock/definition/projects/members.yml | 4 + .../definition/projects/members/paginated.yml | 4 + .mock/definition/projects/stats.yml | 355 ---- .mock/definition/stats.yml | 240 +++ .mock/definition/users.yml | 28 + .mock/definition/workspaces/members.yml | 4 + .../workspaces/members/paginated.yml | 4 + .mock/openapi/openapi.yaml | 573 +------ reference.md | 1475 ++--------------- src/label_studio_sdk/__init__.py | 10 +- .../organizations/__init__.py | 4 +- src/label_studio_sdk/organizations/client.py | 14 +- .../organizations/permissions/__init__.py | 2 - .../organizations/permissions/client.py | 1129 ------------- src/label_studio_sdk/projects/__init__.py | 28 - .../projects/stats/__init__.py | 28 - src/label_studio_sdk/projects/stats/client.py | 1047 +----------- .../projects/stats/types/__init__.py | 30 - .../stats_agreement_annotator_response.py | 26 - .../types/stats_data_filters_response.py | 23 - ...tats_data_filters_response_user_filters.py | 34 - ...ilters_response_user_filters_stats_item.py | 22 - .../types/stats_finished_tasks_response.py | 32 - .../stats/types/stats_lead_time_response.py | 23 - ...lead_time_response_lead_time_stats_item.py | 37 - ...ts_user_ground_truth_agreement_response.py | 20 - ...ound_truth_agreement_response_agreement.py | 5 - ...tats_user_prediction_agreement_response.py | 24 - ...e_average_prediction_agreement_per_user.py | 5 - .../types/stats_user_review_score_response.py | 22 - ...review_score_response_performance_score.py | 5 - ...user_review_score_response_review_score.py | 5 - src/label_studio_sdk/types/__init__.py | 10 +- .../types/configurable_permission_option.py | 25 - .../configurable_permission_option_default.py | 7 - src/label_studio_sdk/types/default_role.py | 4 +- .../types/default_role_enum.py | 5 + .../types/lse_organization.py | 4 +- src/label_studio_sdk/types/lse_user.py | 1 + src/label_studio_sdk/types/lse_user_api.py | 1 + .../types/organization_permission.py | 31 - .../types/organization_permission_request.py | 24 - .../types/paginated_project_member.py | 1 + src/label_studio_sdk/types/who_am_i_user.py | 1 + tests/organizations/test_permissions.py | 183 -- tests/projects/test_members.py | 2 + tests/projects/test_stats.py | 89 - tests/test_users.py | 14 + tests/workspaces/test_members.py | 2 + 52 files changed, 608 insertions(+), 5416 deletions(-) delete mode 100644 .mock/definition/organizations/permissions.yml delete mode 100644 src/label_studio_sdk/organizations/permissions/__init__.py delete mode 100644 src/label_studio_sdk/organizations/permissions/client.py delete mode 100644 src/label_studio_sdk/projects/stats/types/stats_agreement_annotator_response.py delete mode 100644 src/label_studio_sdk/projects/stats/types/stats_data_filters_response.py delete mode 100644 src/label_studio_sdk/projects/stats/types/stats_data_filters_response_user_filters.py delete mode 100644 src/label_studio_sdk/projects/stats/types/stats_data_filters_response_user_filters_stats_item.py delete mode 100644 src/label_studio_sdk/projects/stats/types/stats_finished_tasks_response.py delete mode 100644 src/label_studio_sdk/projects/stats/types/stats_lead_time_response.py delete mode 100644 src/label_studio_sdk/projects/stats/types/stats_lead_time_response_lead_time_stats_item.py delete mode 100644 src/label_studio_sdk/projects/stats/types/stats_user_ground_truth_agreement_response.py delete mode 100644 src/label_studio_sdk/projects/stats/types/stats_user_ground_truth_agreement_response_agreement.py delete mode 100644 src/label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response.py delete mode 100644 src/label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response_average_prediction_agreement_per_user.py delete mode 100644 src/label_studio_sdk/projects/stats/types/stats_user_review_score_response.py delete mode 100644 src/label_studio_sdk/projects/stats/types/stats_user_review_score_response_performance_score.py delete mode 100644 src/label_studio_sdk/projects/stats/types/stats_user_review_score_response_review_score.py delete mode 100644 src/label_studio_sdk/types/configurable_permission_option.py delete mode 100644 src/label_studio_sdk/types/configurable_permission_option_default.py create mode 100644 src/label_studio_sdk/types/default_role_enum.py delete mode 100644 src/label_studio_sdk/types/organization_permission.py delete mode 100644 src/label_studio_sdk/types/organization_permission_request.py delete mode 100644 tests/organizations/test_permissions.py diff --git a/.mock/definition/__package__.yml b/.mock/definition/__package__.yml index ee7522fc3..0fdf3e2fb 100644 --- a/.mock/definition/__package__.yml +++ b/.mock/definition/__package__.yml @@ -1620,23 +1620,6 @@ types: docs: Last updated time source: openapi: openapi/openapi.yaml - ConfigurablePermissionOptionDefault: - discriminated: false - union: - - Role9E7Enum - - NullEnum - source: - openapi: openapi/openapi.yaml - inline: true - ConfigurablePermissionOption: - properties: - default: optional - label: optional - options: list - permission: string - tooltip: optional - source: - openapi: openapi/openapi.yaml ConvertedFormat: properties: export_type: @@ -2177,7 +2160,7 @@ types: occurs, contact the LEAP team for assistance with enabling custom scripts. default_role: - type: optional + type: optional docs: |- Default membership role for invited users @@ -2211,6 +2194,25 @@ types: quick view. source: openapi: openapi/openapi.yaml + DefaultRoleEnum: + enum: + - OW + - AD + - MA + - RE + - AN + - DI + - 'NO' + docs: |- + * `OW` - Owner + * `AD` - Administrator + * `MA` - Manager + * `RE` - Reviewer + * `AN` - Annotator + * `DI` - Deactivated + * `NO` - Not Activated + source: + openapi: openapi/openapi.yaml EditionEnum: enum: - Community @@ -3602,7 +3604,7 @@ types: * `MA` - Manager custom_scripts_enabled: string default_role: - type: optional + type: optional docs: |- Default membership role for invited users @@ -5183,7 +5185,10 @@ types: validation: maxLength: 256 lse_fields: LseFields - org_membership: list + org_membership: + type: list + availability: deprecated + organization_membership: OrganizationMembership pause: string phone: type: optional @@ -5228,7 +5233,10 @@ types: type: optional validation: maxLength: 256 - org_membership: list + org_membership: + type: list + availability: deprecated + organization_membership: OrganizationMembership phone: type: optional validation: @@ -5696,35 +5704,6 @@ types: minLength: 1 source: openapi: openapi/openapi.yaml - OrganizationPermission: - properties: - default_role: string - id: integer - label: string - options: string - organization: integer - permission: - type: string - validation: - maxLength: 255 - roles: - type: optional> - docs: Explicit roles that have this permission within the organization. - tooltip: string - source: - openapi: openapi/openapi.yaml - OrganizationPermissionRequest: - properties: - permission: - type: string - validation: - minLength: 1 - maxLength: 255 - roles: - type: optional> - docs: Explicit roles that have this permission within the organization. - source: - openapi: openapi/openapi.yaml PaginatedAllRolesProjectListList: properties: count: integer @@ -5885,7 +5864,10 @@ types: validation: maxLength: 256 lse_fields: LseFields - org_membership: list + org_membership: + type: list + availability: deprecated + organization_membership: OrganizationMembership pause: string phone: type: optional @@ -7951,7 +7933,10 @@ types: validation: maxLength: 256 lse_fields: WhoAmILseFields - org_membership: list + org_membership: + type: list + availability: deprecated + organization_membership: OrganizationMembership pause: string permissions: list phone: diff --git a/.mock/definition/organizations.yml b/.mock/definition/organizations.yml index 4c0156410..59cba9e71 100644 --- a/.mock/definition/organizations.yml +++ b/.mock/definition/organizations.yml @@ -200,7 +200,7 @@ service: will be raised. If this occurs, contact the LEAP team for assistance with enabling custom scripts. default_role: - type: optional + type: optional docs: |- Default membership role for invited users diff --git a/.mock/definition/organizations/permissions.yml b/.mock/definition/organizations/permissions.yml deleted file mode 100644 index aaf7f88ca..000000000 --- a/.mock/definition/organizations/permissions.yml +++ /dev/null @@ -1,267 +0,0 @@ -imports: - root: ../__package__.yml -service: - auth: false - base-path: '' - endpoints: - list: - path: /api/organizations/{id}/permissions - method: GET - auth: true - docs: >- - List all organization-level permission overrides for a given - organization. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - display-name: List organization permission overrides - request: - name: PermissionsListRequest - query-parameters: - ordering: - type: optional - docs: Which field to use when ordering the results. - response: - docs: '' - type: list - examples: - - path-parameters: - id: 1 - response: - body: - - default_role: default_role - id: 1 - label: label - options: options - organization: 1 - permission: permission - roles: - - OW - tooltip: tooltip - audiences: - - public - create: - path: /api/organizations/{id}/permissions - method: POST - auth: true - docs: >- - Create a new organization-level permission override for a given - organization. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - display-name: Create organization permission override - request: - body: root.OrganizationPermissionRequest - content-type: application/json - response: - docs: '' - type: root.OrganizationPermission - errors: - - root.BadRequestError - - root.ForbiddenError - examples: - - path-parameters: - id: 1 - request: - permission: permission - response: - body: - default_role: default_role - id: 1 - label: label - options: options - organization: 1 - permission: permission - roles: - - OW - tooltip: tooltip - audiences: - - public - get_options: - path: /api/organizations/{id}/permissions/options - method: GET - auth: true - docs: >- - Retrieve the list of configurable permission options (label, tooltip, - default role and allowed roles). - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - display-name: Get configurable permissions options - request: - name: PermissionsGetOptionsRequest - query-parameters: - ordering: - type: optional - docs: Which field to use when ordering the results. - response: - docs: '' - type: list - examples: - - path-parameters: - id: 1 - response: - body: - - default: OW - label: label - options: - - OW - permission: permission - tooltip: tooltip - audiences: - - public - get: - path: /api/organizations/{id}/permissions/{permission} - method: GET - auth: true - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - permission: string - display-name: Retrieve organization permission override - response: - docs: '' - type: root.OrganizationPermission - errors: - - root.ForbiddenError - - root.NotFoundError - examples: - - path-parameters: - id: 1 - permission: permission - response: - body: - default_role: default_role - id: 1 - label: label - options: options - organization: 1 - permission: permission - roles: - - OW - tooltip: tooltip - audiences: - - public - replace: - path: /api/organizations/{id}/permissions/{permission} - method: PUT - auth: true - docs: >- - Replace the organization-level permission override for a given - permission key. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: - type: integer - docs: A unique integer value identifying this organization. - permission: - type: string - docs: Permission key to update within the organization. - display-name: Replace organization permission override - request: - body: root.OrganizationPermissionRequest - content-type: application/json - response: - docs: '' - type: root.OrganizationPermission - errors: - - root.BadRequestError - - root.ForbiddenError - - root.NotFoundError - examples: - - path-parameters: - id: 1 - permission: permission - request: - permission: permission - response: - body: - default_role: default_role - id: 1 - label: label - options: options - organization: 1 - permission: permission - roles: - - OW - tooltip: tooltip - audiences: - - public - delete: - path: /api/organizations/{id}/permissions/{permission} - method: DELETE - auth: true - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - permission: string - display-name: Delete organization permission override - errors: - - root.ForbiddenError - - root.NotFoundError - examples: - - path-parameters: - id: 1 - permission: permission - audiences: - - public - update: - path: /api/organizations/{id}/permissions/{permission} - method: PATCH - auth: true - docs: >- - Partially update the organization-level permission override for a given - permission key. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - permission: string - display-name: Update organization permission override - request: - name: PatchedOrganizationPermissionRequest - body: - properties: - permission: - type: optional - name: patchedOrganizationPermissionRequestPermission - roles: - type: optional> - docs: >- - Explicit roles that have this permission within the - organization. - content-type: application/json - response: - docs: '' - type: root.OrganizationPermission - errors: - - root.BadRequestError - - root.ForbiddenError - - root.NotFoundError - examples: - - path-parameters: - id: 1 - permission: permission - request: {} - response: - body: - default_role: default_role - id: 1 - label: label - options: options - organization: 1 - permission: permission - roles: - - OW - tooltip: tooltip - audiences: - - public - source: - openapi: openapi/openapi.yaml diff --git a/.mock/definition/projects/members.yml b/.mock/definition/projects/members.yml index 18cf1eb9b..28a690e28 100644 --- a/.mock/definition/projects/members.yml +++ b/.mock/definition/projects/members.yml @@ -63,6 +63,10 @@ service: - active: active organization_id: 1 role: role + organization_membership: + active: active + organization_id: 1 + role: role pause: pause phone: phone username: username diff --git a/.mock/definition/projects/members/paginated.yml b/.mock/definition/projects/members/paginated.yml index 0e94dad81..8c58997d0 100644 --- a/.mock/definition/projects/members/paginated.yml +++ b/.mock/definition/projects/members/paginated.yml @@ -76,6 +76,10 @@ service: - active: active organization_id: 1 role: role + organization_membership: + active: active + organization_id: 1 + role: role pause: pause phone: phone project_role: project_role diff --git a/.mock/definition/projects/stats.yml b/.mock/definition/projects/stats.yml index ecf24f8d4..d8c8e4e92 100644 --- a/.mock/definition/projects/stats.yml +++ b/.mock/definition/projects/stats.yml @@ -61,77 +61,6 @@ types: docs: List of users in the matrix source: openapi: openapi/openapi.yaml - StatsAgreementAnnotatorResponse: - properties: - Agreement_per_annotator: - type: optional - docs: Agreement score for the annotator (0-1) - source: - openapi: openapi/openapi.yaml - StatsDataFiltersResponseUserFiltersStatsItem: - properties: - id: - type: optional - docs: User ID or model version identifier (e.g., "model:1.0") - source: - openapi: openapi/openapi.yaml - inline: true - StatsDataFiltersResponseUserFilters: - docs: Data filter statistics by user and model - properties: - stats: - type: optional> - docs: List of filter configurations for users and models - tasks_with_annotations: - type: optional> - docs: Default filter tab for tasks with annotations - source: - openapi: openapi/openapi.yaml - inline: true - StatsDataFiltersResponse: - properties: - user_filters: - type: optional - docs: Data filter statistics by user and model - source: - openapi: openapi/openapi.yaml - StatsFinishedTasksResponse: - properties: - finished: - type: optional - docs: Number of finished tasks - id: - type: optional - docs: User ID - progress: - type: optional - docs: Progress percentage (0-100) - source: - openapi: openapi/openapi.yaml - StatsLeadTimeResponseLeadTimeStatsItem: - properties: - mean_time: - type: optional - docs: Average lead time for the user - median_time: - type: optional - docs: Median lead time for the user - sum_lead_time: - type: optional - docs: Total lead time for the user - user_id: - type: optional - docs: User ID - source: - openapi: openapi/openapi.yaml - inline: true - StatsLeadTimeResponse: - properties: - lead_time_stats: - type: optional> - docs: Lead time statistics including mean, median, and distribution - source: - openapi: openapi/openapi.yaml StatsTotalAgreementResponseZero: properties: total_agreement: optional @@ -151,67 +80,6 @@ types: - StatsTotalAgreementResponseOne source: openapi: openapi/openapi.yaml - StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser: - discriminated: false - union: - - type: double - docs: >- - Average prediction agreement score for the user (0-1) when - per_label=False - - type: map - docs: >- - Average prediction agreement score per label for the user (0-1) when - per_label=True - source: - openapi: openapi/openapi.yaml - inline: true - StatsUserPredictionAgreementResponse: - properties: - average_prediction_agreement_per_user: >- - optional - source: - openapi: openapi/openapi.yaml - StatsUserReviewScoreResponsePerformanceScore: - discriminated: false - union: - - type: double - docs: Performance score for the user when per_label=False - - type: map - docs: Performance score per label for the user when per_label=True - source: - openapi: openapi/openapi.yaml - inline: true - StatsUserReviewScoreResponseReviewScore: - discriminated: false - union: - - type: double - docs: Average review score for the user when per_label=False - - type: map - docs: Average review score per label for the user when per_label=True - source: - openapi: openapi/openapi.yaml - inline: true - StatsUserReviewScoreResponse: - properties: - performance_score: optional - review_score: optional - source: - openapi: openapi/openapi.yaml - StatsUserGroundTruthAgreementResponseAgreement: - discriminated: false - union: - - type: double - docs: Ground truth agreement score for the user (0-1) when per_label=False - - type: map - docs: Ground truth agreement scores per label when per_label=True - source: - openapi: openapi/openapi.yaml - inline: true - StatsUserGroundTruthAgreementResponse: - properties: - agreement: optional - source: - openapi: openapi/openapi.yaml service: auth: false base-path: '' @@ -307,110 +175,6 @@ service: id: 2 audiences: - public - agreement_annotator: - path: /api/projects/{id}/stats/agreement_annotator/{user_id} - method: GET - auth: true - docs: Get agreement statistics for a specific annotator within a project. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - user_id: integer - display-name: Get individual annotator agreement stats - response: - docs: Individual annotator agreement statistics - type: StatsAgreementAnnotatorResponse - examples: - - path-parameters: - id: 1 - user_id: 1 - response: - body: - Agreement_per_annotator: 1.1 - audiences: - - public - data_filters: - path: /api/projects/{id}/stats/data_filter - method: GET - auth: true - docs: Get statistics about user data filters and their usage within a project. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - display-name: Get user data filter statistics - response: - docs: User data filter statistics - type: StatsDataFiltersResponse - examples: - - path-parameters: - id: 1 - response: - body: - user_filters: - stats: - - {} - tasks_with_annotations: - key: value - audiences: - - public - finished_tasks: - path: /api/projects/{id}/stats/finished - method: GET - auth: true - docs: Get statistics about finished tasks for a project. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - display-name: Get finished tasks statistics - request: - name: StatsFinishedTasksRequest - query-parameters: - user_pk: - type: optional - docs: User ID to filter statistics by (optional) - response: - docs: Finished tasks statistics - type: StatsFinishedTasksResponse - examples: - - path-parameters: - id: 1 - response: - body: - finished: 1 - id: 1 - progress: 1 - audiences: - - public - lead_time: - path: /api/projects/{id}/stats/lead_time - method: GET - auth: true - docs: >- - Get lead time statistics across the project, including average - annotation time. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - display-name: Get lead time statistics - response: - docs: Lead time statistics - type: StatsLeadTimeResponse - examples: - - path-parameters: - id: 1 - response: - body: - lead_time_stats: - - mean_time: 1.1 - median_time: 1.1 - sum_lead_time: 1.1 - user_id: 1 - audiences: - - public total_agreement: path: /api/projects/{id}/stats/total_agreement method: GET @@ -444,124 +208,5 @@ service: total_agreement: 1.1 audiences: - public - update_stats: - path: /api/projects/{id}/update-stats - method: GET - auth: true - docs: Start stats recalculation for given project - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - display-name: Start stats recalculation - request: - name: StatsUpdateStatsRequest - query-parameters: - stat_type: - type: optional - docs: 'Stat type to recalculate. Possible values: label, stats' - response: - docs: Successful response returns job id - type: map - examples: - - path-parameters: - id: 1 - response: - body: - key: value - audiences: - - public - user_prediction_agreement: - path: /api/projects/{id}/user-stats/{user_pk}/prediction - method: GET - auth: true - docs: >- - Get prediction agreement statistics for a specific user within a - project. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - user_pk: integer - display-name: Get individual user prediction agreement - request: - name: StatsUserPredictionAgreementRequest - query-parameters: - per_label: - type: optional - docs: Calculate agreement per label - response: - docs: Individual user prediction agreement statistics - type: StatsUserPredictionAgreementResponse - examples: - - path-parameters: - id: 1 - user_pk: 1 - response: - body: - average_prediction_agreement_per_user: 1.1 - audiences: - - public - user_review_score: - path: /api/projects/{id}/user-stats/{user_pk}/review_score - method: GET - auth: true - docs: Get review score statistics for a specific user within a project. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - user_pk: integer - display-name: Get individual user review scores - request: - name: StatsUserReviewScoreRequest - query-parameters: - per_label: - type: optional - docs: Calculate agreement per label - response: - docs: Individual user review score statistics - type: StatsUserReviewScoreResponse - examples: - - path-parameters: - id: 1 - user_pk: 1 - response: - body: - performance_score: 1.1 - review_score: 1.1 - audiences: - - public - user_ground_truth_agreement: - path: /api/projects/{id}/users/{user_pk}/stats/agreement-groundtruth - method: GET - auth: true - docs: >- - Get ground truth agreement statistics for a specific user within a - project. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - user_pk: integer - display-name: Get individual user ground truth agreement - request: - name: StatsUserGroundTruthAgreementRequest - query-parameters: - per_label: - type: optional - docs: Calculate agreement per label - response: - docs: Individual user ground truth agreement statistics - type: StatsUserGroundTruthAgreementResponse - examples: - - path-parameters: - id: 1 - user_pk: 1 - response: - body: - agreement: 1.1 - audiences: - - public source: openapi: openapi/openapi.yaml diff --git a/.mock/definition/stats.yml b/.mock/definition/stats.yml index 6c150e67c..f8d3fc6d6 100644 --- a/.mock/definition/stats.yml +++ b/.mock/definition/stats.yml @@ -14,6 +14,58 @@ types: average_prediction_agreement_per_model: optional source: openapi: openapi/openapi.yaml + ApiProjectsStatsAgreementAnnotatorRetrieveResponse: + properties: + Agreement_per_annotator: + type: optional + docs: Agreement score for the annotator (0-1) + source: + openapi: openapi/openapi.yaml + ApiProjectsStatsDataFilterRetrieveResponse: + properties: + filters: + type: optional> + docs: Data filter statistics by user + source: + openapi: openapi/openapi.yaml + ApiProjectsStatsFinishedRetrieveResponse: + properties: + finished_tasks: + type: optional + docs: Number of finished tasks + progress: + type: optional + docs: Progress percentage (0-100) + source: + openapi: openapi/openapi.yaml + ApiProjectsStatsLeadTimeRetrieveResponse: + properties: + lead_time: + type: optional> + docs: Lead time statistics including mean, median, and distribution + source: + openapi: openapi/openapi.yaml + ApiProjectsUserStatsPredictionRetrieveResponse: + properties: + average_prediction_agreement_per_user: + type: optional + docs: Average prediction agreement score for the user (0-1) + source: + openapi: openapi/openapi.yaml + ApiProjectsUserStatsReviewScoreRetrieveResponse: + properties: + review_score: + type: optional + docs: Average review score for the user + source: + openapi: openapi/openapi.yaml + ApiProjectsUsersStatsAgreementGroundtruthRetrieveResponse: + properties: + agreement: + type: optional + docs: Ground truth agreement score for the user (0-1) + source: + openapi: openapi/openapi.yaml service: auth: false base-path: '' @@ -128,5 +180,193 @@ service: response: body: average_prediction_agreement_per_model: 1.1 + api_projects_stats_agreement_annotator_retrieve: + path: /api/projects/{id}/stats/agreement_annotator/{user_id} + method: GET + auth: true + docs: Get agreement statistics for a specific annotator within a project. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + user_id: integer + display-name: Get individual annotator agreement stats + request: + name: ApiProjectsStatsAgreementAnnotatorRetrieveRequest + query-parameters: + per_label: + type: optional + default: false + docs: Calculate agreement per label + response: + docs: Individual annotator agreement statistics + type: ApiProjectsStatsAgreementAnnotatorRetrieveResponse + examples: + - path-parameters: + id: 1 + user_id: 1 + response: + body: + Agreement_per_annotator: 1.1 + api_projects_stats_data_filter_retrieve: + path: /api/projects/{id}/stats/data_filter + method: GET + auth: true + docs: Get statistics about user data filters and their usage within a project. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + display-name: Get user data filter statistics + response: + docs: User data filter statistics + type: ApiProjectsStatsDataFilterRetrieveResponse + examples: + - path-parameters: + id: 1 + response: + body: + filters: + key: value + api_projects_stats_finished_retrieve: + path: /api/projects/{id}/stats/finished + method: GET + auth: true + docs: Get statistics about finished tasks for a project. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + display-name: Get finished tasks statistics + request: + name: ApiProjectsStatsFinishedRetrieveRequest + query-parameters: + user_pk: + type: optional + docs: User ID to filter statistics by (optional) + response: + docs: Finished tasks statistics + type: ApiProjectsStatsFinishedRetrieveResponse + examples: + - path-parameters: + id: 1 + response: + body: + finished_tasks: 1 + progress: 1.1 + api_projects_stats_lead_time_retrieve: + path: /api/projects/{id}/stats/lead_time + method: GET + auth: true + docs: >- + Get lead time statistics across the project, including average + annotation time. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + display-name: Get lead time statistics + response: + docs: Lead time statistics + type: ApiProjectsStatsLeadTimeRetrieveResponse + examples: + - path-parameters: + id: 1 + response: + body: + lead_time: + key: value + api_projects_update_stats_retrieve: + path: /api/projects/{id}/update-stats + method: GET + auth: true + docs: Start stats recalculation for given project + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + display-name: Start stats recalculation + request: + name: ApiProjectsUpdateStatsRetrieveRequest + query-parameters: + stat_type: + type: optional + docs: 'Stat type to recalculate. Possible values: label, stats' + response: + docs: Successful response returns job id + type: map + examples: + - path-parameters: + id: 1 + response: + body: + key: value + api_projects_user_stats_prediction_retrieve: + path: /api/projects/{id}/user-stats/{user_pk}/prediction + method: GET + auth: true + docs: >- + Get prediction agreement statistics for a specific user within a + project. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + user_pk: integer + display-name: Get individual user prediction agreement + response: + docs: Individual user prediction agreement statistics + type: ApiProjectsUserStatsPredictionRetrieveResponse + examples: + - path-parameters: + id: 1 + user_pk: 1 + response: + body: + average_prediction_agreement_per_user: 1.1 + api_projects_user_stats_review_score_retrieve: + path: /api/projects/{id}/user-stats/{user_pk}/review_score + method: GET + auth: true + docs: Get review score statistics for a specific user within a project. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + user_pk: integer + display-name: Get individual user review scores + response: + docs: Individual user review score statistics + type: ApiProjectsUserStatsReviewScoreRetrieveResponse + examples: + - path-parameters: + id: 1 + user_pk: 1 + response: + body: + review_score: 1.1 + api_projects_users_stats_agreement_groundtruth_retrieve: + path: /api/projects/{id}/users/{user_pk}/stats/agreement-groundtruth + method: GET + auth: true + docs: >- + Get ground truth agreement statistics for a specific user within a + project. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + user_pk: integer + display-name: Get individual user ground truth agreement + response: + docs: Individual user ground truth agreement statistics + type: ApiProjectsUsersStatsAgreementGroundtruthRetrieveResponse + examples: + - path-parameters: + id: 1 + user_pk: 1 + response: + body: + agreement: 1.1 source: openapi: openapi/openapi.yaml diff --git a/.mock/definition/users.yml b/.mock/definition/users.yml index 6ab21bb9f..e39a8f8c0 100644 --- a/.mock/definition/users.yml +++ b/.mock/definition/users.yml @@ -35,6 +35,10 @@ service: - active: active organization_id: 1 role: role + organization_membership: + active: active + organization_id: 1 + role: role phone: phone username: username audiences: @@ -109,6 +113,10 @@ service: - active: active organization_id: 1 role: role + organization_membership: + active: active + organization_id: 1 + role: role phone: phone username: username audiences: @@ -236,6 +244,10 @@ service: - active: active organization_id: 1 role: role + organization_membership: + active: active + organization_id: 1 + role: role pause: pause permissions: - permissions @@ -280,6 +292,10 @@ service: - active: active organization_id: 1 role: role + organization_membership: + active: active + organization_id: 1 + role: role phone: phone username: username audiences: @@ -362,6 +378,10 @@ service: - active: active organization_id: 1 role: role + organization_membership: + active: active + organization_id: 1 + role: role pause: pause phone: phone username: username @@ -418,6 +438,10 @@ service: - active: active organization_id: 1 role: role + organization_membership: + active: active + organization_id: 1 + role: role pause: pause phone: phone username: username @@ -535,6 +559,10 @@ service: - active: active organization_id: 1 role: role + organization_membership: + active: active + organization_id: 1 + role: role pause: pause phone: phone username: username diff --git a/.mock/definition/workspaces/members.yml b/.mock/definition/workspaces/members.yml index f48b32497..f6040d58a 100644 --- a/.mock/definition/workspaces/members.yml +++ b/.mock/definition/workspaces/members.yml @@ -44,6 +44,10 @@ service: - active: active organization_id: 1 role: role + organization_membership: + active: active + organization_id: 1 + role: role pause: pause phone: phone username: username diff --git a/.mock/definition/workspaces/members/paginated.yml b/.mock/definition/workspaces/members/paginated.yml index a1b4e8da2..eed953f6d 100644 --- a/.mock/definition/workspaces/members/paginated.yml +++ b/.mock/definition/workspaces/members/paginated.yml @@ -65,6 +65,10 @@ service: - active: active organization_id: 1 role: role + organization_membership: + active: active + organization_id: 1 + role: role pause: pause phone: phone username: username diff --git a/.mock/openapi/openapi.yaml b/.mock/openapi/openapi.yaml index d0d1b6b2d..7dc9046fd 100644 --- a/.mock/openapi/openapi.yaml +++ b/.mock/openapi/openapi.yaml @@ -5449,296 +5449,6 @@ paths: - organizations - members x-fern-sdk-method-name: get - /api/organizations/{id}/permissions: - get: - description: List all organization-level permission overrides for a given organization. - operationId: api_organizations_permissions_list - parameters: - - in: path - name: id - required: true - schema: - type: integer - - description: Which field to use when ordering the results. - in: query - name: ordering - required: false - schema: - type: string - responses: - '200': - content: - application/json: - schema: - items: - $ref: '#/components/schemas/OrganizationPermission' - type: array - description: '' - security: - - Token: [] - summary: List organization permission overrides - tags: - - Organizations - - Permissions - x-fern-audiences: - - public - x-fern-sdk-group-name: - - organizations - - permissions - x-fern-sdk-method-name: list - post: - description: Create a new organization-level permission override for a given organization. - operationId: api_organizations_permissions_create - parameters: - - in: path - name: id - required: true - schema: - type: integer - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/OrganizationPermissionRequest' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/OrganizationPermissionRequest' - multipart/form-data: - schema: - $ref: '#/components/schemas/OrganizationPermissionRequest' - required: true - responses: - '200': - content: - application/json: - schema: - $ref: '#/components/schemas/OrganizationPermission' - description: '' - '400': - description: Bad Request - '403': - description: Permission Denied - security: - - Token: [] - summary: Create organization permission override - tags: - - Organizations - - Permissions - x-fern-audiences: - - public - x-fern-sdk-group-name: - - organizations - - permissions - x-fern-sdk-method-name: create - /api/organizations/{id}/permissions/options: - get: - description: Retrieve the list of configurable permission options (label, tooltip, default role and allowed roles). - operationId: api_organizations_permissions_options_list - parameters: - - in: path - name: id - required: true - schema: - type: integer - - description: Which field to use when ordering the results. - in: query - name: ordering - required: false - schema: - type: string - responses: - '200': - content: - application/json: - schema: - items: - $ref: '#/components/schemas/ConfigurablePermissionOption' - type: array - description: '' - security: - - Token: [] - summary: Get configurable permissions options - tags: - - Organizations - - Permissions - x-fern-audiences: - - public - x-fern-sdk-group-name: - - organizations - - permissions - x-fern-sdk-method-name: get_options - /api/organizations/{id}/permissions/{permission}: - delete: - operationId: api_organizations_permissions_destroy - parameters: - - in: path - name: id - required: true - schema: - type: integer - - in: path - name: permission - required: true - schema: - type: string - responses: - '204': - description: Deleted - '403': - description: Permission Denied - '404': - description: Permission not found for organization - security: - - Token: [] - summary: Delete organization permission override - tags: - - Organizations - - Permissions - x-fern-audiences: - - public - x-fern-sdk-group-name: - - organizations - - permissions - x-fern-sdk-method-name: delete - get: - operationId: api_organizations_permissions_retrieve - parameters: - - in: path - name: id - required: true - schema: - type: integer - - in: path - name: permission - required: true - schema: - type: string - responses: - '200': - content: - application/json: - schema: - $ref: '#/components/schemas/OrganizationPermission' - description: '' - '403': - description: Permission Denied - '404': - description: Permission not found for organization - security: - - Token: [] - summary: Retrieve organization permission override - tags: - - Organizations - - Permissions - x-fern-audiences: - - public - x-fern-sdk-group-name: - - organizations - - permissions - x-fern-sdk-method-name: get - patch: - description: Partially update the organization-level permission override for a given permission key. - operationId: api_organizations_permissions_partial_update - parameters: - - in: path - name: id - required: true - schema: - type: integer - - in: path - name: permission - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/PatchedOrganizationPermissionRequest' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/PatchedOrganizationPermissionRequest' - multipart/form-data: - schema: - $ref: '#/components/schemas/PatchedOrganizationPermissionRequest' - responses: - '200': - content: - application/json: - schema: - $ref: '#/components/schemas/OrganizationPermission' - description: '' - '400': - description: Bad Request - '403': - description: Permission Denied - '404': - description: Permission not found for organization - security: - - Token: [] - summary: Update organization permission override - tags: - - Organizations - - Permissions - x-fern-audiences: - - public - x-fern-sdk-group-name: - - organizations - - permissions - x-fern-sdk-method-name: update - put: - description: Replace the organization-level permission override for a given permission key. - operationId: api_organizations_permissions_update - parameters: - - description: A unique integer value identifying this organization. - in: path - name: id - required: true - schema: - type: integer - - description: Permission key to update within the organization. - in: path - name: permission - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/OrganizationPermissionRequest' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/OrganizationPermissionRequest' - multipart/form-data: - schema: - $ref: '#/components/schemas/OrganizationPermissionRequest' - required: true - responses: - '200': - content: - application/json: - schema: - $ref: '#/components/schemas/OrganizationPermission' - description: '' - '400': - description: Bad Request - '403': - description: Permission Denied - '404': - description: Permission not found for organization - security: - - Token: [] - summary: Replace organization permission override - tags: - - Organizations - - Permissions - x-fern-audiences: - - public - x-fern-sdk-group-name: - - organizations - - permissions - x-fern-sdk-method-name: replace /api/organizations/{id}/set-default-role: patch: description: Update the default role for members of a specific organization. @@ -8591,6 +8301,12 @@ paths: required: true schema: type: integer + - description: Calculate agreement per label + in: query + name: per_label + schema: + default: false + type: boolean - in: path name: user_id required: true @@ -8612,12 +8328,6 @@ paths: summary: Get individual annotator agreement stats tags: - Stats - x-fern-audiences: - - public - x-fern-sdk-group-name: - - projects - - stats - x-fern-sdk-method-name: agreement_annotator /api/projects/{id}/stats/data_filter: get: description: Get statistics about user data filters and their usage within a project. @@ -8634,24 +8344,8 @@ paths: application/json: schema: properties: - user_filters: - description: Data filter statistics by user and model - properties: - stats: - description: List of filter configurations for users and models - items: - additionalProperties: - description: Filter configurations (finished, skipped, accepted, rejected, gt, predictions, review_score) - type: object - properties: - id: - description: User ID or model version identifier (e.g., "model:1.0") - type: string - type: object - type: array - tasks_with_annotations: - description: Default filter tab for tasks with annotations - type: object + filters: + description: Data filter statistics by user type: object type: object description: User data filter statistics @@ -8660,12 +8354,6 @@ paths: summary: Get user data filter statistics tags: - Stats - x-fern-audiences: - - public - x-fern-sdk-group-name: - - projects - - stats - x-fern-sdk-method-name: data_filters /api/projects/{id}/stats/finished: get: description: Get statistics about finished tasks for a project. @@ -8687,15 +8375,12 @@ paths: application/json: schema: properties: - finished: + finished_tasks: description: Number of finished tasks type: integer - id: - description: User ID - type: integer progress: description: Progress percentage (0-100) - type: integer + type: number type: object description: Finished tasks statistics security: @@ -8703,12 +8388,6 @@ paths: summary: Get finished tasks statistics tags: - Stats - x-fern-audiences: - - public - x-fern-sdk-group-name: - - projects - - stats - x-fern-sdk-method-name: finished_tasks /api/projects/{id}/stats/lead_time: get: description: Get lead time statistics across the project, including average annotation time. @@ -8725,24 +8404,9 @@ paths: application/json: schema: properties: - lead_time_stats: + lead_time: description: Lead time statistics including mean, median, and distribution - items: - properties: - mean_time: - description: Average lead time for the user - type: number - median_time: - description: Median lead time for the user - type: number - sum_lead_time: - description: Total lead time for the user - type: number - user_id: - description: User ID - type: integer - type: object - type: array + type: object type: object description: Lead time statistics security: @@ -8750,12 +8414,6 @@ paths: summary: Get lead time statistics tags: - Stats - x-fern-audiences: - - public - x-fern-sdk-group-name: - - projects - - stats - x-fern-sdk-method-name: lead_time /api/projects/{id}/stats/total_agreement: get: description: |- @@ -9277,12 +8935,6 @@ paths: summary: Start stats recalculation tags: - Stats - x-fern-audiences: - - public - x-fern-sdk-group-name: - - projects - - stats - x-fern-sdk-method-name: update_stats /api/projects/{id}/user-stats/{user_pk}/prediction: get: description: Get prediction agreement statistics for a specific user within a project. @@ -9293,11 +8945,6 @@ paths: required: true schema: type: integer - - description: Calculate agreement per label - in: query - name: per_label - schema: - type: boolean - in: path name: user_pk required: true @@ -9310,13 +8957,8 @@ paths: schema: properties: average_prediction_agreement_per_user: - oneOf: - - description: Average prediction agreement score for the user (0-1) when per_label=False - type: number - - additionalProperties: - type: number - description: Average prediction agreement score per label for the user (0-1) when per_label=True - type: object + description: Average prediction agreement score for the user (0-1) + type: number type: object description: Individual user prediction agreement statistics security: @@ -9324,12 +8966,6 @@ paths: summary: Get individual user prediction agreement tags: - Stats - x-fern-audiences: - - public - x-fern-sdk-group-name: - - projects - - stats - x-fern-sdk-method-name: user_prediction_agreement /api/projects/{id}/user-stats/{user_pk}/review_score: get: description: Get review score statistics for a specific user within a project. @@ -9340,11 +8976,6 @@ paths: required: true schema: type: integer - - description: Calculate agreement per label - in: query - name: per_label - schema: - type: boolean - in: path name: user_pk required: true @@ -9356,22 +8987,9 @@ paths: application/json: schema: properties: - performance_score: - oneOf: - - description: Performance score for the user when per_label=False - type: number - - additionalProperties: - type: number - description: Performance score per label for the user when per_label=True - type: object review_score: - oneOf: - - description: Average review score for the user when per_label=False - type: number - - additionalProperties: - type: number - description: Average review score per label for the user when per_label=True - type: object + description: Average review score for the user + type: number type: object description: Individual user review score statistics security: @@ -9379,12 +8997,6 @@ paths: summary: Get individual user review scores tags: - Stats - x-fern-audiences: - - public - x-fern-sdk-group-name: - - projects - - stats - x-fern-sdk-method-name: user_review_score /api/projects/{id}/users/{user_pk}/stats/agreement-groundtruth: get: description: Get ground truth agreement statistics for a specific user within a project. @@ -9395,11 +9007,6 @@ paths: required: true schema: type: integer - - description: Calculate agreement per label - in: query - name: per_label - schema: - type: boolean - in: path name: user_pk required: true @@ -9412,14 +9019,8 @@ paths: schema: properties: agreement: - oneOf: - - description: Ground truth agreement score for the user (0-1) when per_label=False - type: number - - additionalProperties: - description: Agreement score for specific label (0-1) - type: number - description: Ground truth agreement scores per label when per_label=True - type: object + description: Ground truth agreement score for the user (0-1) + type: number type: object description: Individual user ground truth agreement statistics security: @@ -9427,12 +9028,6 @@ paths: summary: Get individual user ground truth agreement tags: - Stats - x-fern-audiences: - - public - x-fern-sdk-group-name: - - projects - - stats - x-fern-sdk-method-name: user_ground_truth_agreement /api/projects/{id}/validate/: post: description: Determine whether the label configuration for a specific project is valid. @@ -19565,27 +19160,6 @@ components: - task - updated_at type: object - ConfigurablePermissionOption: - properties: - default: - nullable: true - oneOf: - - $ref: '#/components/schemas/Role9e7Enum' - - $ref: '#/components/schemas/NullEnum' - label: - type: string - options: - items: - $ref: '#/components/schemas/Role9e7Enum' - type: array - permission: - type: string - tooltip: - type: string - required: - - options - - permission - type: object ConvertedFormat: properties: export_type: @@ -20232,7 +19806,7 @@ components: type: string default_role: allOf: - - $ref: '#/components/schemas/Role9e7Enum' + - $ref: '#/components/schemas/DefaultRoleEnum' description: |- Default membership role for invited users @@ -20274,6 +19848,24 @@ components: required: - organization type: object + DefaultRoleEnum: + description: |- + * `OW` - Owner + * `AD` - Administrator + * `MA` - Manager + * `RE` - Reviewer + * `AN` - Annotator + * `DI` - Deactivated + * `NO` - Not Activated + enum: + - OW + - AD + - MA + - RE + - AN + - DI + - 'NO' + type: string EditionEnum: description: |- * `Community` - Community @@ -22093,7 +21685,7 @@ components: type: string default_role: allOf: - - $ref: '#/components/schemas/Role9e7Enum' + - $ref: '#/components/schemas/DefaultRoleEnum' description: |- Default membership role for invited users @@ -24334,10 +23926,15 @@ components: - $ref: '#/components/schemas/LseFields' readOnly: true org_membership: + deprecated: true items: $ref: '#/components/schemas/OrganizationMembership' readOnly: true type: array + organization_membership: + allOf: + - $ref: '#/components/schemas/OrganizationMembership' + readOnly: true pause: readOnly: true type: string @@ -24355,6 +23952,7 @@ components: - last_activity - lse_fields - org_membership + - organization_membership - pause - username type: object @@ -24407,10 +24005,15 @@ components: maxLength: 256 type: string org_membership: + deprecated: true items: $ref: '#/components/schemas/OrganizationMembership' readOnly: true type: array + organization_membership: + allOf: + - $ref: '#/components/schemas/OrganizationMembership' + readOnly: true phone: maxLength: 256 type: string @@ -24424,6 +24027,7 @@ components: - initials - last_activity - org_membership + - organization_membership - username type: object LseUserOrganizationMemberList: @@ -25186,57 +24790,6 @@ components: required: - role type: object - OrganizationPermission: - properties: - default_role: - readOnly: true - type: string - id: - readOnly: true - type: integer - label: - readOnly: true - type: string - options: - readOnly: true - type: string - organization: - readOnly: true - type: integer - permission: - maxLength: 255 - type: string - roles: - description: Explicit roles that have this permission within the organization. - items: - $ref: '#/components/schemas/Role9e7Enum' - type: array - tooltip: - readOnly: true - type: string - required: - - default_role - - id - - label - - options - - organization - - permission - - tooltip - type: object - OrganizationPermissionRequest: - properties: - permission: - maxLength: 255 - minLength: 1 - type: string - roles: - description: Explicit roles that have this permission within the organization. - items: - $ref: '#/components/schemas/Role9e7Enum' - type: array - required: - - permission - type: object PaginatedAllRolesProjectListList: properties: count: @@ -25497,10 +25050,15 @@ components: - $ref: '#/components/schemas/LseFields' readOnly: true org_membership: + deprecated: true items: $ref: '#/components/schemas/OrganizationMembership' readOnly: true type: array + organization_membership: + allOf: + - $ref: '#/components/schemas/OrganizationMembership' + readOnly: true pause: readOnly: true type: string @@ -25521,6 +25079,7 @@ components: - last_activity - lse_fields - org_membership + - organization_membership - pause - project_role - username @@ -26118,7 +25677,7 @@ components: type: string default_role: allOf: - - $ref: '#/components/schemas/Role9e7Enum' + - $ref: '#/components/schemas/DefaultRoleEnum' description: |- Default membership role for invited users @@ -27093,18 +26652,6 @@ components: user_id: type: integer type: object - PatchedOrganizationPermissionRequest: - properties: - permission: - maxLength: 255 - minLength: 1 - type: string - roles: - description: Explicit roles that have this permission within the organization. - items: - $ref: '#/components/schemas/Role9e7Enum' - type: array - type: object PatchedPauseRequest: description: |- A ModelSerializer that takes additional arguments for @@ -30340,10 +29887,15 @@ components: - $ref: '#/components/schemas/WhoAmILseFields' readOnly: true org_membership: + deprecated: true items: $ref: '#/components/schemas/OrganizationMembership' readOnly: true type: array + organization_membership: + allOf: + - $ref: '#/components/schemas/OrganizationMembership' + readOnly: true pause: readOnly: true type: string @@ -30366,6 +29918,7 @@ components: - last_activity - lse_fields - org_membership + - organization_membership - pause - permissions - username diff --git a/reference.md b/reference.md index 3ef779234..9920dc9db 100644 --- a/reference.md +++ b/reference.md @@ -4987,7 +4987,7 @@ Set the minimum user role that can edit custom scripts in the UI.
-**default_role:** `typing.Optional[Role9E7Enum]` +**default_role:** `typing.Optional[DefaultRoleEnum]` Default membership role for invited users @@ -26476,1205 +26476,8 @@ client.organizations.members.delete(
-## Organizations Permissions -
client.organizations.permissions.list(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List all organization-level permission overrides for a given organization. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.organizations.permissions.list( - id=1, -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `int` - -
-
- -
-
- -**ordering:** `typing.Optional[str]` — Which field to use when ordering the results. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.organizations.permissions.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a new organization-level permission override for a given organization. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.organizations.permissions.create( - id=1, - permission="permission", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `int` - -
-
- -
-
- -**permission:** `str` - -
-
- -
-
- -**roles:** `typing.Optional[typing.Sequence[Role9E7Enum]]` — Explicit roles that have this permission within the organization. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.organizations.permissions.get_options(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve the list of configurable permission options (label, tooltip, default role and allowed roles). -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.organizations.permissions.get_options( - id=1, -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `int` - -
-
- -
-
- -**ordering:** `typing.Optional[str]` — Which field to use when ordering the results. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.organizations.permissions.get(...) -
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.organizations.permissions.get( - id=1, - permission="permission", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `int` - -
-
- -
-
- -**permission:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.organizations.permissions.replace(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Replace the organization-level permission override for a given permission key. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.organizations.permissions.replace( - id=1, - permission_="permission", - permission="permission", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `int` — A unique integer value identifying this organization. - -
-
- -
-
- -**permission_:** `str` — Permission key to update within the organization. - -
-
- -
-
- -**permission:** `str` - -
-
- -
-
- -**roles:** `typing.Optional[typing.Sequence[Role9E7Enum]]` — Explicit roles that have this permission within the organization. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.organizations.permissions.delete(...) -
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.organizations.permissions.delete( - id=1, - permission="permission", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `int` - -
-
- -
-
- -**permission:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.organizations.permissions.update(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Partially update the organization-level permission override for a given permission key. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.organizations.permissions.update( - id=1, - permission="permission", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `int` - -
-
- -
-
- -**permission:** `str` - -
-
- -
-
- -**patched_organization_permission_request_permission:** `typing.Optional[str]` - -
-
- -
-
- -**roles:** `typing.Optional[typing.Sequence[Role9E7Enum]]` — Explicit roles that have this permission within the organization. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Projects Exports -
client.projects.exports.list_formats(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve the available export formats for the current project by ID. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.projects.exports.list_formats( - id=1, -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `int` — A unique integer value identifying this project. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.projects.exports.list(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Returns a list of exported files for a specific project by ID. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.projects.exports.list( - id=1, -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `int` — A unique integer value identifying this project. - -
-
- -
-
- -**ordering:** `typing.Optional[str]` — Which field to use when ordering the results. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.projects.exports.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a new export request to start a background task and generate an export file for a specific project by ID. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.projects.exports.create( - id=1, -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `int` — A unique integer value identifying this project. - -
-
- -
-
- -**annotation_filter_options:** `typing.Optional[LseAnnotationFilterOptionsRequest]` - -
-
- -
-
- -**converted_formats:** `typing.Optional[typing.Sequence[ConvertedFormatRequest]]` - -
-
- -
-
- -**counters:** `typing.Optional[typing.Optional[typing.Any]]` - -
-
- -
-
- -**created_by:** `typing.Optional[UserSimpleRequest]` - -
-
- -
-
- -**finished_at:** `typing.Optional[dt.datetime]` — Complete or fail time - -
-
- -
-
- -**md5:** `typing.Optional[str]` - -
-
- -
-
- -**serialization_options:** `typing.Optional[SerializationOptionsRequest]` - -
-
- -
-
- -**status:** `typing.Optional[Status7BfEnum]` - -
-
- -
-
- -**task_filter_options:** `typing.Optional[LseTaskFilterOptionsRequest]` - -
-
- -
-
- -**title:** `typing.Optional[str]` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.projects.exports.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve information about an export file by export ID for a specific project. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.projects.exports.get( - export_pk=1, - id=1, -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**export_pk:** `int` — Primary key identifying the export file. - -
-
- -
-
- -**id:** `int` — A unique integer value identifying this project. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.projects.exports.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete an export file by specified export ID. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.projects.exports.delete( - export_pk=1, - id=1, -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**export_pk:** `int` — Primary key identifying the export file. - -
-
- -
-
- -**id:** `int` — A unique integer value identifying this project. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.projects.exports.convert(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Convert export snapshot to selected format -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.projects.exports.convert( - export_pk=1, - id=1, - export_type="export_type", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**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.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve the members for a specific project. Optionally filter by user IDs (comma-separated). -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.projects.members.get( - id=1, -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `int` - -
-
- -
-
- -**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. - -
-
-
-
- - -
-
-
- -## Projects Metrics -
client.projects.metrics.get(...) +## Projects Exports +
client.projects.exports.list_formats(...)
@@ -27686,7 +26489,7 @@ client.projects.members.get(
-Get the current metrics configuration for a project. +Retrieve the available export formats for the current project by ID.
@@ -27706,7 +26509,7 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.metrics.get( +client.projects.exports.list_formats( id=1, ) @@ -27724,7 +26527,7 @@ client.projects.metrics.get(
-**id:** `int` +**id:** `int` — A unique integer value identifying this project.
@@ -27744,7 +26547,7 @@ client.projects.metrics.get(
-
client.projects.metrics.update(...) +
client.projects.exports.list(...)
@@ -27756,7 +26559,7 @@ client.projects.metrics.get(
-Update metrics strategy and parameters for a project. +Returns a list of exported files for a specific project by ID.
@@ -27776,7 +26579,7 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.metrics.update( +client.projects.exports.list( id=1, ) @@ -27794,31 +26597,7 @@ client.projects.metrics.update(
-**id:** `int` - -
-
- -
-
- -**additional_params:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` - -
-
- -
-
- -**agreement_threshold:** `typing.Optional[int]` - -
-
- -
-
- -**max_additional_annotators_assignable:** `typing.Optional[int]` +**id:** `int` — A unique integer value identifying this project.
@@ -27826,7 +26605,7 @@ client.projects.metrics.update(
-**metric_name:** `typing.Optional[str]` +**ordering:** `typing.Optional[str]` — Which field to use when ordering the results.
@@ -27846,8 +26625,7 @@ client.projects.metrics.update(
-## Projects Stats -
client.projects.stats.iaa(...) +
client.projects.exports.create(...)
@@ -27859,7 +26637,7 @@ client.projects.metrics.update(
-Get Inter-Annotator Agreement (IAA) matrix for a project, showing agreement between all annotators. +Create a new export request to start a background task and generate an export file for a specific project by ID.
@@ -27879,7 +26657,7 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.stats.iaa( +client.projects.exports.create( id=1, ) @@ -27897,7 +26675,7 @@ client.projects.stats.iaa(
-**id:** `int` +**id:** `int` — A unique integer value identifying this project.
@@ -27905,7 +26683,7 @@ client.projects.stats.iaa(
-**expand:** `typing.Optional[str]` — Comma-separated list of fields to expand +**annotation_filter_options:** `typing.Optional[LseAnnotationFilterOptionsRequest]`
@@ -27913,7 +26691,7 @@ client.projects.stats.iaa(
-**per_label:** `typing.Optional[bool]` — Calculate IAA per label +**converted_formats:** `typing.Optional[typing.Sequence[ConvertedFormatRequest]]`
@@ -27921,7 +26699,7 @@ client.projects.stats.iaa(
-**std:** `typing.Optional[bool]` — Include standard deviation in results +**counters:** `typing.Optional[typing.Optional[typing.Any]]`
@@ -27929,7 +26707,7 @@ client.projects.stats.iaa(
-**task:** `typing.Optional[str]` — Comma-separated list of task IDs to filter by +**created_by:** `typing.Optional[UserSimpleRequest]`
@@ -27937,70 +26715,39 @@ client.projects.stats.iaa(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**finished_at:** `typing.Optional[dt.datetime]` — Complete or fail time
- -
- - - - -
-
client.projects.stats.agreement_annotator(...)
-#### 📝 Description - -
-
+**md5:** `typing.Optional[str]` + +
+
-Get agreement statistics for a specific annotator within a project. -
-
+**serialization_options:** `typing.Optional[SerializationOptionsRequest]` +
-#### 🔌 Usage - -
-
-
-```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.projects.stats.agreement_annotator( - id=1, - user_id=1, -) - -``` -
-
+**status:** `typing.Optional[Status7BfEnum]` +
-#### ⚙️ Parameters - -
-
-
-**id:** `int` +**task_filter_options:** `typing.Optional[LseTaskFilterOptionsRequest]`
@@ -28008,7 +26755,7 @@ client.projects.stats.agreement_annotator(
-**user_id:** `int` +**title:** `typing.Optional[str]`
@@ -28028,7 +26775,7 @@ client.projects.stats.agreement_annotator(
-
client.projects.stats.data_filters(...) +
client.projects.exports.get(...)
@@ -28040,7 +26787,7 @@ client.projects.stats.agreement_annotator(
-Get statistics about user data filters and their usage within a project. +Retrieve information about an export file by export ID for a specific project.
@@ -28060,7 +26807,8 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.stats.data_filters( +client.projects.exports.get( + export_pk=1, id=1, ) @@ -28078,7 +26826,15 @@ client.projects.stats.data_filters(
-**id:** `int` +**export_pk:** `int` — Primary key identifying the export file. + +
+
+ +
+
+ +**id:** `int` — A unique integer value identifying this project.
@@ -28098,7 +26854,7 @@ client.projects.stats.data_filters(
-
client.projects.stats.finished_tasks(...) +
client.projects.exports.delete(...)
@@ -28110,7 +26866,7 @@ client.projects.stats.data_filters(
-Get statistics about finished tasks for a project. +Delete an export file by specified export ID.
@@ -28130,7 +26886,8 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.stats.finished_tasks( +client.projects.exports.delete( + export_pk=1, id=1, ) @@ -28148,7 +26905,7 @@ client.projects.stats.finished_tasks(
-**id:** `int` +**export_pk:** `int` — Primary key identifying the export file.
@@ -28156,7 +26913,7 @@ client.projects.stats.finished_tasks(
-**user_pk:** `typing.Optional[int]` — User ID to filter statistics by (optional) +**id:** `int` — A unique integer value identifying this project.
@@ -28176,7 +26933,7 @@ client.projects.stats.finished_tasks(
-
client.projects.stats.lead_time(...) +
client.projects.exports.convert(...)
@@ -28188,7 +26945,7 @@ client.projects.stats.finished_tasks(
-Get lead time statistics across the project, including average annotation time. +Convert export snapshot to selected format
@@ -28208,8 +26965,10 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.stats.lead_time( +client.projects.exports.convert( + export_pk=1, id=1, + export_type="export_type", ) ``` @@ -28226,7 +26985,31 @@ client.projects.stats.lead_time(
-**id:** `int` +**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.
@@ -28246,7 +27029,8 @@ client.projects.stats.lead_time(
-
client.projects.stats.total_agreement(...) +## Projects Members +
client.projects.members.get(...)
@@ -28258,9 +27042,7 @@ client.projects.stats.lead_time(
-Overall or per-label total agreement across the project. - -NOTE: due to an open issue in Fern, SDK clients will raise ApiError upon handling a 204 response. As a workaround, wrap call to this function in a try-except block. +Retrieve the members for a specific project. Optionally filter by user IDs (comma-separated).
@@ -28280,7 +27062,7 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.stats.total_agreement( +client.projects.members.get( id=1, ) @@ -28306,7 +27088,7 @@ client.projects.stats.total_agreement(
-**per_label:** `typing.Optional[bool]` — Return agreement per label +**user_ids:** `typing.Optional[str]` — Comma-separated list of user IDs to include. Example: user_ids=1,2,3
@@ -28326,7 +27108,8 @@ client.projects.stats.total_agreement(
-
client.projects.stats.update_stats(...) +## Projects Metrics +
client.projects.metrics.get(...)
@@ -28338,7 +27121,7 @@ client.projects.stats.total_agreement(
-Start stats recalculation for given project +Get the current metrics configuration for a project.
@@ -28358,7 +27141,7 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.stats.update_stats( +client.projects.metrics.get( id=1, ) @@ -28384,14 +27167,6 @@ client.projects.stats.update_stats(
-**stat_type:** `typing.Optional[str]` — Stat type to recalculate. Possible values: label, stats - -
-
- -
-
- **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -28404,7 +27179,7 @@ client.projects.stats.update_stats(
-
client.projects.stats.user_prediction_agreement(...) +
client.projects.metrics.update(...)
@@ -28416,7 +27191,7 @@ client.projects.stats.update_stats(
-Get prediction agreement statistics for a specific user within a project. +Update metrics strategy and parameters for a project.
@@ -28436,9 +27211,8 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.stats.user_prediction_agreement( +client.projects.metrics.update( id=1, - user_pk=1, ) ``` @@ -28463,7 +27237,15 @@ client.projects.stats.user_prediction_agreement(
-**user_pk:** `int` +**additional_params:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` + +
+
+ +
+
+ +**agreement_threshold:** `typing.Optional[int]`
@@ -28471,7 +27253,15 @@ client.projects.stats.user_prediction_agreement(
-**per_label:** `typing.Optional[bool]` — Calculate agreement per label +**max_additional_annotators_assignable:** `typing.Optional[int]` + +
+
+ +
+
+ +**metric_name:** `typing.Optional[str]`
@@ -28491,7 +27281,8 @@ client.projects.stats.user_prediction_agreement(
-
client.projects.stats.user_review_score(...) +## Projects Stats +
client.projects.stats.iaa(...)
@@ -28503,7 +27294,7 @@ client.projects.stats.user_prediction_agreement(
-Get review score statistics for a specific user within a project. +Get Inter-Annotator Agreement (IAA) matrix for a project, showing agreement between all annotators.
@@ -28523,9 +27314,8 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.stats.user_review_score( +client.projects.stats.iaa( id=1, - user_pk=1, ) ``` @@ -28550,7 +27340,7 @@ client.projects.stats.user_review_score(
-**user_pk:** `int` +**expand:** `typing.Optional[str]` — Comma-separated list of fields to expand
@@ -28558,7 +27348,23 @@ client.projects.stats.user_review_score(
-**per_label:** `typing.Optional[bool]` — Calculate agreement per label +**per_label:** `typing.Optional[bool]` — Calculate IAA per label + +
+
+ +
+
+ +**std:** `typing.Optional[bool]` — Include standard deviation in results + +
+
+ +
+
+ +**task:** `typing.Optional[str]` — Comma-separated list of task IDs to filter by
@@ -28578,7 +27384,7 @@ client.projects.stats.user_review_score(
-
client.projects.stats.user_ground_truth_agreement(...) +
client.projects.stats.total_agreement(...)
@@ -28590,7 +27396,9 @@ client.projects.stats.user_review_score(
-Get ground truth agreement statistics for a specific user within a project. +Overall or per-label total agreement across the project. + +NOTE: due to an open issue in Fern, SDK clients will raise ApiError upon handling a 204 response. As a workaround, wrap call to this function in a try-except block.
@@ -28610,9 +27418,8 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.stats.user_ground_truth_agreement( +client.projects.stats.total_agreement( id=1, - user_pk=1, ) ``` @@ -28637,15 +27444,7 @@ client.projects.stats.user_ground_truth_agreement(
-**user_pk:** `int` - -
-
- -
-
- -**per_label:** `typing.Optional[bool]` — Calculate agreement per label +**per_label:** `typing.Optional[bool]` — Return agreement per label
diff --git a/src/label_studio_sdk/__init__.py b/src/label_studio_sdk/__init__.py index 4fe4748d8..85aebcb1c 100644 --- a/src/label_studio_sdk/__init__.py +++ b/src/label_studio_sdk/__init__.py @@ -42,14 +42,13 @@ Comment, CommentRequest, CommentSerializerWithExpandedUser, - ConfigurablePermissionOption, - ConfigurablePermissionOptionDefault, ConvertedFormat, ConvertedFormatRequest, CountLimit, CustomScriptsEditableByEnum, DefaultRole, DefaultRoleCustomScriptsEditableBy, + DefaultRoleEnum, EditionEnum, Export, FileUpload, @@ -139,8 +138,6 @@ OrganizationInvite, OrganizationMember, OrganizationMembership, - OrganizationPermission, - OrganizationPermissionRequest, PaginatedAllRolesProjectListList, PaginatedAnnotationHistoryList, PaginatedLseOrganizationMemberListList, @@ -402,14 +399,13 @@ "Comment", "CommentRequest", "CommentSerializerWithExpandedUser", - "ConfigurablePermissionOption", - "ConfigurablePermissionOptionDefault", "ConvertedFormat", "ConvertedFormatRequest", "CountLimit", "CustomScriptsEditableByEnum", "DefaultRole", "DefaultRoleCustomScriptsEditableBy", + "DefaultRoleEnum", "EditionEnum", "Export", "ExportStorageListTypesResponseItem", @@ -513,8 +509,6 @@ "OrganizationInvite", "OrganizationMember", "OrganizationMembership", - "OrganizationPermission", - "OrganizationPermissionRequest", "PaginatedAllRolesProjectListList", "PaginatedAnnotationHistoryList", "PaginatedLseOrganizationMemberListList", diff --git a/src/label_studio_sdk/organizations/__init__.py b/src/label_studio_sdk/organizations/__init__.py index 8451c0fe6..faea629fa 100644 --- a/src/label_studio_sdk/organizations/__init__.py +++ b/src/label_studio_sdk/organizations/__init__.py @@ -1,6 +1,6 @@ # This file was auto-generated by Fern from our API Definition. from .types import PatchedDefaultRoleRequestCustomScriptsEditableBy -from . import invites, members, permissions +from . import invites, members -__all__ = ["PatchedDefaultRoleRequestCustomScriptsEditableBy", "invites", "members", "permissions"] +__all__ = ["PatchedDefaultRoleRequestCustomScriptsEditableBy", "invites", "members"] diff --git a/src/label_studio_sdk/organizations/client.py b/src/label_studio_sdk/organizations/client.py index 8117bc87d..eaebaacbc 100644 --- a/src/label_studio_sdk/organizations/client.py +++ b/src/label_studio_sdk/organizations/client.py @@ -4,7 +4,6 @@ from ..core.client_wrapper import SyncClientWrapper from .invites.client import InvitesClient from .members.client import MembersClient -from .permissions.client import PermissionsClient from ..core.request_options import RequestOptions from ..types.organization_invite import OrganizationInvite from ..core.unchecked_base_model import construct_type @@ -20,13 +19,12 @@ from .types.patched_default_role_request_custom_scripts_editable_by import ( PatchedDefaultRoleRequestCustomScriptsEditableBy, ) -from ..types.role9e7enum import Role9E7Enum +from ..types.default_role_enum import DefaultRoleEnum from ..types.default_role import DefaultRole from ..core.serialization import convert_and_respect_annotation_metadata from ..core.client_wrapper import AsyncClientWrapper from .invites.client import AsyncInvitesClient from .members.client import AsyncMembersClient -from .permissions.client import AsyncPermissionsClient # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -37,7 +35,6 @@ def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper self.invites = InvitesClient(client_wrapper=self._client_wrapper) self.members = MembersClient(client_wrapper=self._client_wrapper) - self.permissions = PermissionsClient(client_wrapper=self._client_wrapper) def reset_token(self, *, request_options: typing.Optional[RequestOptions] = None) -> OrganizationInvite: """ @@ -309,7 +306,7 @@ def update_default_role( annotator_reviewer_firewall_enabled_at: typing.Optional[dt.datetime] = OMIT, custom_scripts_editable_by: typing.Optional[PatchedDefaultRoleRequestCustomScriptsEditableBy] = OMIT, custom_scripts_enabled_at: typing.Optional[dt.datetime] = OMIT, - default_role: typing.Optional[Role9E7Enum] = OMIT, + default_role: typing.Optional[DefaultRoleEnum] = OMIT, email_notification_settings: typing.Optional[typing.Optional[typing.Any]] = OMIT, embed_domains: typing.Optional[typing.Optional[typing.Any]] = OMIT, embed_settings: typing.Optional[typing.Optional[typing.Any]] = OMIT, @@ -339,7 +336,7 @@ def update_default_role( custom_scripts_enabled_at : typing.Optional[dt.datetime] Set to current time to enabled custom scripts for this organization. Can only be enabled if no organization members are active members of any other organizations; otherwise an error will be raised. If this occurs, contact the LEAP team for assistance with enabling custom scripts. - default_role : typing.Optional[Role9E7Enum] + default_role : typing.Optional[DefaultRoleEnum] Default membership role for invited users * `OW` - Owner @@ -436,7 +433,6 @@ def __init__(self, *, client_wrapper: AsyncClientWrapper): self._client_wrapper = client_wrapper self.invites = AsyncInvitesClient(client_wrapper=self._client_wrapper) self.members = AsyncMembersClient(client_wrapper=self._client_wrapper) - self.permissions = AsyncPermissionsClient(client_wrapper=self._client_wrapper) async def reset_token(self, *, request_options: typing.Optional[RequestOptions] = None) -> OrganizationInvite: """ @@ -740,7 +736,7 @@ async def update_default_role( annotator_reviewer_firewall_enabled_at: typing.Optional[dt.datetime] = OMIT, custom_scripts_editable_by: typing.Optional[PatchedDefaultRoleRequestCustomScriptsEditableBy] = OMIT, custom_scripts_enabled_at: typing.Optional[dt.datetime] = OMIT, - default_role: typing.Optional[Role9E7Enum] = OMIT, + default_role: typing.Optional[DefaultRoleEnum] = OMIT, email_notification_settings: typing.Optional[typing.Optional[typing.Any]] = OMIT, embed_domains: typing.Optional[typing.Optional[typing.Any]] = OMIT, embed_settings: typing.Optional[typing.Optional[typing.Any]] = OMIT, @@ -770,7 +766,7 @@ async def update_default_role( custom_scripts_enabled_at : typing.Optional[dt.datetime] Set to current time to enabled custom scripts for this organization. Can only be enabled if no organization members are active members of any other organizations; otherwise an error will be raised. If this occurs, contact the LEAP team for assistance with enabling custom scripts. - default_role : typing.Optional[Role9E7Enum] + default_role : typing.Optional[DefaultRoleEnum] Default membership role for invited users * `OW` - Owner diff --git a/src/label_studio_sdk/organizations/permissions/__init__.py b/src/label_studio_sdk/organizations/permissions/__init__.py deleted file mode 100644 index f3ea2659b..000000000 --- a/src/label_studio_sdk/organizations/permissions/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - diff --git a/src/label_studio_sdk/organizations/permissions/client.py b/src/label_studio_sdk/organizations/permissions/client.py deleted file mode 100644 index 6a356d5bb..000000000 --- a/src/label_studio_sdk/organizations/permissions/client.py +++ /dev/null @@ -1,1129 +0,0 @@ -# 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.organization_permission import OrganizationPermission -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 ...types.role9e7enum import Role9E7Enum -from ...errors.bad_request_error import BadRequestError -from ...errors.forbidden_error import ForbiddenError -from ...types.configurable_permission_option import ConfigurablePermissionOption -from ...errors.not_found_error import NotFoundError -from ...core.client_wrapper import AsyncClientWrapper - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class PermissionsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def list( - self, id: int, *, ordering: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None - ) -> typing.List[OrganizationPermission]: - """ - List all organization-level permission overrides for a given organization. - - Parameters - ---------- - id : int - - ordering : typing.Optional[str] - Which field to use when ordering the results. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - typing.List[OrganizationPermission] - - - Examples - -------- - from label_studio_sdk import LabelStudio - - client = LabelStudio( - api_key="YOUR_API_KEY", - ) - client.organizations.permissions.list( - id=1, - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/organizations/{jsonable_encoder(id)}/permissions", - method="GET", - params={ - "ordering": ordering, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - typing.List[OrganizationPermission], - construct_type( - type_=typing.List[OrganizationPermission], # 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 create( - self, - id: int, - *, - permission: str, - roles: typing.Optional[typing.Sequence[Role9E7Enum]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> OrganizationPermission: - """ - Create a new organization-level permission override for a given organization. - - Parameters - ---------- - id : int - - permission : str - - roles : typing.Optional[typing.Sequence[Role9E7Enum]] - Explicit roles that have this permission within the organization. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - OrganizationPermission - - - Examples - -------- - from label_studio_sdk import LabelStudio - - client = LabelStudio( - api_key="YOUR_API_KEY", - ) - client.organizations.permissions.create( - id=1, - permission="permission", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/organizations/{jsonable_encoder(id)}/permissions", - method="POST", - json={ - "permission": permission, - "roles": roles, - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - OrganizationPermission, - construct_type( - type_=OrganizationPermission, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 403: - raise ForbiddenError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # 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 get_options( - self, id: int, *, ordering: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None - ) -> typing.List[ConfigurablePermissionOption]: - """ - Retrieve the list of configurable permission options (label, tooltip, default role and allowed roles). - - Parameters - ---------- - id : int - - ordering : typing.Optional[str] - Which field to use when ordering the results. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - typing.List[ConfigurablePermissionOption] - - - Examples - -------- - from label_studio_sdk import LabelStudio - - client = LabelStudio( - api_key="YOUR_API_KEY", - ) - client.organizations.permissions.get_options( - id=1, - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/organizations/{jsonable_encoder(id)}/permissions/options", - method="GET", - params={ - "ordering": ordering, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - typing.List[ConfigurablePermissionOption], - construct_type( - type_=typing.List[ConfigurablePermissionOption], # 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 get( - self, id: int, permission: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> OrganizationPermission: - """ - Parameters - ---------- - id : int - - permission : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - OrganizationPermission - - - Examples - -------- - from label_studio_sdk import LabelStudio - - client = LabelStudio( - api_key="YOUR_API_KEY", - ) - client.organizations.permissions.get( - id=1, - permission="permission", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/organizations/{jsonable_encoder(id)}/permissions/{jsonable_encoder(permission)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - OrganizationPermission, - construct_type( - type_=OrganizationPermission, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # 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 replace( - self, - id: int, - permission_: str, - *, - permission: str, - roles: typing.Optional[typing.Sequence[Role9E7Enum]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> OrganizationPermission: - """ - Replace the organization-level permission override for a given permission key. - - Parameters - ---------- - id : int - A unique integer value identifying this organization. - - permission_ : str - Permission key to update within the organization. - - permission : str - - roles : typing.Optional[typing.Sequence[Role9E7Enum]] - Explicit roles that have this permission within the organization. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - OrganizationPermission - - - Examples - -------- - from label_studio_sdk import LabelStudio - - client = LabelStudio( - api_key="YOUR_API_KEY", - ) - client.organizations.permissions.replace( - id=1, - permission_="permission", - permission="permission", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/organizations/{jsonable_encoder(id)}/permissions/{jsonable_encoder(permission_)}", - method="PUT", - json={ - "permission": permission, - "roles": roles, - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - OrganizationPermission, - construct_type( - type_=OrganizationPermission, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 403: - raise ForbiddenError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # 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 delete(self, id: int, permission: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: - """ - Parameters - ---------- - id : int - - permission : str - - 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.organizations.permissions.delete( - id=1, - permission="permission", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/organizations/{jsonable_encoder(id)}/permissions/{jsonable_encoder(permission)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 403: - raise ForbiddenError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # 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 update( - self, - id: int, - permission: str, - *, - patched_organization_permission_request_permission: typing.Optional[str] = OMIT, - roles: typing.Optional[typing.Sequence[Role9E7Enum]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> OrganizationPermission: - """ - Partially update the organization-level permission override for a given permission key. - - Parameters - ---------- - id : int - - permission : str - - patched_organization_permission_request_permission : typing.Optional[str] - - roles : typing.Optional[typing.Sequence[Role9E7Enum]] - Explicit roles that have this permission within the organization. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - OrganizationPermission - - - Examples - -------- - from label_studio_sdk import LabelStudio - - client = LabelStudio( - api_key="YOUR_API_KEY", - ) - client.organizations.permissions.update( - id=1, - permission="permission", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/organizations/{jsonable_encoder(id)}/permissions/{jsonable_encoder(permission)}", - method="PATCH", - json={ - "permission": patched_organization_permission_request_permission, - "roles": roles, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - OrganizationPermission, - construct_type( - type_=OrganizationPermission, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 403: - raise ForbiddenError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # 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 AsyncPermissionsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def list( - self, id: int, *, ordering: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None - ) -> typing.List[OrganizationPermission]: - """ - List all organization-level permission overrides for a given organization. - - Parameters - ---------- - id : int - - ordering : typing.Optional[str] - Which field to use when ordering the results. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - typing.List[OrganizationPermission] - - - Examples - -------- - import asyncio - - from label_studio_sdk import AsyncLabelStudio - - client = AsyncLabelStudio( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.organizations.permissions.list( - id=1, - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/organizations/{jsonable_encoder(id)}/permissions", - method="GET", - params={ - "ordering": ordering, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - typing.List[OrganizationPermission], - construct_type( - type_=typing.List[OrganizationPermission], # 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 create( - self, - id: int, - *, - permission: str, - roles: typing.Optional[typing.Sequence[Role9E7Enum]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> OrganizationPermission: - """ - Create a new organization-level permission override for a given organization. - - Parameters - ---------- - id : int - - permission : str - - roles : typing.Optional[typing.Sequence[Role9E7Enum]] - Explicit roles that have this permission within the organization. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - OrganizationPermission - - - Examples - -------- - import asyncio - - from label_studio_sdk import AsyncLabelStudio - - client = AsyncLabelStudio( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.organizations.permissions.create( - id=1, - permission="permission", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/organizations/{jsonable_encoder(id)}/permissions", - method="POST", - json={ - "permission": permission, - "roles": roles, - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - OrganizationPermission, - construct_type( - type_=OrganizationPermission, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 403: - raise ForbiddenError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # 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 get_options( - self, id: int, *, ordering: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None - ) -> typing.List[ConfigurablePermissionOption]: - """ - Retrieve the list of configurable permission options (label, tooltip, default role and allowed roles). - - Parameters - ---------- - id : int - - ordering : typing.Optional[str] - Which field to use when ordering the results. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - typing.List[ConfigurablePermissionOption] - - - Examples - -------- - import asyncio - - from label_studio_sdk import AsyncLabelStudio - - client = AsyncLabelStudio( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.organizations.permissions.get_options( - id=1, - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/organizations/{jsonable_encoder(id)}/permissions/options", - method="GET", - params={ - "ordering": ordering, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - typing.List[ConfigurablePermissionOption], - construct_type( - type_=typing.List[ConfigurablePermissionOption], # 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 get( - self, id: int, permission: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> OrganizationPermission: - """ - Parameters - ---------- - id : int - - permission : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - OrganizationPermission - - - Examples - -------- - import asyncio - - from label_studio_sdk import AsyncLabelStudio - - client = AsyncLabelStudio( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.organizations.permissions.get( - id=1, - permission="permission", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/organizations/{jsonable_encoder(id)}/permissions/{jsonable_encoder(permission)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - OrganizationPermission, - construct_type( - type_=OrganizationPermission, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # 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 replace( - self, - id: int, - permission_: str, - *, - permission: str, - roles: typing.Optional[typing.Sequence[Role9E7Enum]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> OrganizationPermission: - """ - Replace the organization-level permission override for a given permission key. - - Parameters - ---------- - id : int - A unique integer value identifying this organization. - - permission_ : str - Permission key to update within the organization. - - permission : str - - roles : typing.Optional[typing.Sequence[Role9E7Enum]] - Explicit roles that have this permission within the organization. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - OrganizationPermission - - - Examples - -------- - import asyncio - - from label_studio_sdk import AsyncLabelStudio - - client = AsyncLabelStudio( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.organizations.permissions.replace( - id=1, - permission_="permission", - permission="permission", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/organizations/{jsonable_encoder(id)}/permissions/{jsonable_encoder(permission_)}", - method="PUT", - json={ - "permission": permission, - "roles": roles, - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - OrganizationPermission, - construct_type( - type_=OrganizationPermission, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 403: - raise ForbiddenError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # 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 delete( - self, id: int, permission: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> None: - """ - Parameters - ---------- - id : int - - permission : str - - 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.organizations.permissions.delete( - id=1, - permission="permission", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/organizations/{jsonable_encoder(id)}/permissions/{jsonable_encoder(permission)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 403: - raise ForbiddenError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # 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 update( - self, - id: int, - permission: str, - *, - patched_organization_permission_request_permission: typing.Optional[str] = OMIT, - roles: typing.Optional[typing.Sequence[Role9E7Enum]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> OrganizationPermission: - """ - Partially update the organization-level permission override for a given permission key. - - Parameters - ---------- - id : int - - permission : str - - patched_organization_permission_request_permission : typing.Optional[str] - - roles : typing.Optional[typing.Sequence[Role9E7Enum]] - Explicit roles that have this permission within the organization. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - OrganizationPermission - - - Examples - -------- - import asyncio - - from label_studio_sdk import AsyncLabelStudio - - client = AsyncLabelStudio( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.organizations.permissions.update( - id=1, - permission="permission", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/organizations/{jsonable_encoder(id)}/permissions/{jsonable_encoder(permission)}", - method="PATCH", - json={ - "permission": patched_organization_permission_request_permission, - "roles": roles, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - OrganizationPermission, - construct_type( - type_=OrganizationPermission, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 403: - raise ForbiddenError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - construct_type( - type_=typing.Optional[typing.Any], # 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/projects/__init__.py b/src/label_studio_sdk/projects/__init__.py index eea32526c..fee07c3bc 100644 --- a/src/label_studio_sdk/projects/__init__.py +++ b/src/label_studio_sdk/projects/__init__.py @@ -29,27 +29,13 @@ ) from .exports import ExportsConvertResponse from .stats import ( - StatsAgreementAnnotatorResponse, - StatsDataFiltersResponse, - StatsDataFiltersResponseUserFilters, - StatsDataFiltersResponseUserFiltersStatsItem, - StatsFinishedTasksResponse, StatsIaaResponse, StatsIaaResponseCommonTasks, StatsIaaResponseIaa, StatsIaaResponseStd, - StatsLeadTimeResponse, - StatsLeadTimeResponseLeadTimeStatsItem, StatsTotalAgreementResponse, StatsTotalAgreementResponseOne, StatsTotalAgreementResponseZero, - StatsUserGroundTruthAgreementResponse, - StatsUserGroundTruthAgreementResponseAgreement, - StatsUserPredictionAgreementResponse, - StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser, - StatsUserReviewScoreResponse, - StatsUserReviewScoreResponsePerformanceScore, - StatsUserReviewScoreResponseReviewScore, ) __all__ = [ @@ -76,27 +62,13 @@ "ProjectsImportPredictionsResponse", "ProjectsImportTasksResponse", "ProjectsListRequestFilter", - "StatsAgreementAnnotatorResponse", - "StatsDataFiltersResponse", - "StatsDataFiltersResponseUserFilters", - "StatsDataFiltersResponseUserFiltersStatsItem", - "StatsFinishedTasksResponse", "StatsIaaResponse", "StatsIaaResponseCommonTasks", "StatsIaaResponseIaa", "StatsIaaResponseStd", - "StatsLeadTimeResponse", - "StatsLeadTimeResponseLeadTimeStatsItem", "StatsTotalAgreementResponse", "StatsTotalAgreementResponseOne", "StatsTotalAgreementResponseZero", - "StatsUserGroundTruthAgreementResponse", - "StatsUserGroundTruthAgreementResponseAgreement", - "StatsUserPredictionAgreementResponse", - "StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser", - "StatsUserReviewScoreResponse", - "StatsUserReviewScoreResponsePerformanceScore", - "StatsUserReviewScoreResponseReviewScore", "assignments", "exports", "members", diff --git a/src/label_studio_sdk/projects/stats/__init__.py b/src/label_studio_sdk/projects/stats/__init__.py index 0cb78a0d6..581602a85 100644 --- a/src/label_studio_sdk/projects/stats/__init__.py +++ b/src/label_studio_sdk/projects/stats/__init__.py @@ -1,49 +1,21 @@ # This file was auto-generated by Fern from our API Definition. from .types import ( - StatsAgreementAnnotatorResponse, - StatsDataFiltersResponse, - StatsDataFiltersResponseUserFilters, - StatsDataFiltersResponseUserFiltersStatsItem, - StatsFinishedTasksResponse, StatsIaaResponse, StatsIaaResponseCommonTasks, StatsIaaResponseIaa, StatsIaaResponseStd, - StatsLeadTimeResponse, - StatsLeadTimeResponseLeadTimeStatsItem, StatsTotalAgreementResponse, StatsTotalAgreementResponseOne, StatsTotalAgreementResponseZero, - StatsUserGroundTruthAgreementResponse, - StatsUserGroundTruthAgreementResponseAgreement, - StatsUserPredictionAgreementResponse, - StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser, - StatsUserReviewScoreResponse, - StatsUserReviewScoreResponsePerformanceScore, - StatsUserReviewScoreResponseReviewScore, ) __all__ = [ - "StatsAgreementAnnotatorResponse", - "StatsDataFiltersResponse", - "StatsDataFiltersResponseUserFilters", - "StatsDataFiltersResponseUserFiltersStatsItem", - "StatsFinishedTasksResponse", "StatsIaaResponse", "StatsIaaResponseCommonTasks", "StatsIaaResponseIaa", "StatsIaaResponseStd", - "StatsLeadTimeResponse", - "StatsLeadTimeResponseLeadTimeStatsItem", "StatsTotalAgreementResponse", "StatsTotalAgreementResponseOne", "StatsTotalAgreementResponseZero", - "StatsUserGroundTruthAgreementResponse", - "StatsUserGroundTruthAgreementResponseAgreement", - "StatsUserPredictionAgreementResponse", - "StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser", - "StatsUserReviewScoreResponse", - "StatsUserReviewScoreResponsePerformanceScore", - "StatsUserReviewScoreResponseReviewScore", ] diff --git a/src/label_studio_sdk/projects/stats/client.py b/src/label_studio_sdk/projects/stats/client.py index 508cc75ea..adb673a7e 100644 --- a/src/label_studio_sdk/projects/stats/client.py +++ b/src/label_studio_sdk/projects/stats/client.py @@ -8,14 +8,7 @@ from ...core.unchecked_base_model import construct_type from json.decoder import JSONDecodeError from ...core.api_error import ApiError -from .types.stats_agreement_annotator_response import StatsAgreementAnnotatorResponse -from .types.stats_data_filters_response import StatsDataFiltersResponse -from .types.stats_finished_tasks_response import StatsFinishedTasksResponse -from .types.stats_lead_time_response import StatsLeadTimeResponse from .types.stats_total_agreement_response import StatsTotalAgreementResponse -from .types.stats_user_prediction_agreement_response import StatsUserPredictionAgreementResponse -from .types.stats_user_review_score_response import StatsUserReviewScoreResponse -from .types.stats_user_ground_truth_agreement_response import StatsUserGroundTruthAgreementResponse from ...core.client_wrapper import AsyncClientWrapper @@ -96,829 +89,7 @@ def iaa( raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) - def agreement_annotator( - self, id: int, user_id: int, *, request_options: typing.Optional[RequestOptions] = None - ) -> StatsAgreementAnnotatorResponse: - """ - Get agreement statistics for a specific annotator within a project. - - Parameters - ---------- - id : int - - user_id : int - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - StatsAgreementAnnotatorResponse - Individual annotator agreement statistics - - Examples - -------- - from label_studio_sdk import LabelStudio - - client = LabelStudio( - api_key="YOUR_API_KEY", - ) - client.projects.stats.agreement_annotator( - id=1, - user_id=1, - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/stats/agreement_annotator/{jsonable_encoder(user_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - StatsAgreementAnnotatorResponse, - construct_type( - type_=StatsAgreementAnnotatorResponse, # 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 data_filters( - self, id: int, *, request_options: typing.Optional[RequestOptions] = None - ) -> StatsDataFiltersResponse: - """ - Get statistics about user data filters and their usage within a project. - - Parameters - ---------- - id : int - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - StatsDataFiltersResponse - User data filter statistics - - Examples - -------- - from label_studio_sdk import LabelStudio - - client = LabelStudio( - api_key="YOUR_API_KEY", - ) - client.projects.stats.data_filters( - id=1, - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/stats/data_filter", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - StatsDataFiltersResponse, - construct_type( - type_=StatsDataFiltersResponse, # 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 finished_tasks( - self, id: int, *, user_pk: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None - ) -> StatsFinishedTasksResponse: - """ - Get statistics about finished tasks for a project. - - Parameters - ---------- - id : int - - user_pk : typing.Optional[int] - User ID to filter statistics by (optional) - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - StatsFinishedTasksResponse - Finished tasks statistics - - Examples - -------- - from label_studio_sdk import LabelStudio - - client = LabelStudio( - api_key="YOUR_API_KEY", - ) - client.projects.stats.finished_tasks( - id=1, - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/stats/finished", - method="GET", - params={ - "user_pk": user_pk, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - StatsFinishedTasksResponse, - construct_type( - type_=StatsFinishedTasksResponse, # 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 lead_time(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> StatsLeadTimeResponse: - """ - Get lead time statistics across the project, including average annotation time. - - Parameters - ---------- - id : int - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - StatsLeadTimeResponse - Lead time statistics - - Examples - -------- - from label_studio_sdk import LabelStudio - - client = LabelStudio( - api_key="YOUR_API_KEY", - ) - client.projects.stats.lead_time( - id=1, - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/stats/lead_time", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - StatsLeadTimeResponse, - construct_type( - type_=StatsLeadTimeResponse, # 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 total_agreement( - self, - id: int, - *, - per_label: typing.Optional[bool] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> StatsTotalAgreementResponse: - """ - Overall or per-label total agreement across the project. - - NOTE: due to an open issue in Fern, SDK clients will raise ApiError upon handling a 204 response. As a workaround, wrap call to this function in a try-except block. - - Parameters - ---------- - id : int - - per_label : typing.Optional[bool] - Return agreement per label - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - StatsTotalAgreementResponse - Total agreement - - Examples - -------- - from label_studio_sdk import LabelStudio - - client = LabelStudio( - api_key="YOUR_API_KEY", - ) - client.projects.stats.total_agreement( - id=1, - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/stats/total_agreement", - method="GET", - params={ - "per_label": per_label, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - StatsTotalAgreementResponse, - construct_type( - type_=StatsTotalAgreementResponse, # 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 update_stats( - self, - id: int, - *, - stat_type: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> typing.Dict[str, typing.Optional[typing.Any]]: - """ - Start stats recalculation for given project - - Parameters - ---------- - id : int - - stat_type : typing.Optional[str] - Stat type to recalculate. Possible values: label, stats - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - typing.Dict[str, typing.Optional[typing.Any]] - Successful response returns job id - - Examples - -------- - from label_studio_sdk import LabelStudio - - client = LabelStudio( - api_key="YOUR_API_KEY", - ) - client.projects.stats.update_stats( - id=1, - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/update-stats", - method="GET", - params={ - "stat_type": stat_type, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - typing.Dict[str, typing.Optional[typing.Any]], - construct_type( - type_=typing.Dict[str, typing.Optional[typing.Any]], # 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 user_prediction_agreement( - self, - id: int, - user_pk: int, - *, - per_label: typing.Optional[bool] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> StatsUserPredictionAgreementResponse: - """ - Get prediction agreement statistics for a specific user within a project. - - Parameters - ---------- - id : int - - user_pk : int - - per_label : typing.Optional[bool] - Calculate agreement per label - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - StatsUserPredictionAgreementResponse - Individual user prediction agreement statistics - - Examples - -------- - from label_studio_sdk import LabelStudio - - client = LabelStudio( - api_key="YOUR_API_KEY", - ) - client.projects.stats.user_prediction_agreement( - id=1, - user_pk=1, - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/user-stats/{jsonable_encoder(user_pk)}/prediction", - method="GET", - params={ - "per_label": per_label, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - StatsUserPredictionAgreementResponse, - construct_type( - type_=StatsUserPredictionAgreementResponse, # 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 user_review_score( - self, - id: int, - user_pk: int, - *, - per_label: typing.Optional[bool] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> StatsUserReviewScoreResponse: - """ - Get review score statistics for a specific user within a project. - - Parameters - ---------- - id : int - - user_pk : int - - per_label : typing.Optional[bool] - Calculate agreement per label - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - StatsUserReviewScoreResponse - Individual user review score statistics - - Examples - -------- - from label_studio_sdk import LabelStudio - - client = LabelStudio( - api_key="YOUR_API_KEY", - ) - client.projects.stats.user_review_score( - id=1, - user_pk=1, - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/user-stats/{jsonable_encoder(user_pk)}/review_score", - method="GET", - params={ - "per_label": per_label, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - StatsUserReviewScoreResponse, - construct_type( - type_=StatsUserReviewScoreResponse, # 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 user_ground_truth_agreement( - self, - id: int, - user_pk: int, - *, - per_label: typing.Optional[bool] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> StatsUserGroundTruthAgreementResponse: - """ - Get ground truth agreement statistics for a specific user within a project. - - Parameters - ---------- - id : int - - user_pk : int - - per_label : typing.Optional[bool] - Calculate agreement per label - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - StatsUserGroundTruthAgreementResponse - Individual user ground truth agreement statistics - - Examples - -------- - from label_studio_sdk import LabelStudio - - client = LabelStudio( - api_key="YOUR_API_KEY", - ) - client.projects.stats.user_ground_truth_agreement( - id=1, - user_pk=1, - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/users/{jsonable_encoder(user_pk)}/stats/agreement-groundtruth", - method="GET", - params={ - "per_label": per_label, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - StatsUserGroundTruthAgreementResponse, - construct_type( - type_=StatsUserGroundTruthAgreementResponse, # 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 AsyncStatsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def iaa( - self, - id: int, - *, - expand: typing.Optional[str] = None, - per_label: typing.Optional[bool] = None, - std: typing.Optional[bool] = None, - task: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> StatsIaaResponse: - """ - Get Inter-Annotator Agreement (IAA) matrix for a project, showing agreement between all annotators. - - Parameters - ---------- - id : int - - expand : typing.Optional[str] - Comma-separated list of fields to expand - - per_label : typing.Optional[bool] - Calculate IAA per label - - std : typing.Optional[bool] - Include standard deviation in results - - task : typing.Optional[str] - Comma-separated list of task IDs to filter by - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - StatsIaaResponse - Inter-Annotator Agreement matrix - - Examples - -------- - import asyncio - - from label_studio_sdk import AsyncLabelStudio - - client = AsyncLabelStudio( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.projects.stats.iaa( - id=1, - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/stats/IAA", - method="GET", - params={ - "expand": expand, - "per_label": per_label, - "std": std, - "task": task, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - StatsIaaResponse, - construct_type( - type_=StatsIaaResponse, # 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 agreement_annotator( - self, id: int, user_id: int, *, request_options: typing.Optional[RequestOptions] = None - ) -> StatsAgreementAnnotatorResponse: - """ - Get agreement statistics for a specific annotator within a project. - - Parameters - ---------- - id : int - - user_id : int - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - StatsAgreementAnnotatorResponse - Individual annotator agreement statistics - - Examples - -------- - import asyncio - - from label_studio_sdk import AsyncLabelStudio - - client = AsyncLabelStudio( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.projects.stats.agreement_annotator( - id=1, - user_id=1, - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/stats/agreement_annotator/{jsonable_encoder(user_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - StatsAgreementAnnotatorResponse, - construct_type( - type_=StatsAgreementAnnotatorResponse, # 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 data_filters( - self, id: int, *, request_options: typing.Optional[RequestOptions] = None - ) -> StatsDataFiltersResponse: - """ - Get statistics about user data filters and their usage within a project. - - Parameters - ---------- - id : int - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - StatsDataFiltersResponse - User data filter statistics - - Examples - -------- - import asyncio - - from label_studio_sdk import AsyncLabelStudio - - client = AsyncLabelStudio( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.projects.stats.data_filters( - id=1, - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/stats/data_filter", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - StatsDataFiltersResponse, - construct_type( - type_=StatsDataFiltersResponse, # 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 finished_tasks( - self, id: int, *, user_pk: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None - ) -> StatsFinishedTasksResponse: - """ - Get statistics about finished tasks for a project. - - Parameters - ---------- - id : int - - user_pk : typing.Optional[int] - User ID to filter statistics by (optional) - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - StatsFinishedTasksResponse - Finished tasks statistics - - Examples - -------- - import asyncio - - from label_studio_sdk import AsyncLabelStudio - - client = AsyncLabelStudio( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.projects.stats.finished_tasks( - id=1, - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/stats/finished", - method="GET", - params={ - "user_pk": user_pk, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - StatsFinishedTasksResponse, - construct_type( - type_=StatsFinishedTasksResponse, # 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 lead_time( - self, id: int, *, request_options: typing.Optional[RequestOptions] = None - ) -> StatsLeadTimeResponse: - """ - Get lead time statistics across the project, including average annotation time. - - Parameters - ---------- - id : int - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - StatsLeadTimeResponse - Lead time statistics - - Examples - -------- - import asyncio - - from label_studio_sdk import AsyncLabelStudio - - client = AsyncLabelStudio( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.projects.stats.lead_time( - id=1, - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/stats/lead_time", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - StatsLeadTimeResponse, - construct_type( - type_=StatsLeadTimeResponse, # 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 total_agreement( + def total_agreement( self, id: int, *, @@ -947,24 +118,16 @@ async def total_agreement( Examples -------- - import asyncio - - from label_studio_sdk import AsyncLabelStudio + from label_studio_sdk import LabelStudio - client = AsyncLabelStudio( + client = LabelStudio( api_key="YOUR_API_KEY", ) - - - async def main() -> None: - await client.projects.stats.total_agreement( - id=1, - ) - - - asyncio.run(main()) + client.projects.stats.total_agreement( + id=1, + ) """ - _response = await self._client_wrapper.httpx_client.request( + _response = self._client_wrapper.httpx_client.request( f"api/projects/{jsonable_encoder(id)}/stats/total_agreement", method="GET", params={ @@ -986,169 +149,47 @@ async def main() -> None: raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) - async def update_stats( - self, - id: int, - *, - stat_type: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> typing.Dict[str, typing.Optional[typing.Any]]: - """ - Start stats recalculation for given project - - Parameters - ---------- - id : int - - stat_type : typing.Optional[str] - Stat type to recalculate. Possible values: label, stats - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - typing.Dict[str, typing.Optional[typing.Any]] - Successful response returns job id - - Examples - -------- - import asyncio - - from label_studio_sdk import AsyncLabelStudio - - client = AsyncLabelStudio( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.projects.stats.update_stats( - id=1, - ) - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/update-stats", - method="GET", - params={ - "stat_type": stat_type, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - typing.Dict[str, typing.Optional[typing.Any]], - construct_type( - type_=typing.Dict[str, typing.Optional[typing.Any]], # 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 AsyncStatsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper - async def user_prediction_agreement( + async def iaa( self, id: int, - user_pk: int, *, + expand: typing.Optional[str] = None, per_label: typing.Optional[bool] = None, + std: typing.Optional[bool] = None, + task: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> StatsUserPredictionAgreementResponse: + ) -> StatsIaaResponse: """ - Get prediction agreement statistics for a specific user within a project. + Get Inter-Annotator Agreement (IAA) matrix for a project, showing agreement between all annotators. Parameters ---------- id : int - user_pk : int + expand : typing.Optional[str] + Comma-separated list of fields to expand per_label : typing.Optional[bool] - Calculate agreement per label - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - StatsUserPredictionAgreementResponse - Individual user prediction agreement statistics - - Examples - -------- - import asyncio - - from label_studio_sdk import AsyncLabelStudio - - client = AsyncLabelStudio( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.projects.stats.user_prediction_agreement( - id=1, - user_pk=1, - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/user-stats/{jsonable_encoder(user_pk)}/prediction", - method="GET", - params={ - "per_label": per_label, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - StatsUserPredictionAgreementResponse, - construct_type( - type_=StatsUserPredictionAgreementResponse, # 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 user_review_score( - self, - id: int, - user_pk: int, - *, - per_label: typing.Optional[bool] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> StatsUserReviewScoreResponse: - """ - Get review score statistics for a specific user within a project. - - Parameters - ---------- - id : int + Calculate IAA per label - user_pk : int + std : typing.Optional[bool] + Include standard deviation in results - per_label : typing.Optional[bool] - Calculate agreement per label + task : typing.Optional[str] + Comma-separated list of task IDs to filter by request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - StatsUserReviewScoreResponse - Individual user review score statistics + StatsIaaResponse + Inter-Annotator Agreement matrix Examples -------- @@ -1162,28 +203,30 @@ async def user_review_score( async def main() -> None: - await client.projects.stats.user_review_score( + await client.projects.stats.iaa( id=1, - user_pk=1, ) asyncio.run(main()) """ _response = await self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/user-stats/{jsonable_encoder(user_pk)}/review_score", + f"api/projects/{jsonable_encoder(id)}/stats/IAA", method="GET", params={ + "expand": expand, "per_label": per_label, + "std": std, + "task": task, }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: return typing.cast( - StatsUserReviewScoreResponse, + StatsIaaResponse, construct_type( - type_=StatsUserReviewScoreResponse, # type: ignore + type_=StatsIaaResponse, # type: ignore object_=_response.json(), ), ) @@ -1192,33 +235,32 @@ async def main() -> None: raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) - async def user_ground_truth_agreement( + async def total_agreement( self, id: int, - user_pk: int, *, per_label: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> StatsUserGroundTruthAgreementResponse: + ) -> StatsTotalAgreementResponse: """ - Get ground truth agreement statistics for a specific user within a project. + Overall or per-label total agreement across the project. + + NOTE: due to an open issue in Fern, SDK clients will raise ApiError upon handling a 204 response. As a workaround, wrap call to this function in a try-except block. Parameters ---------- id : int - user_pk : int - per_label : typing.Optional[bool] - Calculate agreement per label + Return agreement per label request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - StatsUserGroundTruthAgreementResponse - Individual user ground truth agreement statistics + StatsTotalAgreementResponse + Total agreement Examples -------- @@ -1232,16 +274,15 @@ async def user_ground_truth_agreement( async def main() -> None: - await client.projects.stats.user_ground_truth_agreement( + await client.projects.stats.total_agreement( id=1, - user_pk=1, ) asyncio.run(main()) """ _response = await self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/users/{jsonable_encoder(user_pk)}/stats/agreement-groundtruth", + f"api/projects/{jsonable_encoder(id)}/stats/total_agreement", method="GET", params={ "per_label": per_label, @@ -1251,9 +292,9 @@ async def main() -> None: try: if 200 <= _response.status_code < 300: return typing.cast( - StatsUserGroundTruthAgreementResponse, + StatsTotalAgreementResponse, construct_type( - type_=StatsUserGroundTruthAgreementResponse, # type: ignore + type_=StatsTotalAgreementResponse, # type: ignore object_=_response.json(), ), ) diff --git a/src/label_studio_sdk/projects/stats/types/__init__.py b/src/label_studio_sdk/projects/stats/types/__init__.py index 85fe87687..6c85c31f5 100644 --- a/src/label_studio_sdk/projects/stats/types/__init__.py +++ b/src/label_studio_sdk/projects/stats/types/__init__.py @@ -1,49 +1,19 @@ # This file was auto-generated by Fern from our API Definition. -from .stats_agreement_annotator_response import StatsAgreementAnnotatorResponse -from .stats_data_filters_response import StatsDataFiltersResponse -from .stats_data_filters_response_user_filters import StatsDataFiltersResponseUserFilters -from .stats_data_filters_response_user_filters_stats_item import StatsDataFiltersResponseUserFiltersStatsItem -from .stats_finished_tasks_response import StatsFinishedTasksResponse from .stats_iaa_response import StatsIaaResponse from .stats_iaa_response_common_tasks import StatsIaaResponseCommonTasks from .stats_iaa_response_iaa import StatsIaaResponseIaa from .stats_iaa_response_std import StatsIaaResponseStd -from .stats_lead_time_response import StatsLeadTimeResponse -from .stats_lead_time_response_lead_time_stats_item import StatsLeadTimeResponseLeadTimeStatsItem from .stats_total_agreement_response import StatsTotalAgreementResponse from .stats_total_agreement_response_one import StatsTotalAgreementResponseOne from .stats_total_agreement_response_zero import StatsTotalAgreementResponseZero -from .stats_user_ground_truth_agreement_response import StatsUserGroundTruthAgreementResponse -from .stats_user_ground_truth_agreement_response_agreement import StatsUserGroundTruthAgreementResponseAgreement -from .stats_user_prediction_agreement_response import StatsUserPredictionAgreementResponse -from .stats_user_prediction_agreement_response_average_prediction_agreement_per_user import ( - StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser, -) -from .stats_user_review_score_response import StatsUserReviewScoreResponse -from .stats_user_review_score_response_performance_score import StatsUserReviewScoreResponsePerformanceScore -from .stats_user_review_score_response_review_score import StatsUserReviewScoreResponseReviewScore __all__ = [ - "StatsAgreementAnnotatorResponse", - "StatsDataFiltersResponse", - "StatsDataFiltersResponseUserFilters", - "StatsDataFiltersResponseUserFiltersStatsItem", - "StatsFinishedTasksResponse", "StatsIaaResponse", "StatsIaaResponseCommonTasks", "StatsIaaResponseIaa", "StatsIaaResponseStd", - "StatsLeadTimeResponse", - "StatsLeadTimeResponseLeadTimeStatsItem", "StatsTotalAgreementResponse", "StatsTotalAgreementResponseOne", "StatsTotalAgreementResponseZero", - "StatsUserGroundTruthAgreementResponse", - "StatsUserGroundTruthAgreementResponseAgreement", - "StatsUserPredictionAgreementResponse", - "StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser", - "StatsUserReviewScoreResponse", - "StatsUserReviewScoreResponsePerformanceScore", - "StatsUserReviewScoreResponseReviewScore", ] diff --git a/src/label_studio_sdk/projects/stats/types/stats_agreement_annotator_response.py b/src/label_studio_sdk/projects/stats/types/stats_agreement_annotator_response.py deleted file mode 100644 index 2b349891f..000000000 --- a/src/label_studio_sdk/projects/stats/types/stats_agreement_annotator_response.py +++ /dev/null @@ -1,26 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ....core.unchecked_base_model import UncheckedBaseModel -import typing_extensions -import typing -from ....core.serialization import FieldMetadata -import pydantic -from ....core.pydantic_utilities import IS_PYDANTIC_V2 - - -class StatsAgreementAnnotatorResponse(UncheckedBaseModel): - agreement_per_annotator: typing_extensions.Annotated[ - typing.Optional[float], FieldMetadata(alias="Agreement_per_annotator") - ] = pydantic.Field(default=None) - """ - Agreement score for the annotator (0-1) - """ - - 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/projects/stats/types/stats_data_filters_response.py b/src/label_studio_sdk/projects/stats/types/stats_data_filters_response.py deleted file mode 100644 index acefc57bc..000000000 --- a/src/label_studio_sdk/projects/stats/types/stats_data_filters_response.py +++ /dev/null @@ -1,23 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ....core.unchecked_base_model import UncheckedBaseModel -import typing -from .stats_data_filters_response_user_filters import StatsDataFiltersResponseUserFilters -import pydantic -from ....core.pydantic_utilities import IS_PYDANTIC_V2 - - -class StatsDataFiltersResponse(UncheckedBaseModel): - user_filters: typing.Optional[StatsDataFiltersResponseUserFilters] = pydantic.Field(default=None) - """ - Data filter statistics by user and model - """ - - 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/projects/stats/types/stats_data_filters_response_user_filters.py b/src/label_studio_sdk/projects/stats/types/stats_data_filters_response_user_filters.py deleted file mode 100644 index d1937add9..000000000 --- a/src/label_studio_sdk/projects/stats/types/stats_data_filters_response_user_filters.py +++ /dev/null @@ -1,34 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ....core.unchecked_base_model import UncheckedBaseModel -import typing -from .stats_data_filters_response_user_filters_stats_item import StatsDataFiltersResponseUserFiltersStatsItem -import pydantic -from ....core.pydantic_utilities import IS_PYDANTIC_V2 - - -class StatsDataFiltersResponseUserFilters(UncheckedBaseModel): - """ - Data filter statistics by user and model - """ - - stats: typing.Optional[typing.List[StatsDataFiltersResponseUserFiltersStatsItem]] = pydantic.Field(default=None) - """ - List of filter configurations for users and models - """ - - tasks_with_annotations: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field( - default=None - ) - """ - Default filter tab for tasks with annotations - """ - - 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/projects/stats/types/stats_data_filters_response_user_filters_stats_item.py b/src/label_studio_sdk/projects/stats/types/stats_data_filters_response_user_filters_stats_item.py deleted file mode 100644 index 5839cd96c..000000000 --- a/src/label_studio_sdk/projects/stats/types/stats_data_filters_response_user_filters_stats_item.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ....core.unchecked_base_model import UncheckedBaseModel -import typing -import pydantic -from ....core.pydantic_utilities import IS_PYDANTIC_V2 - - -class StatsDataFiltersResponseUserFiltersStatsItem(UncheckedBaseModel): - id: typing.Optional[str] = pydantic.Field(default=None) - """ - User ID or model version identifier (e.g., "model:1.0") - """ - - 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/projects/stats/types/stats_finished_tasks_response.py b/src/label_studio_sdk/projects/stats/types/stats_finished_tasks_response.py deleted file mode 100644 index 65e7cdb7a..000000000 --- a/src/label_studio_sdk/projects/stats/types/stats_finished_tasks_response.py +++ /dev/null @@ -1,32 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ....core.unchecked_base_model import UncheckedBaseModel -import typing -import pydantic -from ....core.pydantic_utilities import IS_PYDANTIC_V2 - - -class StatsFinishedTasksResponse(UncheckedBaseModel): - finished: typing.Optional[int] = pydantic.Field(default=None) - """ - Number of finished tasks - """ - - id: typing.Optional[int] = pydantic.Field(default=None) - """ - User ID - """ - - progress: typing.Optional[int] = pydantic.Field(default=None) - """ - Progress percentage (0-100) - """ - - 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/projects/stats/types/stats_lead_time_response.py b/src/label_studio_sdk/projects/stats/types/stats_lead_time_response.py deleted file mode 100644 index d0175fb94..000000000 --- a/src/label_studio_sdk/projects/stats/types/stats_lead_time_response.py +++ /dev/null @@ -1,23 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ....core.unchecked_base_model import UncheckedBaseModel -import typing -from .stats_lead_time_response_lead_time_stats_item import StatsLeadTimeResponseLeadTimeStatsItem -import pydantic -from ....core.pydantic_utilities import IS_PYDANTIC_V2 - - -class StatsLeadTimeResponse(UncheckedBaseModel): - lead_time_stats: typing.Optional[typing.List[StatsLeadTimeResponseLeadTimeStatsItem]] = pydantic.Field(default=None) - """ - Lead time statistics including mean, median, and distribution - """ - - 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/projects/stats/types/stats_lead_time_response_lead_time_stats_item.py b/src/label_studio_sdk/projects/stats/types/stats_lead_time_response_lead_time_stats_item.py deleted file mode 100644 index d4fbca4b2..000000000 --- a/src/label_studio_sdk/projects/stats/types/stats_lead_time_response_lead_time_stats_item.py +++ /dev/null @@ -1,37 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ....core.unchecked_base_model import UncheckedBaseModel -import typing -import pydantic -from ....core.pydantic_utilities import IS_PYDANTIC_V2 - - -class StatsLeadTimeResponseLeadTimeStatsItem(UncheckedBaseModel): - mean_time: typing.Optional[float] = pydantic.Field(default=None) - """ - Average lead time for the user - """ - - median_time: typing.Optional[float] = pydantic.Field(default=None) - """ - Median lead time for the user - """ - - sum_lead_time: typing.Optional[float] = pydantic.Field(default=None) - """ - Total lead time for the user - """ - - user_id: typing.Optional[int] = pydantic.Field(default=None) - """ - User ID - """ - - 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/projects/stats/types/stats_user_ground_truth_agreement_response.py b/src/label_studio_sdk/projects/stats/types/stats_user_ground_truth_agreement_response.py deleted file mode 100644 index cf78669ea..000000000 --- a/src/label_studio_sdk/projects/stats/types/stats_user_ground_truth_agreement_response.py +++ /dev/null @@ -1,20 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ....core.unchecked_base_model import UncheckedBaseModel -import typing -from .stats_user_ground_truth_agreement_response_agreement import StatsUserGroundTruthAgreementResponseAgreement -from ....core.pydantic_utilities import IS_PYDANTIC_V2 -import pydantic - - -class StatsUserGroundTruthAgreementResponse(UncheckedBaseModel): - agreement: typing.Optional[StatsUserGroundTruthAgreementResponseAgreement] = None - - 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/projects/stats/types/stats_user_ground_truth_agreement_response_agreement.py b/src/label_studio_sdk/projects/stats/types/stats_user_ground_truth_agreement_response_agreement.py deleted file mode 100644 index e96b04a42..000000000 --- a/src/label_studio_sdk/projects/stats/types/stats_user_ground_truth_agreement_response_agreement.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -StatsUserGroundTruthAgreementResponseAgreement = typing.Union[float, typing.Dict[str, float]] diff --git a/src/label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response.py b/src/label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response.py deleted file mode 100644 index 71efcb3d3..000000000 --- a/src/label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response.py +++ /dev/null @@ -1,24 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ....core.unchecked_base_model import UncheckedBaseModel -import typing -from .stats_user_prediction_agreement_response_average_prediction_agreement_per_user import ( - StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser, -) -from ....core.pydantic_utilities import IS_PYDANTIC_V2 -import pydantic - - -class StatsUserPredictionAgreementResponse(UncheckedBaseModel): - average_prediction_agreement_per_user: typing.Optional[ - StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser - ] = None - - 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/projects/stats/types/stats_user_prediction_agreement_response_average_prediction_agreement_per_user.py b/src/label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response_average_prediction_agreement_per_user.py deleted file mode 100644 index 553a16b31..000000000 --- a/src/label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response_average_prediction_agreement_per_user.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser = typing.Union[float, typing.Dict[str, float]] diff --git a/src/label_studio_sdk/projects/stats/types/stats_user_review_score_response.py b/src/label_studio_sdk/projects/stats/types/stats_user_review_score_response.py deleted file mode 100644 index de7dcf7e9..000000000 --- a/src/label_studio_sdk/projects/stats/types/stats_user_review_score_response.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ....core.unchecked_base_model import UncheckedBaseModel -import typing -from .stats_user_review_score_response_performance_score import StatsUserReviewScoreResponsePerformanceScore -from .stats_user_review_score_response_review_score import StatsUserReviewScoreResponseReviewScore -from ....core.pydantic_utilities import IS_PYDANTIC_V2 -import pydantic - - -class StatsUserReviewScoreResponse(UncheckedBaseModel): - performance_score: typing.Optional[StatsUserReviewScoreResponsePerformanceScore] = None - review_score: typing.Optional[StatsUserReviewScoreResponseReviewScore] = None - - 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/projects/stats/types/stats_user_review_score_response_performance_score.py b/src/label_studio_sdk/projects/stats/types/stats_user_review_score_response_performance_score.py deleted file mode 100644 index cca02c711..000000000 --- a/src/label_studio_sdk/projects/stats/types/stats_user_review_score_response_performance_score.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -StatsUserReviewScoreResponsePerformanceScore = typing.Union[float, typing.Dict[str, float]] diff --git a/src/label_studio_sdk/projects/stats/types/stats_user_review_score_response_review_score.py b/src/label_studio_sdk/projects/stats/types/stats_user_review_score_response_review_score.py deleted file mode 100644 index 75909433d..000000000 --- a/src/label_studio_sdk/projects/stats/types/stats_user_review_score_response_review_score.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -StatsUserReviewScoreResponseReviewScore = typing.Union[float, typing.Dict[str, float]] diff --git a/src/label_studio_sdk/types/__init__.py b/src/label_studio_sdk/types/__init__.py index f539e9f73..916608b86 100644 --- a/src/label_studio_sdk/types/__init__.py +++ b/src/label_studio_sdk/types/__init__.py @@ -43,14 +43,13 @@ from .comment import Comment from .comment_request import CommentRequest from .comment_serializer_with_expanded_user import CommentSerializerWithExpandedUser -from .configurable_permission_option import ConfigurablePermissionOption -from .configurable_permission_option_default import ConfigurablePermissionOptionDefault from .converted_format import ConvertedFormat from .converted_format_request import ConvertedFormatRequest from .count_limit import CountLimit from .custom_scripts_editable_by_enum import CustomScriptsEditableByEnum from .default_role import DefaultRole from .default_role_custom_scripts_editable_by import DefaultRoleCustomScriptsEditableBy +from .default_role_enum import DefaultRoleEnum from .edition_enum import EditionEnum from .export import Export from .file_upload import FileUpload @@ -140,8 +139,6 @@ from .organization_invite import OrganizationInvite from .organization_member import OrganizationMember from .organization_membership import OrganizationMembership -from .organization_permission import OrganizationPermission -from .organization_permission_request import OrganizationPermissionRequest from .paginated_all_roles_project_list_list import PaginatedAllRolesProjectListList from .paginated_annotation_history_list import PaginatedAnnotationHistoryList from .paginated_lse_organization_member_list_list import PaginatedLseOrganizationMemberListList @@ -268,14 +265,13 @@ "Comment", "CommentRequest", "CommentSerializerWithExpandedUser", - "ConfigurablePermissionOption", - "ConfigurablePermissionOptionDefault", "ConvertedFormat", "ConvertedFormatRequest", "CountLimit", "CustomScriptsEditableByEnum", "DefaultRole", "DefaultRoleCustomScriptsEditableBy", + "DefaultRoleEnum", "EditionEnum", "Export", "FileUpload", @@ -365,8 +361,6 @@ "OrganizationInvite", "OrganizationMember", "OrganizationMembership", - "OrganizationPermission", - "OrganizationPermissionRequest", "PaginatedAllRolesProjectListList", "PaginatedAnnotationHistoryList", "PaginatedLseOrganizationMemberListList", diff --git a/src/label_studio_sdk/types/configurable_permission_option.py b/src/label_studio_sdk/types/configurable_permission_option.py deleted file mode 100644 index db9475f8e..000000000 --- a/src/label_studio_sdk/types/configurable_permission_option.py +++ /dev/null @@ -1,25 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ..core.unchecked_base_model import UncheckedBaseModel -import typing -from .configurable_permission_option_default import ConfigurablePermissionOptionDefault -from .role9e7enum import Role9E7Enum -from ..core.pydantic_utilities import IS_PYDANTIC_V2 -import pydantic - - -class ConfigurablePermissionOption(UncheckedBaseModel): - default: typing.Optional[ConfigurablePermissionOptionDefault] = None - label: typing.Optional[str] = None - options: typing.List[Role9E7Enum] - permission: str - tooltip: typing.Optional[str] = None - - 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/configurable_permission_option_default.py b/src/label_studio_sdk/types/configurable_permission_option_default.py deleted file mode 100644 index ee182d47a..000000000 --- a/src/label_studio_sdk/types/configurable_permission_option_default.py +++ /dev/null @@ -1,7 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from .role9e7enum import Role9E7Enum -from .null_enum import NullEnum - -ConfigurablePermissionOptionDefault = typing.Union[Role9E7Enum, NullEnum] diff --git a/src/label_studio_sdk/types/default_role.py b/src/label_studio_sdk/types/default_role.py index 0ad8ea3ac..fe031178a 100644 --- a/src/label_studio_sdk/types/default_role.py +++ b/src/label_studio_sdk/types/default_role.py @@ -5,7 +5,7 @@ import datetime as dt import pydantic from .default_role_custom_scripts_editable_by import DefaultRoleCustomScriptsEditableBy -from .role9e7enum import Role9E7Enum +from .default_role_enum import DefaultRoleEnum from ..core.pydantic_utilities import IS_PYDANTIC_V2 @@ -28,7 +28,7 @@ class DefaultRole(UncheckedBaseModel): Set to current time to enabled custom scripts for this organization. Can only be enabled if no organization members are active members of any other organizations; otherwise an error will be raised. If this occurs, contact the LEAP team for assistance with enabling custom scripts. """ - default_role: typing.Optional[Role9E7Enum] = pydantic.Field(default=None) + default_role: typing.Optional[DefaultRoleEnum] = pydantic.Field(default=None) """ Default membership role for invited users diff --git a/src/label_studio_sdk/types/default_role_enum.py b/src/label_studio_sdk/types/default_role_enum.py new file mode 100644 index 000000000..37e91a29c --- /dev/null +++ b/src/label_studio_sdk/types/default_role_enum.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +DefaultRoleEnum = typing.Union[typing.Literal["OW", "AD", "MA", "RE", "AN", "DI", "NO"], typing.Any] diff --git a/src/label_studio_sdk/types/lse_organization.py b/src/label_studio_sdk/types/lse_organization.py index 511a055e9..cfd182c7c 100644 --- a/src/label_studio_sdk/types/lse_organization.py +++ b/src/label_studio_sdk/types/lse_organization.py @@ -6,7 +6,7 @@ import typing from .lse_organization_custom_scripts_editable_by import LseOrganizationCustomScriptsEditableBy import pydantic -from .role9e7enum import Role9E7Enum +from .default_role_enum import DefaultRoleEnum from ..core.pydantic_utilities import IS_PYDANTIC_V2 @@ -22,7 +22,7 @@ class LseOrganization(UncheckedBaseModel): """ custom_scripts_enabled: str - default_role: typing.Optional[Role9E7Enum] = pydantic.Field(default=None) + default_role: typing.Optional[DefaultRoleEnum] = pydantic.Field(default=None) """ Default membership role for invited users diff --git a/src/label_studio_sdk/types/lse_user.py b/src/label_studio_sdk/types/lse_user.py index 5f146708c..b374650e2 100644 --- a/src/label_studio_sdk/types/lse_user.py +++ b/src/label_studio_sdk/types/lse_user.py @@ -35,6 +35,7 @@ class LseUser(UncheckedBaseModel): last_name: typing.Optional[str] = None lse_fields: LseFields org_membership: typing.List[OrganizationMembership] + organization_membership: OrganizationMembership pause: str phone: typing.Optional[str] = None username: str diff --git a/src/label_studio_sdk/types/lse_user_api.py b/src/label_studio_sdk/types/lse_user_api.py index b7ca5dd85..8ac956e36 100644 --- a/src/label_studio_sdk/types/lse_user_api.py +++ b/src/label_studio_sdk/types/lse_user_api.py @@ -33,6 +33,7 @@ class LseUserApi(UncheckedBaseModel): last_activity: dt.datetime last_name: typing.Optional[str] = None org_membership: typing.List[OrganizationMembership] + organization_membership: OrganizationMembership phone: typing.Optional[str] = None username: str diff --git a/src/label_studio_sdk/types/organization_permission.py b/src/label_studio_sdk/types/organization_permission.py deleted file mode 100644 index e9ca4c416..000000000 --- a/src/label_studio_sdk/types/organization_permission.py +++ /dev/null @@ -1,31 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ..core.unchecked_base_model import UncheckedBaseModel -import typing -from .role9e7enum import Role9E7Enum -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2 - - -class OrganizationPermission(UncheckedBaseModel): - default_role: str - id: int - label: str - options: str - organization: int - permission: str - roles: typing.Optional[typing.List[Role9E7Enum]] = pydantic.Field(default=None) - """ - Explicit roles that have this permission within the organization. - """ - - tooltip: str - - 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/organization_permission_request.py b/src/label_studio_sdk/types/organization_permission_request.py deleted file mode 100644 index 6f333242a..000000000 --- a/src/label_studio_sdk/types/organization_permission_request.py +++ /dev/null @@ -1,24 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ..core.unchecked_base_model import UncheckedBaseModel -import typing -from .role9e7enum import Role9E7Enum -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2 - - -class OrganizationPermissionRequest(UncheckedBaseModel): - permission: str - roles: typing.Optional[typing.List[Role9E7Enum]] = pydantic.Field(default=None) - """ - Explicit roles that have this permission within the organization. - """ - - 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/paginated_project_member.py b/src/label_studio_sdk/types/paginated_project_member.py index aaa72a4ed..5ae248237 100644 --- a/src/label_studio_sdk/types/paginated_project_member.py +++ b/src/label_studio_sdk/types/paginated_project_member.py @@ -35,6 +35,7 @@ class PaginatedProjectMember(UncheckedBaseModel): last_name: typing.Optional[str] = None lse_fields: LseFields org_membership: typing.List[OrganizationMembership] + organization_membership: OrganizationMembership pause: str phone: typing.Optional[str] = None project_role: str diff --git a/src/label_studio_sdk/types/who_am_i_user.py b/src/label_studio_sdk/types/who_am_i_user.py index cfc4138eb..91648ab49 100644 --- a/src/label_studio_sdk/types/who_am_i_user.py +++ b/src/label_studio_sdk/types/who_am_i_user.py @@ -35,6 +35,7 @@ class WhoAmIUser(UncheckedBaseModel): last_name: typing.Optional[str] = None lse_fields: WhoAmILseFields org_membership: typing.List[OrganizationMembership] + organization_membership: OrganizationMembership pause: str permissions: typing.List[str] phone: typing.Optional[str] = None diff --git a/tests/organizations/test_permissions.py b/tests/organizations/test_permissions.py deleted file mode 100644 index 813475542..000000000 --- a/tests/organizations/test_permissions.py +++ /dev/null @@ -1,183 +0,0 @@ -# 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 = [ - { - "default_role": "default_role", - "id": 1, - "label": "label", - "options": "options", - "organization": 1, - "permission": "permission", - "roles": ["OW"], - "tooltip": "tooltip", - } - ] - expected_types: typing.Tuple[typing.Any, typing.Any] = ( - "list", - { - 0: { - "default_role": None, - "id": "integer", - "label": None, - "options": None, - "organization": "integer", - "permission": None, - "roles": ("list", {0: None}), - "tooltip": None, - } - }, - ) - response = client.organizations.permissions.list(id=1) - validate_response(response, expected_response, expected_types) - - async_response = await async_client.organizations.permissions.list(id=1) - validate_response(async_response, expected_response, expected_types) - - -async def test_create(client: LabelStudio, async_client: AsyncLabelStudio) -> None: - expected_response: typing.Any = { - "default_role": "default_role", - "id": 1, - "label": "label", - "options": "options", - "organization": 1, - "permission": "permission", - "roles": ["OW"], - "tooltip": "tooltip", - } - expected_types: typing.Any = { - "default_role": None, - "id": "integer", - "label": None, - "options": None, - "organization": "integer", - "permission": None, - "roles": ("list", {0: None}), - "tooltip": None, - } - response = client.organizations.permissions.create(id=1, permission="permission") - validate_response(response, expected_response, expected_types) - - async_response = await async_client.organizations.permissions.create(id=1, permission="permission") - validate_response(async_response, expected_response, expected_types) - - -async def test_get_options(client: LabelStudio, async_client: AsyncLabelStudio) -> None: - expected_response: typing.Any = [ - {"default": "OW", "label": "label", "options": ["OW"], "permission": "permission", "tooltip": "tooltip"} - ] - expected_types: typing.Tuple[typing.Any, typing.Any] = ( - "list", - {0: {"default": None, "label": None, "options": ("list", {0: None}), "permission": None, "tooltip": None}}, - ) - response = client.organizations.permissions.get_options(id=1) - validate_response(response, expected_response, expected_types) - - async_response = await async_client.organizations.permissions.get_options(id=1) - validate_response(async_response, expected_response, expected_types) - - -async def test_get(client: LabelStudio, async_client: AsyncLabelStudio) -> None: - expected_response: typing.Any = { - "default_role": "default_role", - "id": 1, - "label": "label", - "options": "options", - "organization": 1, - "permission": "permission", - "roles": ["OW"], - "tooltip": "tooltip", - } - expected_types: typing.Any = { - "default_role": None, - "id": "integer", - "label": None, - "options": None, - "organization": "integer", - "permission": None, - "roles": ("list", {0: None}), - "tooltip": None, - } - response = client.organizations.permissions.get(id=1, permission="permission") - validate_response(response, expected_response, expected_types) - - async_response = await async_client.organizations.permissions.get(id=1, permission="permission") - validate_response(async_response, expected_response, expected_types) - - -async def test_replace(client: LabelStudio, async_client: AsyncLabelStudio) -> None: - expected_response: typing.Any = { - "default_role": "default_role", - "id": 1, - "label": "label", - "options": "options", - "organization": 1, - "permission": "permission", - "roles": ["OW"], - "tooltip": "tooltip", - } - expected_types: typing.Any = { - "default_role": None, - "id": "integer", - "label": None, - "options": None, - "organization": "integer", - "permission": None, - "roles": ("list", {0: None}), - "tooltip": None, - } - response = client.organizations.permissions.replace(id=1, permission_="permission", permission="permission") - validate_response(response, expected_response, expected_types) - - async_response = await async_client.organizations.permissions.replace( - id=1, permission_="permission", permission="permission" - ) - validate_response(async_response, expected_response, expected_types) - - -async def test_delete(client: LabelStudio, async_client: AsyncLabelStudio) -> None: - # Type ignore to avoid mypy complaining about the function not being meant to return a value - assert ( - client.organizations.permissions.delete(id=1, permission="permission") # type: ignore[func-returns-value] - is None - ) - - assert ( - await async_client.organizations.permissions.delete(id=1, permission="permission") # type: ignore[func-returns-value] - is None - ) - - -async def test_update(client: LabelStudio, async_client: AsyncLabelStudio) -> None: - expected_response: typing.Any = { - "default_role": "default_role", - "id": 1, - "label": "label", - "options": "options", - "organization": 1, - "permission": "permission", - "roles": ["OW"], - "tooltip": "tooltip", - } - expected_types: typing.Any = { - "default_role": None, - "id": "integer", - "label": None, - "options": None, - "organization": "integer", - "permission": None, - "roles": ("list", {0: None}), - "tooltip": None, - } - response = client.organizations.permissions.update(id=1, permission="permission") - validate_response(response, expected_response, expected_types) - - async_response = await async_client.organizations.permissions.update(id=1, permission="permission") - validate_response(async_response, expected_response, expected_types) diff --git a/tests/projects/test_members.py b/tests/projects/test_members.py index 330af2695..bc984ef0c 100644 --- a/tests/projects/test_members.py +++ b/tests/projects/test_members.py @@ -37,6 +37,7 @@ async def test_get(client: LabelStudio, async_client: AsyncLabelStudio) -> None: "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", @@ -74,6 +75,7 @@ async def test_get(client: LabelStudio, async_client: AsyncLabelStudio) -> 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, diff --git a/tests/projects/test_stats.py b/tests/projects/test_stats.py index 0a36d76af..f1e74a60a 100644 --- a/tests/projects/test_stats.py +++ b/tests/projects/test_stats.py @@ -29,55 +29,6 @@ async def test_iaa(client: LabelStudio, async_client: AsyncLabelStudio) -> None: validate_response(async_response, expected_response, expected_types) -async def test_agreement_annotator(client: LabelStudio, async_client: AsyncLabelStudio) -> None: - expected_response: typing.Any = {"Agreement_per_annotator": 1.1} - expected_types: typing.Any = {"Agreement_per_annotator": None} - response = client.projects.stats.agreement_annotator(id=1, user_id=1) - validate_response(response, expected_response, expected_types) - - async_response = await async_client.projects.stats.agreement_annotator(id=1, user_id=1) - validate_response(async_response, expected_response, expected_types) - - -async def test_data_filters(client: LabelStudio, async_client: AsyncLabelStudio) -> None: - expected_response: typing.Any = {"user_filters": {"stats": [{}], "tasks_with_annotations": {"key": "value"}}} - expected_types: typing.Any = { - "user_filters": {"stats": ("list", {0: {}}), "tasks_with_annotations": ("dict", {0: (None, None)})} - } - response = client.projects.stats.data_filters(id=1) - validate_response(response, expected_response, expected_types) - - async_response = await async_client.projects.stats.data_filters(id=1) - validate_response(async_response, expected_response, expected_types) - - -async def test_finished_tasks(client: LabelStudio, async_client: AsyncLabelStudio) -> None: - expected_response: typing.Any = {"finished": 1, "id": 1, "progress": 1} - expected_types: typing.Any = {"finished": "integer", "id": "integer", "progress": "integer"} - response = client.projects.stats.finished_tasks(id=1) - validate_response(response, expected_response, expected_types) - - async_response = await async_client.projects.stats.finished_tasks(id=1) - validate_response(async_response, expected_response, expected_types) - - -async def test_lead_time(client: LabelStudio, async_client: AsyncLabelStudio) -> None: - expected_response: typing.Any = { - "lead_time_stats": [{"mean_time": 1.1, "median_time": 1.1, "sum_lead_time": 1.1, "user_id": 1}] - } - expected_types: typing.Any = { - "lead_time_stats": ( - "list", - {0: {"mean_time": None, "median_time": None, "sum_lead_time": None, "user_id": "integer"}}, - ) - } - response = client.projects.stats.lead_time(id=1) - validate_response(response, expected_response, expected_types) - - async_response = await async_client.projects.stats.lead_time(id=1) - validate_response(async_response, expected_response, expected_types) - - async def test_total_agreement(client: LabelStudio, async_client: AsyncLabelStudio) -> None: expected_response: typing.Any = {"total_agreement": 1.1} expected_types: typing.Any = {"total_agreement": None} @@ -86,43 +37,3 @@ async def test_total_agreement(client: LabelStudio, async_client: AsyncLabelStud async_response = await async_client.projects.stats.total_agreement(id=1) validate_response(async_response, expected_response, expected_types) - - -async def test_update_stats(client: LabelStudio, async_client: AsyncLabelStudio) -> None: - expected_response: typing.Any = {"key": "value"} - expected_types: typing.Tuple[typing.Any, typing.Any] = ("dict", {0: (None, None)}) - response = client.projects.stats.update_stats(id=1) - validate_response(response, expected_response, expected_types) - - async_response = await async_client.projects.stats.update_stats(id=1) - validate_response(async_response, expected_response, expected_types) - - -async def test_user_prediction_agreement(client: LabelStudio, async_client: AsyncLabelStudio) -> None: - expected_response: typing.Any = {"average_prediction_agreement_per_user": 1.1} - expected_types: typing.Any = {"average_prediction_agreement_per_user": None} - response = client.projects.stats.user_prediction_agreement(id=1, user_pk=1) - validate_response(response, expected_response, expected_types) - - async_response = await async_client.projects.stats.user_prediction_agreement(id=1, user_pk=1) - validate_response(async_response, expected_response, expected_types) - - -async def test_user_review_score(client: LabelStudio, async_client: AsyncLabelStudio) -> None: - expected_response: typing.Any = {"performance_score": 1.1, "review_score": 1.1} - expected_types: typing.Any = {"performance_score": None, "review_score": None} - response = client.projects.stats.user_review_score(id=1, user_pk=1) - validate_response(response, expected_response, expected_types) - - async_response = await async_client.projects.stats.user_review_score(id=1, user_pk=1) - validate_response(async_response, expected_response, expected_types) - - -async def test_user_ground_truth_agreement(client: LabelStudio, async_client: AsyncLabelStudio) -> None: - expected_response: typing.Any = {"agreement": 1.1} - expected_types: typing.Any = {"agreement": None} - response = client.projects.stats.user_ground_truth_agreement(id=1, user_pk=1) - validate_response(response, expected_response, expected_types) - - async_response = await async_client.projects.stats.user_ground_truth_agreement(id=1, user_pk=1) - validate_response(async_response, expected_response, expected_types) diff --git a/tests/test_users.py b/tests/test_users.py index bcaef4118..6d3a0cbd0 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -21,6 +21,7 @@ async def test_get_current_user(client: LabelStudio, async_client: AsyncLabelStu "last_activity": "2024-01-15T09:30:00Z", "last_name": "last_name", "org_membership": [{"active": "active", "organization_id": 1, "role": "role"}], + "organization_membership": {"active": "active", "organization_id": 1, "role": "role"}, "phone": "phone", "username": "username", } @@ -38,6 +39,7 @@ async def test_get_current_user(client: LabelStudio, async_client: AsyncLabelStu "last_activity": "datetime", "last_name": None, "org_membership": ("list", {0: {"active": None, "organization_id": "integer", "role": None}}), + "organization_membership": {"active": None, "organization_id": "integer", "role": None}, "phone": None, "username": None, } @@ -63,6 +65,7 @@ async def test_update_current_user(client: LabelStudio, async_client: AsyncLabel "last_activity": "2024-01-15T09:30:00Z", "last_name": "last_name", "org_membership": [{"active": "active", "organization_id": 1, "role": "role"}], + "organization_membership": {"active": "active", "organization_id": 1, "role": "role"}, "phone": "phone", "username": "username", } @@ -80,6 +83,7 @@ async def test_update_current_user(client: LabelStudio, async_client: AsyncLabel "last_activity": "datetime", "last_name": None, "org_membership": ("list", {0: {"active": None, "organization_id": "integer", "role": None}}), + "organization_membership": {"active": None, "organization_id": "integer", "role": None}, "phone": None, "username": None, } @@ -161,6 +165,7 @@ async def test_whoami(client: LabelStudio, async_client: AsyncLabelStudio) -> No "trial_role": "annotator", }, "org_membership": [{"active": "active", "organization_id": 1, "role": "role"}], + "organization_membership": {"active": "active", "organization_id": 1, "role": "role"}, "pause": "pause", "permissions": ["permissions"], "phone": "phone", @@ -196,6 +201,7 @@ async def test_whoami(client: LabelStudio, async_client: AsyncLabelStudio) -> No "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, "permissions": ("list", {0: None}), "phone": None, @@ -224,6 +230,7 @@ async def test_list_(client: LabelStudio, async_client: AsyncLabelStudio) -> Non "last_activity": "2024-01-15T09:30:00Z", "last_name": "last_name", "org_membership": [{"active": "active", "organization_id": 1, "role": "role"}], + "organization_membership": {"active": "active", "organization_id": 1, "role": "role"}, "phone": "phone", "username": "username", } @@ -245,6 +252,7 @@ async def test_list_(client: LabelStudio, async_client: AsyncLabelStudio) -> Non "last_activity": "datetime", "last_name": None, "org_membership": ("list", {0: {"active": None, "organization_id": "integer", "role": None}}), + "organization_membership": {"active": None, "organization_id": "integer", "role": None}, "phone": None, "username": None, } @@ -287,6 +295,7 @@ async def test_create(client: LabelStudio, async_client: AsyncLabelStudio) -> No "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", @@ -320,6 +329,7 @@ async def test_create(client: LabelStudio, async_client: AsyncLabelStudio) -> No "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, @@ -361,6 +371,7 @@ async def test_get(client: LabelStudio, async_client: AsyncLabelStudio) -> None: "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", @@ -394,6 +405,7 @@ async def test_get(client: LabelStudio, async_client: AsyncLabelStudio) -> 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, @@ -448,6 +460,7 @@ async def test_update(client: LabelStudio, async_client: AsyncLabelStudio) -> No "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", @@ -481,6 +494,7 @@ async def test_update(client: LabelStudio, async_client: AsyncLabelStudio) -> No "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, diff --git a/tests/workspaces/test_members.py b/tests/workspaces/test_members.py index e20d22bfc..d4926043a 100644 --- a/tests/workspaces/test_members.py +++ b/tests/workspaces/test_members.py @@ -28,6 +28,7 @@ async def test_list_(client: LabelStudio, async_client: AsyncLabelStudio) -> Non "invite_expired_at": "invite_expired_at", }, "org_membership": [{"active": "active", "organization_id": 1, "role": "role"}], + "organization_membership": {"active": "active", "organization_id": 1, "role": "role"}, "pause": "pause", "phone": "phone", "username": "username", @@ -58,6 +59,7 @@ async def test_list_(client: LabelStudio, async_client: AsyncLabelStudio) -> Non "invite_expired_at": 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, From 72f945579ded672eb978cbe8b2ea7176ac3864ec Mon Sep 17 00:00:00 2001 From: fern-api <115122769+fern-api[bot]@users.noreply.github.com> Date: Fri, 19 Sep 2025 20:09:59 +0000 Subject: [PATCH 2/6] SDK regeneration --- .mock/definition/__package__.yml | 69 +- .mock/definition/organizations.yml | 2 +- .../definition/organizations/permissions.yml | 267 +++ .mock/definition/projects/stats.yml | 355 ++++ .mock/definition/stats.yml | 240 --- .mock/openapi/openapi.yaml | 549 +++++- reference.md | 1471 +++++++++++++++-- src/label_studio_sdk/__init__.py | 10 +- .../organizations/__init__.py | 4 +- src/label_studio_sdk/organizations/client.py | 14 +- .../organizations/permissions/__init__.py | 2 + .../organizations/permissions/client.py | 1129 +++++++++++++ src/label_studio_sdk/projects/__init__.py | 28 + .../projects/stats/__init__.py | 28 + src/label_studio_sdk/projects/stats/client.py | 1045 +++++++++++- .../projects/stats/types/__init__.py | 30 + .../stats_agreement_annotator_response.py | 26 + .../types/stats_data_filters_response.py | 23 + ...tats_data_filters_response_user_filters.py | 34 + ...ilters_response_user_filters_stats_item.py | 22 + .../types/stats_finished_tasks_response.py | 32 + .../stats/types/stats_lead_time_response.py | 23 + ...lead_time_response_lead_time_stats_item.py | 37 + ...ts_user_ground_truth_agreement_response.py | 20 + ...ound_truth_agreement_response_agreement.py | 5 + ...tats_user_prediction_agreement_response.py | 24 + ...e_average_prediction_agreement_per_user.py | 5 + .../types/stats_user_review_score_response.py | 22 + ...review_score_response_performance_score.py | 5 + ...user_review_score_response_review_score.py | 5 + src/label_studio_sdk/types/__init__.py | 10 +- .../types/configurable_permission_option.py | 25 + .../configurable_permission_option_default.py | 7 + src/label_studio_sdk/types/default_role.py | 4 +- .../types/default_role_enum.py | 5 - .../types/lse_organization.py | 4 +- .../types/organization_permission.py | 31 + .../types/organization_permission_request.py | 24 + tests/organizations/test_permissions.py | 183 ++ tests/projects/test_stats.py | 89 + 40 files changed, 5409 insertions(+), 499 deletions(-) create mode 100644 .mock/definition/organizations/permissions.yml create mode 100644 src/label_studio_sdk/organizations/permissions/__init__.py create mode 100644 src/label_studio_sdk/organizations/permissions/client.py create mode 100644 src/label_studio_sdk/projects/stats/types/stats_agreement_annotator_response.py create mode 100644 src/label_studio_sdk/projects/stats/types/stats_data_filters_response.py create mode 100644 src/label_studio_sdk/projects/stats/types/stats_data_filters_response_user_filters.py create mode 100644 src/label_studio_sdk/projects/stats/types/stats_data_filters_response_user_filters_stats_item.py create mode 100644 src/label_studio_sdk/projects/stats/types/stats_finished_tasks_response.py create mode 100644 src/label_studio_sdk/projects/stats/types/stats_lead_time_response.py create mode 100644 src/label_studio_sdk/projects/stats/types/stats_lead_time_response_lead_time_stats_item.py create mode 100644 src/label_studio_sdk/projects/stats/types/stats_user_ground_truth_agreement_response.py create mode 100644 src/label_studio_sdk/projects/stats/types/stats_user_ground_truth_agreement_response_agreement.py create mode 100644 src/label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response.py create mode 100644 src/label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response_average_prediction_agreement_per_user.py create mode 100644 src/label_studio_sdk/projects/stats/types/stats_user_review_score_response.py create mode 100644 src/label_studio_sdk/projects/stats/types/stats_user_review_score_response_performance_score.py create mode 100644 src/label_studio_sdk/projects/stats/types/stats_user_review_score_response_review_score.py create mode 100644 src/label_studio_sdk/types/configurable_permission_option.py create mode 100644 src/label_studio_sdk/types/configurable_permission_option_default.py delete mode 100644 src/label_studio_sdk/types/default_role_enum.py create mode 100644 src/label_studio_sdk/types/organization_permission.py create mode 100644 src/label_studio_sdk/types/organization_permission_request.py create mode 100644 tests/organizations/test_permissions.py diff --git a/.mock/definition/__package__.yml b/.mock/definition/__package__.yml index 0fdf3e2fb..23b5c85fd 100644 --- a/.mock/definition/__package__.yml +++ b/.mock/definition/__package__.yml @@ -1620,6 +1620,23 @@ types: docs: Last updated time source: openapi: openapi/openapi.yaml + ConfigurablePermissionOptionDefault: + discriminated: false + union: + - Role9E7Enum + - NullEnum + source: + openapi: openapi/openapi.yaml + inline: true + ConfigurablePermissionOption: + properties: + default: optional + label: optional + options: list + permission: string + tooltip: optional + source: + openapi: openapi/openapi.yaml ConvertedFormat: properties: export_type: @@ -2160,7 +2177,7 @@ types: occurs, contact the LEAP team for assistance with enabling custom scripts. default_role: - type: optional + type: optional docs: |- Default membership role for invited users @@ -2194,25 +2211,6 @@ types: quick view. source: openapi: openapi/openapi.yaml - DefaultRoleEnum: - enum: - - OW - - AD - - MA - - RE - - AN - - DI - - 'NO' - docs: |- - * `OW` - Owner - * `AD` - Administrator - * `MA` - Manager - * `RE` - Reviewer - * `AN` - Annotator - * `DI` - Deactivated - * `NO` - Not Activated - source: - openapi: openapi/openapi.yaml EditionEnum: enum: - Community @@ -3604,7 +3602,7 @@ types: * `MA` - Manager custom_scripts_enabled: string default_role: - type: optional + type: optional docs: |- Default membership role for invited users @@ -5704,6 +5702,35 @@ types: minLength: 1 source: openapi: openapi/openapi.yaml + OrganizationPermission: + properties: + default_role: string + id: integer + label: string + options: string + organization: integer + permission: + type: string + validation: + maxLength: 255 + roles: + type: optional> + docs: Explicit roles that have this permission within the organization. + tooltip: string + source: + openapi: openapi/openapi.yaml + OrganizationPermissionRequest: + properties: + permission: + type: string + validation: + minLength: 1 + maxLength: 255 + roles: + type: optional> + docs: Explicit roles that have this permission within the organization. + source: + openapi: openapi/openapi.yaml PaginatedAllRolesProjectListList: properties: count: integer diff --git a/.mock/definition/organizations.yml b/.mock/definition/organizations.yml index 59cba9e71..4c0156410 100644 --- a/.mock/definition/organizations.yml +++ b/.mock/definition/organizations.yml @@ -200,7 +200,7 @@ service: will be raised. If this occurs, contact the LEAP team for assistance with enabling custom scripts. default_role: - type: optional + type: optional docs: |- Default membership role for invited users diff --git a/.mock/definition/organizations/permissions.yml b/.mock/definition/organizations/permissions.yml new file mode 100644 index 000000000..aaf7f88ca --- /dev/null +++ b/.mock/definition/organizations/permissions.yml @@ -0,0 +1,267 @@ +imports: + root: ../__package__.yml +service: + auth: false + base-path: '' + endpoints: + list: + path: /api/organizations/{id}/permissions + method: GET + auth: true + docs: >- + List all organization-level permission overrides for a given + organization. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + display-name: List organization permission overrides + request: + name: PermissionsListRequest + query-parameters: + ordering: + type: optional + docs: Which field to use when ordering the results. + response: + docs: '' + type: list + examples: + - path-parameters: + id: 1 + response: + body: + - default_role: default_role + id: 1 + label: label + options: options + organization: 1 + permission: permission + roles: + - OW + tooltip: tooltip + audiences: + - public + create: + path: /api/organizations/{id}/permissions + method: POST + auth: true + docs: >- + Create a new organization-level permission override for a given + organization. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + display-name: Create organization permission override + request: + body: root.OrganizationPermissionRequest + content-type: application/json + response: + docs: '' + type: root.OrganizationPermission + errors: + - root.BadRequestError + - root.ForbiddenError + examples: + - path-parameters: + id: 1 + request: + permission: permission + response: + body: + default_role: default_role + id: 1 + label: label + options: options + organization: 1 + permission: permission + roles: + - OW + tooltip: tooltip + audiences: + - public + get_options: + path: /api/organizations/{id}/permissions/options + method: GET + auth: true + docs: >- + Retrieve the list of configurable permission options (label, tooltip, + default role and allowed roles). + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + display-name: Get configurable permissions options + request: + name: PermissionsGetOptionsRequest + query-parameters: + ordering: + type: optional + docs: Which field to use when ordering the results. + response: + docs: '' + type: list + examples: + - path-parameters: + id: 1 + response: + body: + - default: OW + label: label + options: + - OW + permission: permission + tooltip: tooltip + audiences: + - public + get: + path: /api/organizations/{id}/permissions/{permission} + method: GET + auth: true + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + permission: string + display-name: Retrieve organization permission override + response: + docs: '' + type: root.OrganizationPermission + errors: + - root.ForbiddenError + - root.NotFoundError + examples: + - path-parameters: + id: 1 + permission: permission + response: + body: + default_role: default_role + id: 1 + label: label + options: options + organization: 1 + permission: permission + roles: + - OW + tooltip: tooltip + audiences: + - public + replace: + path: /api/organizations/{id}/permissions/{permission} + method: PUT + auth: true + docs: >- + Replace the organization-level permission override for a given + permission key. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: + type: integer + docs: A unique integer value identifying this organization. + permission: + type: string + docs: Permission key to update within the organization. + display-name: Replace organization permission override + request: + body: root.OrganizationPermissionRequest + content-type: application/json + response: + docs: '' + type: root.OrganizationPermission + errors: + - root.BadRequestError + - root.ForbiddenError + - root.NotFoundError + examples: + - path-parameters: + id: 1 + permission: permission + request: + permission: permission + response: + body: + default_role: default_role + id: 1 + label: label + options: options + organization: 1 + permission: permission + roles: + - OW + tooltip: tooltip + audiences: + - public + delete: + path: /api/organizations/{id}/permissions/{permission} + method: DELETE + auth: true + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + permission: string + display-name: Delete organization permission override + errors: + - root.ForbiddenError + - root.NotFoundError + examples: + - path-parameters: + id: 1 + permission: permission + audiences: + - public + update: + path: /api/organizations/{id}/permissions/{permission} + method: PATCH + auth: true + docs: >- + Partially update the organization-level permission override for a given + permission key. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + permission: string + display-name: Update organization permission override + request: + name: PatchedOrganizationPermissionRequest + body: + properties: + permission: + type: optional + name: patchedOrganizationPermissionRequestPermission + roles: + type: optional> + docs: >- + Explicit roles that have this permission within the + organization. + content-type: application/json + response: + docs: '' + type: root.OrganizationPermission + errors: + - root.BadRequestError + - root.ForbiddenError + - root.NotFoundError + examples: + - path-parameters: + id: 1 + permission: permission + request: {} + response: + body: + default_role: default_role + id: 1 + label: label + options: options + organization: 1 + permission: permission + roles: + - OW + tooltip: tooltip + audiences: + - public + source: + openapi: openapi/openapi.yaml diff --git a/.mock/definition/projects/stats.yml b/.mock/definition/projects/stats.yml index d8c8e4e92..ecf24f8d4 100644 --- a/.mock/definition/projects/stats.yml +++ b/.mock/definition/projects/stats.yml @@ -61,6 +61,77 @@ types: docs: List of users in the matrix source: openapi: openapi/openapi.yaml + StatsAgreementAnnotatorResponse: + properties: + Agreement_per_annotator: + type: optional + docs: Agreement score for the annotator (0-1) + source: + openapi: openapi/openapi.yaml + StatsDataFiltersResponseUserFiltersStatsItem: + properties: + id: + type: optional + docs: User ID or model version identifier (e.g., "model:1.0") + source: + openapi: openapi/openapi.yaml + inline: true + StatsDataFiltersResponseUserFilters: + docs: Data filter statistics by user and model + properties: + stats: + type: optional> + docs: List of filter configurations for users and models + tasks_with_annotations: + type: optional> + docs: Default filter tab for tasks with annotations + source: + openapi: openapi/openapi.yaml + inline: true + StatsDataFiltersResponse: + properties: + user_filters: + type: optional + docs: Data filter statistics by user and model + source: + openapi: openapi/openapi.yaml + StatsFinishedTasksResponse: + properties: + finished: + type: optional + docs: Number of finished tasks + id: + type: optional + docs: User ID + progress: + type: optional + docs: Progress percentage (0-100) + source: + openapi: openapi/openapi.yaml + StatsLeadTimeResponseLeadTimeStatsItem: + properties: + mean_time: + type: optional + docs: Average lead time for the user + median_time: + type: optional + docs: Median lead time for the user + sum_lead_time: + type: optional + docs: Total lead time for the user + user_id: + type: optional + docs: User ID + source: + openapi: openapi/openapi.yaml + inline: true + StatsLeadTimeResponse: + properties: + lead_time_stats: + type: optional> + docs: Lead time statistics including mean, median, and distribution + source: + openapi: openapi/openapi.yaml StatsTotalAgreementResponseZero: properties: total_agreement: optional @@ -80,6 +151,67 @@ types: - StatsTotalAgreementResponseOne source: openapi: openapi/openapi.yaml + StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser: + discriminated: false + union: + - type: double + docs: >- + Average prediction agreement score for the user (0-1) when + per_label=False + - type: map + docs: >- + Average prediction agreement score per label for the user (0-1) when + per_label=True + source: + openapi: openapi/openapi.yaml + inline: true + StatsUserPredictionAgreementResponse: + properties: + average_prediction_agreement_per_user: >- + optional + source: + openapi: openapi/openapi.yaml + StatsUserReviewScoreResponsePerformanceScore: + discriminated: false + union: + - type: double + docs: Performance score for the user when per_label=False + - type: map + docs: Performance score per label for the user when per_label=True + source: + openapi: openapi/openapi.yaml + inline: true + StatsUserReviewScoreResponseReviewScore: + discriminated: false + union: + - type: double + docs: Average review score for the user when per_label=False + - type: map + docs: Average review score per label for the user when per_label=True + source: + openapi: openapi/openapi.yaml + inline: true + StatsUserReviewScoreResponse: + properties: + performance_score: optional + review_score: optional + source: + openapi: openapi/openapi.yaml + StatsUserGroundTruthAgreementResponseAgreement: + discriminated: false + union: + - type: double + docs: Ground truth agreement score for the user (0-1) when per_label=False + - type: map + docs: Ground truth agreement scores per label when per_label=True + source: + openapi: openapi/openapi.yaml + inline: true + StatsUserGroundTruthAgreementResponse: + properties: + agreement: optional + source: + openapi: openapi/openapi.yaml service: auth: false base-path: '' @@ -175,6 +307,110 @@ service: id: 2 audiences: - public + agreement_annotator: + path: /api/projects/{id}/stats/agreement_annotator/{user_id} + method: GET + auth: true + docs: Get agreement statistics for a specific annotator within a project. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + user_id: integer + display-name: Get individual annotator agreement stats + response: + docs: Individual annotator agreement statistics + type: StatsAgreementAnnotatorResponse + examples: + - path-parameters: + id: 1 + user_id: 1 + response: + body: + Agreement_per_annotator: 1.1 + audiences: + - public + data_filters: + path: /api/projects/{id}/stats/data_filter + method: GET + auth: true + docs: Get statistics about user data filters and their usage within a project. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + display-name: Get user data filter statistics + response: + docs: User data filter statistics + type: StatsDataFiltersResponse + examples: + - path-parameters: + id: 1 + response: + body: + user_filters: + stats: + - {} + tasks_with_annotations: + key: value + audiences: + - public + finished_tasks: + path: /api/projects/{id}/stats/finished + method: GET + auth: true + docs: Get statistics about finished tasks for a project. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + display-name: Get finished tasks statistics + request: + name: StatsFinishedTasksRequest + query-parameters: + user_pk: + type: optional + docs: User ID to filter statistics by (optional) + response: + docs: Finished tasks statistics + type: StatsFinishedTasksResponse + examples: + - path-parameters: + id: 1 + response: + body: + finished: 1 + id: 1 + progress: 1 + audiences: + - public + lead_time: + path: /api/projects/{id}/stats/lead_time + method: GET + auth: true + docs: >- + Get lead time statistics across the project, including average + annotation time. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + display-name: Get lead time statistics + response: + docs: Lead time statistics + type: StatsLeadTimeResponse + examples: + - path-parameters: + id: 1 + response: + body: + lead_time_stats: + - mean_time: 1.1 + median_time: 1.1 + sum_lead_time: 1.1 + user_id: 1 + audiences: + - public total_agreement: path: /api/projects/{id}/stats/total_agreement method: GET @@ -208,5 +444,124 @@ service: total_agreement: 1.1 audiences: - public + update_stats: + path: /api/projects/{id}/update-stats + method: GET + auth: true + docs: Start stats recalculation for given project + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + display-name: Start stats recalculation + request: + name: StatsUpdateStatsRequest + query-parameters: + stat_type: + type: optional + docs: 'Stat type to recalculate. Possible values: label, stats' + response: + docs: Successful response returns job id + type: map + examples: + - path-parameters: + id: 1 + response: + body: + key: value + audiences: + - public + user_prediction_agreement: + path: /api/projects/{id}/user-stats/{user_pk}/prediction + method: GET + auth: true + docs: >- + Get prediction agreement statistics for a specific user within a + project. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + user_pk: integer + display-name: Get individual user prediction agreement + request: + name: StatsUserPredictionAgreementRequest + query-parameters: + per_label: + type: optional + docs: Calculate agreement per label + response: + docs: Individual user prediction agreement statistics + type: StatsUserPredictionAgreementResponse + examples: + - path-parameters: + id: 1 + user_pk: 1 + response: + body: + average_prediction_agreement_per_user: 1.1 + audiences: + - public + user_review_score: + path: /api/projects/{id}/user-stats/{user_pk}/review_score + method: GET + auth: true + docs: Get review score statistics for a specific user within a project. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + user_pk: integer + display-name: Get individual user review scores + request: + name: StatsUserReviewScoreRequest + query-parameters: + per_label: + type: optional + docs: Calculate agreement per label + response: + docs: Individual user review score statistics + type: StatsUserReviewScoreResponse + examples: + - path-parameters: + id: 1 + user_pk: 1 + response: + body: + performance_score: 1.1 + review_score: 1.1 + audiences: + - public + user_ground_truth_agreement: + path: /api/projects/{id}/users/{user_pk}/stats/agreement-groundtruth + method: GET + auth: true + docs: >- + Get ground truth agreement statistics for a specific user within a + project. + source: + openapi: openapi/openapi.yaml + path-parameters: + id: integer + user_pk: integer + display-name: Get individual user ground truth agreement + request: + name: StatsUserGroundTruthAgreementRequest + query-parameters: + per_label: + type: optional + docs: Calculate agreement per label + response: + docs: Individual user ground truth agreement statistics + type: StatsUserGroundTruthAgreementResponse + examples: + - path-parameters: + id: 1 + user_pk: 1 + response: + body: + agreement: 1.1 + audiences: + - public source: openapi: openapi/openapi.yaml diff --git a/.mock/definition/stats.yml b/.mock/definition/stats.yml index f8d3fc6d6..6c150e67c 100644 --- a/.mock/definition/stats.yml +++ b/.mock/definition/stats.yml @@ -14,58 +14,6 @@ types: average_prediction_agreement_per_model: optional source: openapi: openapi/openapi.yaml - ApiProjectsStatsAgreementAnnotatorRetrieveResponse: - properties: - Agreement_per_annotator: - type: optional - docs: Agreement score for the annotator (0-1) - source: - openapi: openapi/openapi.yaml - ApiProjectsStatsDataFilterRetrieveResponse: - properties: - filters: - type: optional> - docs: Data filter statistics by user - source: - openapi: openapi/openapi.yaml - ApiProjectsStatsFinishedRetrieveResponse: - properties: - finished_tasks: - type: optional - docs: Number of finished tasks - progress: - type: optional - docs: Progress percentage (0-100) - source: - openapi: openapi/openapi.yaml - ApiProjectsStatsLeadTimeRetrieveResponse: - properties: - lead_time: - type: optional> - docs: Lead time statistics including mean, median, and distribution - source: - openapi: openapi/openapi.yaml - ApiProjectsUserStatsPredictionRetrieveResponse: - properties: - average_prediction_agreement_per_user: - type: optional - docs: Average prediction agreement score for the user (0-1) - source: - openapi: openapi/openapi.yaml - ApiProjectsUserStatsReviewScoreRetrieveResponse: - properties: - review_score: - type: optional - docs: Average review score for the user - source: - openapi: openapi/openapi.yaml - ApiProjectsUsersStatsAgreementGroundtruthRetrieveResponse: - properties: - agreement: - type: optional - docs: Ground truth agreement score for the user (0-1) - source: - openapi: openapi/openapi.yaml service: auth: false base-path: '' @@ -180,193 +128,5 @@ service: response: body: average_prediction_agreement_per_model: 1.1 - api_projects_stats_agreement_annotator_retrieve: - path: /api/projects/{id}/stats/agreement_annotator/{user_id} - method: GET - auth: true - docs: Get agreement statistics for a specific annotator within a project. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - user_id: integer - display-name: Get individual annotator agreement stats - request: - name: ApiProjectsStatsAgreementAnnotatorRetrieveRequest - query-parameters: - per_label: - type: optional - default: false - docs: Calculate agreement per label - response: - docs: Individual annotator agreement statistics - type: ApiProjectsStatsAgreementAnnotatorRetrieveResponse - examples: - - path-parameters: - id: 1 - user_id: 1 - response: - body: - Agreement_per_annotator: 1.1 - api_projects_stats_data_filter_retrieve: - path: /api/projects/{id}/stats/data_filter - method: GET - auth: true - docs: Get statistics about user data filters and their usage within a project. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - display-name: Get user data filter statistics - response: - docs: User data filter statistics - type: ApiProjectsStatsDataFilterRetrieveResponse - examples: - - path-parameters: - id: 1 - response: - body: - filters: - key: value - api_projects_stats_finished_retrieve: - path: /api/projects/{id}/stats/finished - method: GET - auth: true - docs: Get statistics about finished tasks for a project. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - display-name: Get finished tasks statistics - request: - name: ApiProjectsStatsFinishedRetrieveRequest - query-parameters: - user_pk: - type: optional - docs: User ID to filter statistics by (optional) - response: - docs: Finished tasks statistics - type: ApiProjectsStatsFinishedRetrieveResponse - examples: - - path-parameters: - id: 1 - response: - body: - finished_tasks: 1 - progress: 1.1 - api_projects_stats_lead_time_retrieve: - path: /api/projects/{id}/stats/lead_time - method: GET - auth: true - docs: >- - Get lead time statistics across the project, including average - annotation time. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - display-name: Get lead time statistics - response: - docs: Lead time statistics - type: ApiProjectsStatsLeadTimeRetrieveResponse - examples: - - path-parameters: - id: 1 - response: - body: - lead_time: - key: value - api_projects_update_stats_retrieve: - path: /api/projects/{id}/update-stats - method: GET - auth: true - docs: Start stats recalculation for given project - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - display-name: Start stats recalculation - request: - name: ApiProjectsUpdateStatsRetrieveRequest - query-parameters: - stat_type: - type: optional - docs: 'Stat type to recalculate. Possible values: label, stats' - response: - docs: Successful response returns job id - type: map - examples: - - path-parameters: - id: 1 - response: - body: - key: value - api_projects_user_stats_prediction_retrieve: - path: /api/projects/{id}/user-stats/{user_pk}/prediction - method: GET - auth: true - docs: >- - Get prediction agreement statistics for a specific user within a - project. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - user_pk: integer - display-name: Get individual user prediction agreement - response: - docs: Individual user prediction agreement statistics - type: ApiProjectsUserStatsPredictionRetrieveResponse - examples: - - path-parameters: - id: 1 - user_pk: 1 - response: - body: - average_prediction_agreement_per_user: 1.1 - api_projects_user_stats_review_score_retrieve: - path: /api/projects/{id}/user-stats/{user_pk}/review_score - method: GET - auth: true - docs: Get review score statistics for a specific user within a project. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - user_pk: integer - display-name: Get individual user review scores - response: - docs: Individual user review score statistics - type: ApiProjectsUserStatsReviewScoreRetrieveResponse - examples: - - path-parameters: - id: 1 - user_pk: 1 - response: - body: - review_score: 1.1 - api_projects_users_stats_agreement_groundtruth_retrieve: - path: /api/projects/{id}/users/{user_pk}/stats/agreement-groundtruth - method: GET - auth: true - docs: >- - Get ground truth agreement statistics for a specific user within a - project. - source: - openapi: openapi/openapi.yaml - path-parameters: - id: integer - user_pk: integer - display-name: Get individual user ground truth agreement - response: - docs: Individual user ground truth agreement statistics - type: ApiProjectsUsersStatsAgreementGroundtruthRetrieveResponse - examples: - - path-parameters: - id: 1 - user_pk: 1 - response: - body: - agreement: 1.1 source: openapi: openapi/openapi.yaml diff --git a/.mock/openapi/openapi.yaml b/.mock/openapi/openapi.yaml index 7dc9046fd..5edf09d63 100644 --- a/.mock/openapi/openapi.yaml +++ b/.mock/openapi/openapi.yaml @@ -5449,6 +5449,296 @@ paths: - organizations - members x-fern-sdk-method-name: get + /api/organizations/{id}/permissions: + get: + description: List all organization-level permission overrides for a given organization. + operationId: api_organizations_permissions_list + parameters: + - in: path + name: id + required: true + schema: + type: integer + - description: Which field to use when ordering the results. + in: query + name: ordering + required: false + schema: + type: string + responses: + '200': + content: + application/json: + schema: + items: + $ref: '#/components/schemas/OrganizationPermission' + type: array + description: '' + security: + - Token: [] + summary: List organization permission overrides + tags: + - Organizations + - Permissions + x-fern-audiences: + - public + x-fern-sdk-group-name: + - organizations + - permissions + x-fern-sdk-method-name: list + post: + description: Create a new organization-level permission override for a given organization. + operationId: api_organizations_permissions_create + parameters: + - in: path + name: id + required: true + schema: + type: integer + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/OrganizationPermissionRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/OrganizationPermissionRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/OrganizationPermissionRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/OrganizationPermission' + description: '' + '400': + description: Bad Request + '403': + description: Permission Denied + security: + - Token: [] + summary: Create organization permission override + tags: + - Organizations + - Permissions + x-fern-audiences: + - public + x-fern-sdk-group-name: + - organizations + - permissions + x-fern-sdk-method-name: create + /api/organizations/{id}/permissions/options: + get: + description: Retrieve the list of configurable permission options (label, tooltip, default role and allowed roles). + operationId: api_organizations_permissions_options_list + parameters: + - in: path + name: id + required: true + schema: + type: integer + - description: Which field to use when ordering the results. + in: query + name: ordering + required: false + schema: + type: string + responses: + '200': + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ConfigurablePermissionOption' + type: array + description: '' + security: + - Token: [] + summary: Get configurable permissions options + tags: + - Organizations + - Permissions + x-fern-audiences: + - public + x-fern-sdk-group-name: + - organizations + - permissions + x-fern-sdk-method-name: get_options + /api/organizations/{id}/permissions/{permission}: + delete: + operationId: api_organizations_permissions_destroy + parameters: + - in: path + name: id + required: true + schema: + type: integer + - in: path + name: permission + required: true + schema: + type: string + responses: + '204': + description: Deleted + '403': + description: Permission Denied + '404': + description: Permission not found for organization + security: + - Token: [] + summary: Delete organization permission override + tags: + - Organizations + - Permissions + x-fern-audiences: + - public + x-fern-sdk-group-name: + - organizations + - permissions + x-fern-sdk-method-name: delete + get: + operationId: api_organizations_permissions_retrieve + parameters: + - in: path + name: id + required: true + schema: + type: integer + - in: path + name: permission + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/OrganizationPermission' + description: '' + '403': + description: Permission Denied + '404': + description: Permission not found for organization + security: + - Token: [] + summary: Retrieve organization permission override + tags: + - Organizations + - Permissions + x-fern-audiences: + - public + x-fern-sdk-group-name: + - organizations + - permissions + x-fern-sdk-method-name: get + patch: + description: Partially update the organization-level permission override for a given permission key. + operationId: api_organizations_permissions_partial_update + parameters: + - in: path + name: id + required: true + schema: + type: integer + - in: path + name: permission + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedOrganizationPermissionRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchedOrganizationPermissionRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchedOrganizationPermissionRequest' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/OrganizationPermission' + description: '' + '400': + description: Bad Request + '403': + description: Permission Denied + '404': + description: Permission not found for organization + security: + - Token: [] + summary: Update organization permission override + tags: + - Organizations + - Permissions + x-fern-audiences: + - public + x-fern-sdk-group-name: + - organizations + - permissions + x-fern-sdk-method-name: update + put: + description: Replace the organization-level permission override for a given permission key. + operationId: api_organizations_permissions_update + parameters: + - description: A unique integer value identifying this organization. + in: path + name: id + required: true + schema: + type: integer + - description: Permission key to update within the organization. + in: path + name: permission + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/OrganizationPermissionRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/OrganizationPermissionRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/OrganizationPermissionRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/OrganizationPermission' + description: '' + '400': + description: Bad Request + '403': + description: Permission Denied + '404': + description: Permission not found for organization + security: + - Token: [] + summary: Replace organization permission override + tags: + - Organizations + - Permissions + x-fern-audiences: + - public + x-fern-sdk-group-name: + - organizations + - permissions + x-fern-sdk-method-name: replace /api/organizations/{id}/set-default-role: patch: description: Update the default role for members of a specific organization. @@ -8301,12 +8591,6 @@ paths: required: true schema: type: integer - - description: Calculate agreement per label - in: query - name: per_label - schema: - default: false - type: boolean - in: path name: user_id required: true @@ -8328,6 +8612,12 @@ paths: summary: Get individual annotator agreement stats tags: - Stats + x-fern-audiences: + - public + x-fern-sdk-group-name: + - projects + - stats + x-fern-sdk-method-name: agreement_annotator /api/projects/{id}/stats/data_filter: get: description: Get statistics about user data filters and their usage within a project. @@ -8344,8 +8634,24 @@ paths: application/json: schema: properties: - filters: - description: Data filter statistics by user + user_filters: + description: Data filter statistics by user and model + properties: + stats: + description: List of filter configurations for users and models + items: + additionalProperties: + description: Filter configurations (finished, skipped, accepted, rejected, gt, predictions, review_score) + type: object + properties: + id: + description: User ID or model version identifier (e.g., "model:1.0") + type: string + type: object + type: array + tasks_with_annotations: + description: Default filter tab for tasks with annotations + type: object type: object type: object description: User data filter statistics @@ -8354,6 +8660,12 @@ paths: summary: Get user data filter statistics tags: - Stats + x-fern-audiences: + - public + x-fern-sdk-group-name: + - projects + - stats + x-fern-sdk-method-name: data_filters /api/projects/{id}/stats/finished: get: description: Get statistics about finished tasks for a project. @@ -8375,12 +8687,15 @@ paths: application/json: schema: properties: - finished_tasks: + finished: description: Number of finished tasks type: integer + id: + description: User ID + type: integer progress: description: Progress percentage (0-100) - type: number + type: integer type: object description: Finished tasks statistics security: @@ -8388,6 +8703,12 @@ paths: summary: Get finished tasks statistics tags: - Stats + x-fern-audiences: + - public + x-fern-sdk-group-name: + - projects + - stats + x-fern-sdk-method-name: finished_tasks /api/projects/{id}/stats/lead_time: get: description: Get lead time statistics across the project, including average annotation time. @@ -8404,9 +8725,24 @@ paths: application/json: schema: properties: - lead_time: + lead_time_stats: description: Lead time statistics including mean, median, and distribution - type: object + items: + properties: + mean_time: + description: Average lead time for the user + type: number + median_time: + description: Median lead time for the user + type: number + sum_lead_time: + description: Total lead time for the user + type: number + user_id: + description: User ID + type: integer + type: object + type: array type: object description: Lead time statistics security: @@ -8414,6 +8750,12 @@ paths: summary: Get lead time statistics tags: - Stats + x-fern-audiences: + - public + x-fern-sdk-group-name: + - projects + - stats + x-fern-sdk-method-name: lead_time /api/projects/{id}/stats/total_agreement: get: description: |- @@ -8935,6 +9277,12 @@ paths: summary: Start stats recalculation tags: - Stats + x-fern-audiences: + - public + x-fern-sdk-group-name: + - projects + - stats + x-fern-sdk-method-name: update_stats /api/projects/{id}/user-stats/{user_pk}/prediction: get: description: Get prediction agreement statistics for a specific user within a project. @@ -8945,6 +9293,11 @@ paths: required: true schema: type: integer + - description: Calculate agreement per label + in: query + name: per_label + schema: + type: boolean - in: path name: user_pk required: true @@ -8957,8 +9310,13 @@ paths: schema: properties: average_prediction_agreement_per_user: - description: Average prediction agreement score for the user (0-1) - type: number + oneOf: + - description: Average prediction agreement score for the user (0-1) when per_label=False + type: number + - additionalProperties: + type: number + description: Average prediction agreement score per label for the user (0-1) when per_label=True + type: object type: object description: Individual user prediction agreement statistics security: @@ -8966,6 +9324,12 @@ paths: summary: Get individual user prediction agreement tags: - Stats + x-fern-audiences: + - public + x-fern-sdk-group-name: + - projects + - stats + x-fern-sdk-method-name: user_prediction_agreement /api/projects/{id}/user-stats/{user_pk}/review_score: get: description: Get review score statistics for a specific user within a project. @@ -8976,6 +9340,11 @@ paths: required: true schema: type: integer + - description: Calculate agreement per label + in: query + name: per_label + schema: + type: boolean - in: path name: user_pk required: true @@ -8987,9 +9356,22 @@ paths: application/json: schema: properties: + performance_score: + oneOf: + - description: Performance score for the user when per_label=False + type: number + - additionalProperties: + type: number + description: Performance score per label for the user when per_label=True + type: object review_score: - description: Average review score for the user - type: number + oneOf: + - description: Average review score for the user when per_label=False + type: number + - additionalProperties: + type: number + description: Average review score per label for the user when per_label=True + type: object type: object description: Individual user review score statistics security: @@ -8997,6 +9379,12 @@ paths: summary: Get individual user review scores tags: - Stats + x-fern-audiences: + - public + x-fern-sdk-group-name: + - projects + - stats + x-fern-sdk-method-name: user_review_score /api/projects/{id}/users/{user_pk}/stats/agreement-groundtruth: get: description: Get ground truth agreement statistics for a specific user within a project. @@ -9007,6 +9395,11 @@ paths: required: true schema: type: integer + - description: Calculate agreement per label + in: query + name: per_label + schema: + type: boolean - in: path name: user_pk required: true @@ -9019,8 +9412,14 @@ paths: schema: properties: agreement: - description: Ground truth agreement score for the user (0-1) - type: number + oneOf: + - description: Ground truth agreement score for the user (0-1) when per_label=False + type: number + - additionalProperties: + description: Agreement score for specific label (0-1) + type: number + description: Ground truth agreement scores per label when per_label=True + type: object type: object description: Individual user ground truth agreement statistics security: @@ -9028,6 +9427,12 @@ paths: summary: Get individual user ground truth agreement tags: - Stats + x-fern-audiences: + - public + x-fern-sdk-group-name: + - projects + - stats + x-fern-sdk-method-name: user_ground_truth_agreement /api/projects/{id}/validate/: post: description: Determine whether the label configuration for a specific project is valid. @@ -19160,6 +19565,27 @@ components: - task - updated_at type: object + ConfigurablePermissionOption: + properties: + default: + nullable: true + oneOf: + - $ref: '#/components/schemas/Role9e7Enum' + - $ref: '#/components/schemas/NullEnum' + label: + type: string + options: + items: + $ref: '#/components/schemas/Role9e7Enum' + type: array + permission: + type: string + tooltip: + type: string + required: + - options + - permission + type: object ConvertedFormat: properties: export_type: @@ -19806,7 +20232,7 @@ components: type: string default_role: allOf: - - $ref: '#/components/schemas/DefaultRoleEnum' + - $ref: '#/components/schemas/Role9e7Enum' description: |- Default membership role for invited users @@ -19848,24 +20274,6 @@ components: required: - organization type: object - DefaultRoleEnum: - description: |- - * `OW` - Owner - * `AD` - Administrator - * `MA` - Manager - * `RE` - Reviewer - * `AN` - Annotator - * `DI` - Deactivated - * `NO` - Not Activated - enum: - - OW - - AD - - MA - - RE - - AN - - DI - - 'NO' - type: string EditionEnum: description: |- * `Community` - Community @@ -21685,7 +22093,7 @@ components: type: string default_role: allOf: - - $ref: '#/components/schemas/DefaultRoleEnum' + - $ref: '#/components/schemas/Role9e7Enum' description: |- Default membership role for invited users @@ -24790,6 +25198,57 @@ components: required: - role type: object + OrganizationPermission: + properties: + default_role: + readOnly: true + type: string + id: + readOnly: true + type: integer + label: + readOnly: true + type: string + options: + readOnly: true + type: string + organization: + readOnly: true + type: integer + permission: + maxLength: 255 + type: string + roles: + description: Explicit roles that have this permission within the organization. + items: + $ref: '#/components/schemas/Role9e7Enum' + type: array + tooltip: + readOnly: true + type: string + required: + - default_role + - id + - label + - options + - organization + - permission + - tooltip + type: object + OrganizationPermissionRequest: + properties: + permission: + maxLength: 255 + minLength: 1 + type: string + roles: + description: Explicit roles that have this permission within the organization. + items: + $ref: '#/components/schemas/Role9e7Enum' + type: array + required: + - permission + type: object PaginatedAllRolesProjectListList: properties: count: @@ -25677,7 +26136,7 @@ components: type: string default_role: allOf: - - $ref: '#/components/schemas/DefaultRoleEnum' + - $ref: '#/components/schemas/Role9e7Enum' description: |- Default membership role for invited users @@ -26652,6 +27111,18 @@ components: user_id: type: integer type: object + PatchedOrganizationPermissionRequest: + properties: + permission: + maxLength: 255 + minLength: 1 + type: string + roles: + description: Explicit roles that have this permission within the organization. + items: + $ref: '#/components/schemas/Role9e7Enum' + type: array + type: object PatchedPauseRequest: description: |- A ModelSerializer that takes additional arguments for diff --git a/reference.md b/reference.md index 9920dc9db..3ef779234 100644 --- a/reference.md +++ b/reference.md @@ -4987,7 +4987,7 @@ Set the minimum user role that can edit custom scripts in the UI.
-**default_role:** `typing.Optional[DefaultRoleEnum]` +**default_role:** `typing.Optional[Role9E7Enum]` Default membership role for invited users @@ -26472,6 +26472,571 @@ client.organizations.members.delete(
+ +
+
+ +## Organizations Permissions +
client.organizations.permissions.list(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +List all organization-level permission overrides for a given organization. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.organizations.permissions.list( + id=1, +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**id:** `int` + +
+
+ +
+
+ +**ordering:** `typing.Optional[str]` — Which field to use when ordering the results. + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.organizations.permissions.create(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Create a new organization-level permission override for a given organization. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.organizations.permissions.create( + id=1, + permission="permission", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**id:** `int` + +
+
+ +
+
+ +**permission:** `str` + +
+
+ +
+
+ +**roles:** `typing.Optional[typing.Sequence[Role9E7Enum]]` — Explicit roles that have this permission within the organization. + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.organizations.permissions.get_options(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieve the list of configurable permission options (label, tooltip, default role and allowed roles). +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.organizations.permissions.get_options( + id=1, +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**id:** `int` + +
+
+ +
+
+ +**ordering:** `typing.Optional[str]` — Which field to use when ordering the results. + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.organizations.permissions.get(...) +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.organizations.permissions.get( + id=1, + permission="permission", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**id:** `int` + +
+
+ +
+
+ +**permission:** `str` + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.organizations.permissions.replace(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Replace the organization-level permission override for a given permission key. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.organizations.permissions.replace( + id=1, + permission_="permission", + permission="permission", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**id:** `int` — A unique integer value identifying this organization. + +
+
+ +
+
+ +**permission_:** `str` — Permission key to update within the organization. + +
+
+ +
+
+ +**permission:** `str` + +
+
+ +
+
+ +**roles:** `typing.Optional[typing.Sequence[Role9E7Enum]]` — Explicit roles that have this permission within the organization. + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.organizations.permissions.delete(...) +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.organizations.permissions.delete( + id=1, + permission="permission", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**id:** `int` + +
+
+ +
+
+ +**permission:** `str` + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.organizations.permissions.update(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Partially update the organization-level permission override for a given permission key. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.organizations.permissions.update( + id=1, + permission="permission", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**id:** `int` + +
+
+ +
+
+ +**permission:** `str` + +
+
+ +
+
+ +**patched_organization_permission_request_permission:** `typing.Optional[str]` + +
+
+ +
+
+ +**roles:** `typing.Optional[typing.Sequence[Role9E7Enum]]` — Explicit roles that have this permission within the organization. + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ +
@@ -26489,7 +27054,639 @@ client.organizations.members.delete(
-Retrieve the available export formats for the current project by ID. +Retrieve the available export formats for the current project by ID. +
+
+ + + +#### 🔌 Usage + +
+
+ +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.projects.exports.list_formats( + id=1, +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**id:** `int` — A unique integer value identifying this project. + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + + + +
+ +
client.projects.exports.list(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Returns a list of exported files for a specific project by ID. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.projects.exports.list( + id=1, +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**id:** `int` — A unique integer value identifying this project. + +
+
+ +
+
+ +**ordering:** `typing.Optional[str]` — Which field to use when ordering the results. + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.projects.exports.create(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Create a new export request to start a background task and generate an export file for a specific project by ID. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.projects.exports.create( + id=1, +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**id:** `int` — A unique integer value identifying this project. + +
+
+ +
+
+ +**annotation_filter_options:** `typing.Optional[LseAnnotationFilterOptionsRequest]` + +
+
+ +
+
+ +**converted_formats:** `typing.Optional[typing.Sequence[ConvertedFormatRequest]]` + +
+
+ +
+
+ +**counters:** `typing.Optional[typing.Optional[typing.Any]]` + +
+
+ +
+
+ +**created_by:** `typing.Optional[UserSimpleRequest]` + +
+
+ +
+
+ +**finished_at:** `typing.Optional[dt.datetime]` — Complete or fail time + +
+
+ +
+
+ +**md5:** `typing.Optional[str]` + +
+
+ +
+
+ +**serialization_options:** `typing.Optional[SerializationOptionsRequest]` + +
+
+ +
+
+ +**status:** `typing.Optional[Status7BfEnum]` + +
+
+ +
+
+ +**task_filter_options:** `typing.Optional[LseTaskFilterOptionsRequest]` + +
+
+ +
+
+ +**title:** `typing.Optional[str]` + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.projects.exports.get(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieve information about an export file by export ID for a specific project. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.projects.exports.get( + export_pk=1, + id=1, +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**export_pk:** `int` — Primary key identifying the export file. + +
+
+ +
+
+ +**id:** `int` — A unique integer value identifying this project. + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.projects.exports.delete(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Delete an export file by specified export ID. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.projects.exports.delete( + export_pk=1, + id=1, +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**export_pk:** `int` — Primary key identifying the export file. + +
+
+ +
+
+ +**id:** `int` — A unique integer value identifying this project. + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.projects.exports.convert(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Convert export snapshot to selected format +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.projects.exports.convert( + export_pk=1, + id=1, + export_type="export_type", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**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.get(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieve the members for a specific project. Optionally filter by user IDs (comma-separated). +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.projects.members.get( + id=1, +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**id:** `int` + +
+
+ +
+
+ +**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. + +
+
+
+
+ + +
+
+
+ +## Projects Metrics +
client.projects.metrics.get(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Get the current metrics configuration for a project.
@@ -26509,7 +27706,7 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.exports.list_formats( +client.projects.metrics.get( id=1, ) @@ -26527,7 +27724,7 @@ client.projects.exports.list_formats(
-**id:** `int` — A unique integer value identifying this project. +**id:** `int`
@@ -26547,7 +27744,7 @@ client.projects.exports.list_formats(
-
client.projects.exports.list(...) +
client.projects.metrics.update(...)
@@ -26559,7 +27756,7 @@ client.projects.exports.list_formats(
-Returns a list of exported files for a specific project by ID. +Update metrics strategy and parameters for a project.
@@ -26579,7 +27776,7 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.exports.list( +client.projects.metrics.update( id=1, ) @@ -26597,7 +27794,7 @@ client.projects.exports.list(
-**id:** `int` — A unique integer value identifying this project. +**id:** `int`
@@ -26605,7 +27802,31 @@ client.projects.exports.list(
-**ordering:** `typing.Optional[str]` — Which field to use when ordering the results. +**additional_params:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` + +
+
+ +
+
+ +**agreement_threshold:** `typing.Optional[int]` + +
+
+ +
+
+ +**max_additional_annotators_assignable:** `typing.Optional[int]` + +
+
+ +
+
+ +**metric_name:** `typing.Optional[str]`
@@ -26625,7 +27846,8 @@ client.projects.exports.list(
-
client.projects.exports.create(...) +## Projects Stats +
client.projects.stats.iaa(...)
@@ -26637,7 +27859,7 @@ client.projects.exports.list(
-Create a new export request to start a background task and generate an export file for a specific project by ID. +Get Inter-Annotator Agreement (IAA) matrix for a project, showing agreement between all annotators.
@@ -26657,7 +27879,7 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.exports.create( +client.projects.stats.iaa( id=1, ) @@ -26675,7 +27897,7 @@ client.projects.exports.create(
-**id:** `int` — A unique integer value identifying this project. +**id:** `int`
@@ -26683,7 +27905,7 @@ client.projects.exports.create(
-**annotation_filter_options:** `typing.Optional[LseAnnotationFilterOptionsRequest]` +**expand:** `typing.Optional[str]` — Comma-separated list of fields to expand
@@ -26691,7 +27913,7 @@ client.projects.exports.create(
-**converted_formats:** `typing.Optional[typing.Sequence[ConvertedFormatRequest]]` +**per_label:** `typing.Optional[bool]` — Calculate IAA per label
@@ -26699,7 +27921,7 @@ client.projects.exports.create(
-**counters:** `typing.Optional[typing.Optional[typing.Any]]` +**std:** `typing.Optional[bool]` — Include standard deviation in results
@@ -26707,7 +27929,7 @@ client.projects.exports.create(
-**created_by:** `typing.Optional[UserSimpleRequest]` +**task:** `typing.Optional[str]` — Comma-separated list of task IDs to filter by
@@ -26715,39 +27937,70 @@ client.projects.exports.create(
-**finished_at:** `typing.Optional[dt.datetime]` — Complete or fail time +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+ +
-
-
-**md5:** `typing.Optional[str]` -
+
+
client.projects.stats.agreement_annotator(...)
-**serialization_options:** `typing.Optional[SerializationOptionsRequest]` - +#### 📝 Description + +
+
+ +
+
+ +Get agreement statistics for a specific annotator within a project. +
+
+#### 🔌 Usage +
-**status:** `typing.Optional[Status7BfEnum]` - +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.projects.stats.agreement_annotator( + id=1, + user_id=1, +) + +``` +
+
+#### ⚙️ Parameters +
-**task_filter_options:** `typing.Optional[LseTaskFilterOptionsRequest]` +
+
+ +**id:** `int`
@@ -26755,7 +28008,7 @@ client.projects.exports.create(
-**title:** `typing.Optional[str]` +**user_id:** `int`
@@ -26775,7 +28028,7 @@ client.projects.exports.create(
-
client.projects.exports.get(...) +
client.projects.stats.data_filters(...)
@@ -26787,7 +28040,7 @@ client.projects.exports.create(
-Retrieve information about an export file by export ID for a specific project. +Get statistics about user data filters and their usage within a project.
@@ -26807,8 +28060,7 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.exports.get( - export_pk=1, +client.projects.stats.data_filters( id=1, ) @@ -26826,15 +28078,7 @@ client.projects.exports.get(
-**export_pk:** `int` — Primary key identifying the export file. - -
-
- -
-
- -**id:** `int` — A unique integer value identifying this project. +**id:** `int`
@@ -26854,7 +28098,7 @@ client.projects.exports.get(
-
client.projects.exports.delete(...) +
client.projects.stats.finished_tasks(...)
@@ -26866,7 +28110,7 @@ client.projects.exports.get(
-Delete an export file by specified export ID. +Get statistics about finished tasks for a project.
@@ -26886,8 +28130,7 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.exports.delete( - export_pk=1, +client.projects.stats.finished_tasks( id=1, ) @@ -26905,7 +28148,7 @@ client.projects.exports.delete(
-**export_pk:** `int` — Primary key identifying the export file. +**id:** `int`
@@ -26913,7 +28156,7 @@ client.projects.exports.delete(
-**id:** `int` — A unique integer value identifying this project. +**user_pk:** `typing.Optional[int]` — User ID to filter statistics by (optional)
@@ -26933,7 +28176,7 @@ client.projects.exports.delete(
-
client.projects.exports.convert(...) +
client.projects.stats.lead_time(...)
@@ -26945,7 +28188,7 @@ client.projects.exports.delete(
-Convert export snapshot to selected format +Get lead time statistics across the project, including average annotation time.
@@ -26965,10 +28208,8 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.exports.convert( - export_pk=1, +client.projects.stats.lead_time( id=1, - export_type="export_type", ) ``` @@ -26985,31 +28226,7 @@ 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. - -
-
- -
-
- -**download_resources:** `typing.Optional[bool]` — Download resources in converter. +**id:** `int`
@@ -27029,8 +28246,7 @@ client.projects.exports.convert(
-## Projects Members -
client.projects.members.get(...) +
client.projects.stats.total_agreement(...)
@@ -27042,7 +28258,9 @@ client.projects.exports.convert(
-Retrieve the members for a specific project. Optionally filter by user IDs (comma-separated). +Overall or per-label total agreement across the project. + +NOTE: due to an open issue in Fern, SDK clients will raise ApiError upon handling a 204 response. As a workaround, wrap call to this function in a try-except block.
@@ -27062,7 +28280,7 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.members.get( +client.projects.stats.total_agreement( id=1, ) @@ -27088,7 +28306,7 @@ client.projects.members.get(
-**user_ids:** `typing.Optional[str]` — Comma-separated list of user IDs to include. Example: user_ids=1,2,3 +**per_label:** `typing.Optional[bool]` — Return agreement per label
@@ -27108,8 +28326,7 @@ client.projects.members.get(
-## Projects Metrics -
client.projects.metrics.get(...) +
client.projects.stats.update_stats(...)
@@ -27121,7 +28338,7 @@ client.projects.members.get(
-Get the current metrics configuration for a project. +Start stats recalculation for given project
@@ -27141,7 +28358,7 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.metrics.get( +client.projects.stats.update_stats( id=1, ) @@ -27167,6 +28384,14 @@ client.projects.metrics.get(
+**stat_type:** `typing.Optional[str]` — Stat type to recalculate. Possible values: label, stats + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -27179,7 +28404,7 @@ client.projects.metrics.get(
-
client.projects.metrics.update(...) +
client.projects.stats.user_prediction_agreement(...)
@@ -27191,7 +28416,7 @@ client.projects.metrics.get(
-Update metrics strategy and parameters for a project. +Get prediction agreement statistics for a specific user within a project.
@@ -27211,8 +28436,9 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.metrics.update( +client.projects.stats.user_prediction_agreement( id=1, + user_pk=1, ) ``` @@ -27237,23 +28463,7 @@ client.projects.metrics.update(
-**additional_params:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` - -
-
- -
-
- -**agreement_threshold:** `typing.Optional[int]` - -
-
- -
-
- -**max_additional_annotators_assignable:** `typing.Optional[int]` +**user_pk:** `int`
@@ -27261,7 +28471,7 @@ client.projects.metrics.update(
-**metric_name:** `typing.Optional[str]` +**per_label:** `typing.Optional[bool]` — Calculate agreement per label
@@ -27281,8 +28491,7 @@ client.projects.metrics.update(
-## Projects Stats -
client.projects.stats.iaa(...) +
client.projects.stats.user_review_score(...)
@@ -27294,7 +28503,7 @@ client.projects.metrics.update(
-Get Inter-Annotator Agreement (IAA) matrix for a project, showing agreement between all annotators. +Get review score statistics for a specific user within a project.
@@ -27314,8 +28523,9 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.stats.iaa( +client.projects.stats.user_review_score( id=1, + user_pk=1, ) ``` @@ -27340,23 +28550,7 @@ client.projects.stats.iaa(
-**expand:** `typing.Optional[str]` — Comma-separated list of fields to expand - -
-
- -
-
- -**per_label:** `typing.Optional[bool]` — Calculate IAA per label - -
-
- -
-
- -**std:** `typing.Optional[bool]` — Include standard deviation in results +**user_pk:** `int`
@@ -27364,7 +28558,7 @@ client.projects.stats.iaa(
-**task:** `typing.Optional[str]` — Comma-separated list of task IDs to filter by +**per_label:** `typing.Optional[bool]` — Calculate agreement per label
@@ -27384,7 +28578,7 @@ client.projects.stats.iaa(
-
client.projects.stats.total_agreement(...) +
client.projects.stats.user_ground_truth_agreement(...)
@@ -27396,9 +28590,7 @@ client.projects.stats.iaa(
-Overall or per-label total agreement across the project. - -NOTE: due to an open issue in Fern, SDK clients will raise ApiError upon handling a 204 response. As a workaround, wrap call to this function in a try-except block. +Get ground truth agreement statistics for a specific user within a project.
@@ -27418,8 +28610,9 @@ from label_studio_sdk import LabelStudio client = LabelStudio( api_key="YOUR_API_KEY", ) -client.projects.stats.total_agreement( +client.projects.stats.user_ground_truth_agreement( id=1, + user_pk=1, ) ``` @@ -27444,7 +28637,15 @@ client.projects.stats.total_agreement(
-**per_label:** `typing.Optional[bool]` — Return agreement per label +**user_pk:** `int` + +
+
+ +
+
+ +**per_label:** `typing.Optional[bool]` — Calculate agreement per label
diff --git a/src/label_studio_sdk/__init__.py b/src/label_studio_sdk/__init__.py index 85aebcb1c..4fe4748d8 100644 --- a/src/label_studio_sdk/__init__.py +++ b/src/label_studio_sdk/__init__.py @@ -42,13 +42,14 @@ Comment, CommentRequest, CommentSerializerWithExpandedUser, + ConfigurablePermissionOption, + ConfigurablePermissionOptionDefault, ConvertedFormat, ConvertedFormatRequest, CountLimit, CustomScriptsEditableByEnum, DefaultRole, DefaultRoleCustomScriptsEditableBy, - DefaultRoleEnum, EditionEnum, Export, FileUpload, @@ -138,6 +139,8 @@ OrganizationInvite, OrganizationMember, OrganizationMembership, + OrganizationPermission, + OrganizationPermissionRequest, PaginatedAllRolesProjectListList, PaginatedAnnotationHistoryList, PaginatedLseOrganizationMemberListList, @@ -399,13 +402,14 @@ "Comment", "CommentRequest", "CommentSerializerWithExpandedUser", + "ConfigurablePermissionOption", + "ConfigurablePermissionOptionDefault", "ConvertedFormat", "ConvertedFormatRequest", "CountLimit", "CustomScriptsEditableByEnum", "DefaultRole", "DefaultRoleCustomScriptsEditableBy", - "DefaultRoleEnum", "EditionEnum", "Export", "ExportStorageListTypesResponseItem", @@ -509,6 +513,8 @@ "OrganizationInvite", "OrganizationMember", "OrganizationMembership", + "OrganizationPermission", + "OrganizationPermissionRequest", "PaginatedAllRolesProjectListList", "PaginatedAnnotationHistoryList", "PaginatedLseOrganizationMemberListList", diff --git a/src/label_studio_sdk/organizations/__init__.py b/src/label_studio_sdk/organizations/__init__.py index faea629fa..8451c0fe6 100644 --- a/src/label_studio_sdk/organizations/__init__.py +++ b/src/label_studio_sdk/organizations/__init__.py @@ -1,6 +1,6 @@ # This file was auto-generated by Fern from our API Definition. from .types import PatchedDefaultRoleRequestCustomScriptsEditableBy -from . import invites, members +from . import invites, members, permissions -__all__ = ["PatchedDefaultRoleRequestCustomScriptsEditableBy", "invites", "members"] +__all__ = ["PatchedDefaultRoleRequestCustomScriptsEditableBy", "invites", "members", "permissions"] diff --git a/src/label_studio_sdk/organizations/client.py b/src/label_studio_sdk/organizations/client.py index eaebaacbc..8117bc87d 100644 --- a/src/label_studio_sdk/organizations/client.py +++ b/src/label_studio_sdk/organizations/client.py @@ -4,6 +4,7 @@ from ..core.client_wrapper import SyncClientWrapper from .invites.client import InvitesClient from .members.client import MembersClient +from .permissions.client import PermissionsClient from ..core.request_options import RequestOptions from ..types.organization_invite import OrganizationInvite from ..core.unchecked_base_model import construct_type @@ -19,12 +20,13 @@ from .types.patched_default_role_request_custom_scripts_editable_by import ( PatchedDefaultRoleRequestCustomScriptsEditableBy, ) -from ..types.default_role_enum import DefaultRoleEnum +from ..types.role9e7enum import Role9E7Enum from ..types.default_role import DefaultRole from ..core.serialization import convert_and_respect_annotation_metadata from ..core.client_wrapper import AsyncClientWrapper from .invites.client import AsyncInvitesClient from .members.client import AsyncMembersClient +from .permissions.client import AsyncPermissionsClient # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -35,6 +37,7 @@ def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper self.invites = InvitesClient(client_wrapper=self._client_wrapper) self.members = MembersClient(client_wrapper=self._client_wrapper) + self.permissions = PermissionsClient(client_wrapper=self._client_wrapper) def reset_token(self, *, request_options: typing.Optional[RequestOptions] = None) -> OrganizationInvite: """ @@ -306,7 +309,7 @@ def update_default_role( annotator_reviewer_firewall_enabled_at: typing.Optional[dt.datetime] = OMIT, custom_scripts_editable_by: typing.Optional[PatchedDefaultRoleRequestCustomScriptsEditableBy] = OMIT, custom_scripts_enabled_at: typing.Optional[dt.datetime] = OMIT, - default_role: typing.Optional[DefaultRoleEnum] = OMIT, + default_role: typing.Optional[Role9E7Enum] = OMIT, email_notification_settings: typing.Optional[typing.Optional[typing.Any]] = OMIT, embed_domains: typing.Optional[typing.Optional[typing.Any]] = OMIT, embed_settings: typing.Optional[typing.Optional[typing.Any]] = OMIT, @@ -336,7 +339,7 @@ def update_default_role( custom_scripts_enabled_at : typing.Optional[dt.datetime] Set to current time to enabled custom scripts for this organization. Can only be enabled if no organization members are active members of any other organizations; otherwise an error will be raised. If this occurs, contact the LEAP team for assistance with enabling custom scripts. - default_role : typing.Optional[DefaultRoleEnum] + default_role : typing.Optional[Role9E7Enum] Default membership role for invited users * `OW` - Owner @@ -433,6 +436,7 @@ def __init__(self, *, client_wrapper: AsyncClientWrapper): self._client_wrapper = client_wrapper self.invites = AsyncInvitesClient(client_wrapper=self._client_wrapper) self.members = AsyncMembersClient(client_wrapper=self._client_wrapper) + self.permissions = AsyncPermissionsClient(client_wrapper=self._client_wrapper) async def reset_token(self, *, request_options: typing.Optional[RequestOptions] = None) -> OrganizationInvite: """ @@ -736,7 +740,7 @@ async def update_default_role( annotator_reviewer_firewall_enabled_at: typing.Optional[dt.datetime] = OMIT, custom_scripts_editable_by: typing.Optional[PatchedDefaultRoleRequestCustomScriptsEditableBy] = OMIT, custom_scripts_enabled_at: typing.Optional[dt.datetime] = OMIT, - default_role: typing.Optional[DefaultRoleEnum] = OMIT, + default_role: typing.Optional[Role9E7Enum] = OMIT, email_notification_settings: typing.Optional[typing.Optional[typing.Any]] = OMIT, embed_domains: typing.Optional[typing.Optional[typing.Any]] = OMIT, embed_settings: typing.Optional[typing.Optional[typing.Any]] = OMIT, @@ -766,7 +770,7 @@ async def update_default_role( custom_scripts_enabled_at : typing.Optional[dt.datetime] Set to current time to enabled custom scripts for this organization. Can only be enabled if no organization members are active members of any other organizations; otherwise an error will be raised. If this occurs, contact the LEAP team for assistance with enabling custom scripts. - default_role : typing.Optional[DefaultRoleEnum] + default_role : typing.Optional[Role9E7Enum] Default membership role for invited users * `OW` - Owner diff --git a/src/label_studio_sdk/organizations/permissions/__init__.py b/src/label_studio_sdk/organizations/permissions/__init__.py new file mode 100644 index 000000000..f3ea2659b --- /dev/null +++ b/src/label_studio_sdk/organizations/permissions/__init__.py @@ -0,0 +1,2 @@ +# This file was auto-generated by Fern from our API Definition. + diff --git a/src/label_studio_sdk/organizations/permissions/client.py b/src/label_studio_sdk/organizations/permissions/client.py new file mode 100644 index 000000000..6a356d5bb --- /dev/null +++ b/src/label_studio_sdk/organizations/permissions/client.py @@ -0,0 +1,1129 @@ +# 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.organization_permission import OrganizationPermission +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 ...types.role9e7enum import Role9E7Enum +from ...errors.bad_request_error import BadRequestError +from ...errors.forbidden_error import ForbiddenError +from ...types.configurable_permission_option import ConfigurablePermissionOption +from ...errors.not_found_error import NotFoundError +from ...core.client_wrapper import AsyncClientWrapper + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class PermissionsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def list( + self, id: int, *, ordering: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None + ) -> typing.List[OrganizationPermission]: + """ + List all organization-level permission overrides for a given organization. + + Parameters + ---------- + id : int + + ordering : typing.Optional[str] + Which field to use when ordering the results. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + typing.List[OrganizationPermission] + + + Examples + -------- + from label_studio_sdk import LabelStudio + + client = LabelStudio( + api_key="YOUR_API_KEY", + ) + client.organizations.permissions.list( + id=1, + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/organizations/{jsonable_encoder(id)}/permissions", + method="GET", + params={ + "ordering": ordering, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + typing.List[OrganizationPermission], + construct_type( + type_=typing.List[OrganizationPermission], # 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 create( + self, + id: int, + *, + permission: str, + roles: typing.Optional[typing.Sequence[Role9E7Enum]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> OrganizationPermission: + """ + Create a new organization-level permission override for a given organization. + + Parameters + ---------- + id : int + + permission : str + + roles : typing.Optional[typing.Sequence[Role9E7Enum]] + Explicit roles that have this permission within the organization. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + OrganizationPermission + + + Examples + -------- + from label_studio_sdk import LabelStudio + + client = LabelStudio( + api_key="YOUR_API_KEY", + ) + client.organizations.permissions.create( + id=1, + permission="permission", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/organizations/{jsonable_encoder(id)}/permissions", + method="POST", + json={ + "permission": permission, + "roles": roles, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + OrganizationPermission, + construct_type( + type_=OrganizationPermission, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # 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 get_options( + self, id: int, *, ordering: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None + ) -> typing.List[ConfigurablePermissionOption]: + """ + Retrieve the list of configurable permission options (label, tooltip, default role and allowed roles). + + Parameters + ---------- + id : int + + ordering : typing.Optional[str] + Which field to use when ordering the results. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + typing.List[ConfigurablePermissionOption] + + + Examples + -------- + from label_studio_sdk import LabelStudio + + client = LabelStudio( + api_key="YOUR_API_KEY", + ) + client.organizations.permissions.get_options( + id=1, + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/organizations/{jsonable_encoder(id)}/permissions/options", + method="GET", + params={ + "ordering": ordering, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + typing.List[ConfigurablePermissionOption], + construct_type( + type_=typing.List[ConfigurablePermissionOption], # 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 get( + self, id: int, permission: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> OrganizationPermission: + """ + Parameters + ---------- + id : int + + permission : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + OrganizationPermission + + + Examples + -------- + from label_studio_sdk import LabelStudio + + client = LabelStudio( + api_key="YOUR_API_KEY", + ) + client.organizations.permissions.get( + id=1, + permission="permission", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/organizations/{jsonable_encoder(id)}/permissions/{jsonable_encoder(permission)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + OrganizationPermission, + construct_type( + type_=OrganizationPermission, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # 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 replace( + self, + id: int, + permission_: str, + *, + permission: str, + roles: typing.Optional[typing.Sequence[Role9E7Enum]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> OrganizationPermission: + """ + Replace the organization-level permission override for a given permission key. + + Parameters + ---------- + id : int + A unique integer value identifying this organization. + + permission_ : str + Permission key to update within the organization. + + permission : str + + roles : typing.Optional[typing.Sequence[Role9E7Enum]] + Explicit roles that have this permission within the organization. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + OrganizationPermission + + + Examples + -------- + from label_studio_sdk import LabelStudio + + client = LabelStudio( + api_key="YOUR_API_KEY", + ) + client.organizations.permissions.replace( + id=1, + permission_="permission", + permission="permission", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/organizations/{jsonable_encoder(id)}/permissions/{jsonable_encoder(permission_)}", + method="PUT", + json={ + "permission": permission, + "roles": roles, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + OrganizationPermission, + construct_type( + type_=OrganizationPermission, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # 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 delete(self, id: int, permission: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: + """ + Parameters + ---------- + id : int + + permission : str + + 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.organizations.permissions.delete( + id=1, + permission="permission", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/organizations/{jsonable_encoder(id)}/permissions/{jsonable_encoder(permission)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # 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 update( + self, + id: int, + permission: str, + *, + patched_organization_permission_request_permission: typing.Optional[str] = OMIT, + roles: typing.Optional[typing.Sequence[Role9E7Enum]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> OrganizationPermission: + """ + Partially update the organization-level permission override for a given permission key. + + Parameters + ---------- + id : int + + permission : str + + patched_organization_permission_request_permission : typing.Optional[str] + + roles : typing.Optional[typing.Sequence[Role9E7Enum]] + Explicit roles that have this permission within the organization. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + OrganizationPermission + + + Examples + -------- + from label_studio_sdk import LabelStudio + + client = LabelStudio( + api_key="YOUR_API_KEY", + ) + client.organizations.permissions.update( + id=1, + permission="permission", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/organizations/{jsonable_encoder(id)}/permissions/{jsonable_encoder(permission)}", + method="PATCH", + json={ + "permission": patched_organization_permission_request_permission, + "roles": roles, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + OrganizationPermission, + construct_type( + type_=OrganizationPermission, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # 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 AsyncPermissionsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def list( + self, id: int, *, ordering: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None + ) -> typing.List[OrganizationPermission]: + """ + List all organization-level permission overrides for a given organization. + + Parameters + ---------- + id : int + + ordering : typing.Optional[str] + Which field to use when ordering the results. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + typing.List[OrganizationPermission] + + + Examples + -------- + import asyncio + + from label_studio_sdk import AsyncLabelStudio + + client = AsyncLabelStudio( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.organizations.permissions.list( + id=1, + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/organizations/{jsonable_encoder(id)}/permissions", + method="GET", + params={ + "ordering": ordering, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + typing.List[OrganizationPermission], + construct_type( + type_=typing.List[OrganizationPermission], # 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 create( + self, + id: int, + *, + permission: str, + roles: typing.Optional[typing.Sequence[Role9E7Enum]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> OrganizationPermission: + """ + Create a new organization-level permission override for a given organization. + + Parameters + ---------- + id : int + + permission : str + + roles : typing.Optional[typing.Sequence[Role9E7Enum]] + Explicit roles that have this permission within the organization. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + OrganizationPermission + + + Examples + -------- + import asyncio + + from label_studio_sdk import AsyncLabelStudio + + client = AsyncLabelStudio( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.organizations.permissions.create( + id=1, + permission="permission", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/organizations/{jsonable_encoder(id)}/permissions", + method="POST", + json={ + "permission": permission, + "roles": roles, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + OrganizationPermission, + construct_type( + type_=OrganizationPermission, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # 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 get_options( + self, id: int, *, ordering: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None + ) -> typing.List[ConfigurablePermissionOption]: + """ + Retrieve the list of configurable permission options (label, tooltip, default role and allowed roles). + + Parameters + ---------- + id : int + + ordering : typing.Optional[str] + Which field to use when ordering the results. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + typing.List[ConfigurablePermissionOption] + + + Examples + -------- + import asyncio + + from label_studio_sdk import AsyncLabelStudio + + client = AsyncLabelStudio( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.organizations.permissions.get_options( + id=1, + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/organizations/{jsonable_encoder(id)}/permissions/options", + method="GET", + params={ + "ordering": ordering, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + typing.List[ConfigurablePermissionOption], + construct_type( + type_=typing.List[ConfigurablePermissionOption], # 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 get( + self, id: int, permission: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> OrganizationPermission: + """ + Parameters + ---------- + id : int + + permission : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + OrganizationPermission + + + Examples + -------- + import asyncio + + from label_studio_sdk import AsyncLabelStudio + + client = AsyncLabelStudio( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.organizations.permissions.get( + id=1, + permission="permission", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/organizations/{jsonable_encoder(id)}/permissions/{jsonable_encoder(permission)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + OrganizationPermission, + construct_type( + type_=OrganizationPermission, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # 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 replace( + self, + id: int, + permission_: str, + *, + permission: str, + roles: typing.Optional[typing.Sequence[Role9E7Enum]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> OrganizationPermission: + """ + Replace the organization-level permission override for a given permission key. + + Parameters + ---------- + id : int + A unique integer value identifying this organization. + + permission_ : str + Permission key to update within the organization. + + permission : str + + roles : typing.Optional[typing.Sequence[Role9E7Enum]] + Explicit roles that have this permission within the organization. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + OrganizationPermission + + + Examples + -------- + import asyncio + + from label_studio_sdk import AsyncLabelStudio + + client = AsyncLabelStudio( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.organizations.permissions.replace( + id=1, + permission_="permission", + permission="permission", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/organizations/{jsonable_encoder(id)}/permissions/{jsonable_encoder(permission_)}", + method="PUT", + json={ + "permission": permission, + "roles": roles, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + OrganizationPermission, + construct_type( + type_=OrganizationPermission, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # 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 delete( + self, id: int, permission: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> None: + """ + Parameters + ---------- + id : int + + permission : str + + 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.organizations.permissions.delete( + id=1, + permission="permission", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/organizations/{jsonable_encoder(id)}/permissions/{jsonable_encoder(permission)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # 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 update( + self, + id: int, + permission: str, + *, + patched_organization_permission_request_permission: typing.Optional[str] = OMIT, + roles: typing.Optional[typing.Sequence[Role9E7Enum]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> OrganizationPermission: + """ + Partially update the organization-level permission override for a given permission key. + + Parameters + ---------- + id : int + + permission : str + + patched_organization_permission_request_permission : typing.Optional[str] + + roles : typing.Optional[typing.Sequence[Role9E7Enum]] + Explicit roles that have this permission within the organization. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + OrganizationPermission + + + Examples + -------- + import asyncio + + from label_studio_sdk import AsyncLabelStudio + + client = AsyncLabelStudio( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.organizations.permissions.update( + id=1, + permission="permission", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/organizations/{jsonable_encoder(id)}/permissions/{jsonable_encoder(permission)}", + method="PATCH", + json={ + "permission": patched_organization_permission_request_permission, + "roles": roles, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + OrganizationPermission, + construct_type( + type_=OrganizationPermission, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + typing.Optional[typing.Any], + construct_type( + type_=typing.Optional[typing.Any], # 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/projects/__init__.py b/src/label_studio_sdk/projects/__init__.py index fee07c3bc..eea32526c 100644 --- a/src/label_studio_sdk/projects/__init__.py +++ b/src/label_studio_sdk/projects/__init__.py @@ -29,13 +29,27 @@ ) from .exports import ExportsConvertResponse from .stats import ( + StatsAgreementAnnotatorResponse, + StatsDataFiltersResponse, + StatsDataFiltersResponseUserFilters, + StatsDataFiltersResponseUserFiltersStatsItem, + StatsFinishedTasksResponse, StatsIaaResponse, StatsIaaResponseCommonTasks, StatsIaaResponseIaa, StatsIaaResponseStd, + StatsLeadTimeResponse, + StatsLeadTimeResponseLeadTimeStatsItem, StatsTotalAgreementResponse, StatsTotalAgreementResponseOne, StatsTotalAgreementResponseZero, + StatsUserGroundTruthAgreementResponse, + StatsUserGroundTruthAgreementResponseAgreement, + StatsUserPredictionAgreementResponse, + StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser, + StatsUserReviewScoreResponse, + StatsUserReviewScoreResponsePerformanceScore, + StatsUserReviewScoreResponseReviewScore, ) __all__ = [ @@ -62,13 +76,27 @@ "ProjectsImportPredictionsResponse", "ProjectsImportTasksResponse", "ProjectsListRequestFilter", + "StatsAgreementAnnotatorResponse", + "StatsDataFiltersResponse", + "StatsDataFiltersResponseUserFilters", + "StatsDataFiltersResponseUserFiltersStatsItem", + "StatsFinishedTasksResponse", "StatsIaaResponse", "StatsIaaResponseCommonTasks", "StatsIaaResponseIaa", "StatsIaaResponseStd", + "StatsLeadTimeResponse", + "StatsLeadTimeResponseLeadTimeStatsItem", "StatsTotalAgreementResponse", "StatsTotalAgreementResponseOne", "StatsTotalAgreementResponseZero", + "StatsUserGroundTruthAgreementResponse", + "StatsUserGroundTruthAgreementResponseAgreement", + "StatsUserPredictionAgreementResponse", + "StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser", + "StatsUserReviewScoreResponse", + "StatsUserReviewScoreResponsePerformanceScore", + "StatsUserReviewScoreResponseReviewScore", "assignments", "exports", "members", diff --git a/src/label_studio_sdk/projects/stats/__init__.py b/src/label_studio_sdk/projects/stats/__init__.py index 581602a85..0cb78a0d6 100644 --- a/src/label_studio_sdk/projects/stats/__init__.py +++ b/src/label_studio_sdk/projects/stats/__init__.py @@ -1,21 +1,49 @@ # This file was auto-generated by Fern from our API Definition. from .types import ( + StatsAgreementAnnotatorResponse, + StatsDataFiltersResponse, + StatsDataFiltersResponseUserFilters, + StatsDataFiltersResponseUserFiltersStatsItem, + StatsFinishedTasksResponse, StatsIaaResponse, StatsIaaResponseCommonTasks, StatsIaaResponseIaa, StatsIaaResponseStd, + StatsLeadTimeResponse, + StatsLeadTimeResponseLeadTimeStatsItem, StatsTotalAgreementResponse, StatsTotalAgreementResponseOne, StatsTotalAgreementResponseZero, + StatsUserGroundTruthAgreementResponse, + StatsUserGroundTruthAgreementResponseAgreement, + StatsUserPredictionAgreementResponse, + StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser, + StatsUserReviewScoreResponse, + StatsUserReviewScoreResponsePerformanceScore, + StatsUserReviewScoreResponseReviewScore, ) __all__ = [ + "StatsAgreementAnnotatorResponse", + "StatsDataFiltersResponse", + "StatsDataFiltersResponseUserFilters", + "StatsDataFiltersResponseUserFiltersStatsItem", + "StatsFinishedTasksResponse", "StatsIaaResponse", "StatsIaaResponseCommonTasks", "StatsIaaResponseIaa", "StatsIaaResponseStd", + "StatsLeadTimeResponse", + "StatsLeadTimeResponseLeadTimeStatsItem", "StatsTotalAgreementResponse", "StatsTotalAgreementResponseOne", "StatsTotalAgreementResponseZero", + "StatsUserGroundTruthAgreementResponse", + "StatsUserGroundTruthAgreementResponseAgreement", + "StatsUserPredictionAgreementResponse", + "StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser", + "StatsUserReviewScoreResponse", + "StatsUserReviewScoreResponsePerformanceScore", + "StatsUserReviewScoreResponseReviewScore", ] diff --git a/src/label_studio_sdk/projects/stats/client.py b/src/label_studio_sdk/projects/stats/client.py index adb673a7e..508cc75ea 100644 --- a/src/label_studio_sdk/projects/stats/client.py +++ b/src/label_studio_sdk/projects/stats/client.py @@ -8,7 +8,14 @@ from ...core.unchecked_base_model import construct_type from json.decoder import JSONDecodeError from ...core.api_error import ApiError +from .types.stats_agreement_annotator_response import StatsAgreementAnnotatorResponse +from .types.stats_data_filters_response import StatsDataFiltersResponse +from .types.stats_finished_tasks_response import StatsFinishedTasksResponse +from .types.stats_lead_time_response import StatsLeadTimeResponse from .types.stats_total_agreement_response import StatsTotalAgreementResponse +from .types.stats_user_prediction_agreement_response import StatsUserPredictionAgreementResponse +from .types.stats_user_review_score_response import StatsUserReviewScoreResponse +from .types.stats_user_ground_truth_agreement_response import StatsUserGroundTruthAgreementResponse from ...core.client_wrapper import AsyncClientWrapper @@ -89,6 +96,205 @@ def iaa( raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) + def agreement_annotator( + self, id: int, user_id: int, *, request_options: typing.Optional[RequestOptions] = None + ) -> StatsAgreementAnnotatorResponse: + """ + Get agreement statistics for a specific annotator within a project. + + Parameters + ---------- + id : int + + user_id : int + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + StatsAgreementAnnotatorResponse + Individual annotator agreement statistics + + Examples + -------- + from label_studio_sdk import LabelStudio + + client = LabelStudio( + api_key="YOUR_API_KEY", + ) + client.projects.stats.agreement_annotator( + id=1, + user_id=1, + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/projects/{jsonable_encoder(id)}/stats/agreement_annotator/{jsonable_encoder(user_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + StatsAgreementAnnotatorResponse, + construct_type( + type_=StatsAgreementAnnotatorResponse, # 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 data_filters( + self, id: int, *, request_options: typing.Optional[RequestOptions] = None + ) -> StatsDataFiltersResponse: + """ + Get statistics about user data filters and their usage within a project. + + Parameters + ---------- + id : int + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + StatsDataFiltersResponse + User data filter statistics + + Examples + -------- + from label_studio_sdk import LabelStudio + + client = LabelStudio( + api_key="YOUR_API_KEY", + ) + client.projects.stats.data_filters( + id=1, + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/projects/{jsonable_encoder(id)}/stats/data_filter", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + StatsDataFiltersResponse, + construct_type( + type_=StatsDataFiltersResponse, # 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 finished_tasks( + self, id: int, *, user_pk: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None + ) -> StatsFinishedTasksResponse: + """ + Get statistics about finished tasks for a project. + + Parameters + ---------- + id : int + + user_pk : typing.Optional[int] + User ID to filter statistics by (optional) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + StatsFinishedTasksResponse + Finished tasks statistics + + Examples + -------- + from label_studio_sdk import LabelStudio + + client = LabelStudio( + api_key="YOUR_API_KEY", + ) + client.projects.stats.finished_tasks( + id=1, + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/projects/{jsonable_encoder(id)}/stats/finished", + method="GET", + params={ + "user_pk": user_pk, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + StatsFinishedTasksResponse, + construct_type( + type_=StatsFinishedTasksResponse, # 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 lead_time(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> StatsLeadTimeResponse: + """ + Get lead time statistics across the project, including average annotation time. + + Parameters + ---------- + id : int + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + StatsLeadTimeResponse + Lead time statistics + + Examples + -------- + from label_studio_sdk import LabelStudio + + client = LabelStudio( + api_key="YOUR_API_KEY", + ) + client.projects.stats.lead_time( + id=1, + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/projects/{jsonable_encoder(id)}/stats/lead_time", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + StatsLeadTimeResponse, + construct_type( + type_=StatsLeadTimeResponse, # 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 total_agreement( self, id: int, @@ -118,16 +324,647 @@ def total_agreement( Examples -------- - from label_studio_sdk import LabelStudio + from label_studio_sdk import LabelStudio + + client = LabelStudio( + api_key="YOUR_API_KEY", + ) + client.projects.stats.total_agreement( + id=1, + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/projects/{jsonable_encoder(id)}/stats/total_agreement", + method="GET", + params={ + "per_label": per_label, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + StatsTotalAgreementResponse, + construct_type( + type_=StatsTotalAgreementResponse, # 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 update_stats( + self, + id: int, + *, + stat_type: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> typing.Dict[str, typing.Optional[typing.Any]]: + """ + Start stats recalculation for given project + + Parameters + ---------- + id : int + + stat_type : typing.Optional[str] + Stat type to recalculate. Possible values: label, stats + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + typing.Dict[str, typing.Optional[typing.Any]] + Successful response returns job id + + Examples + -------- + from label_studio_sdk import LabelStudio + + client = LabelStudio( + api_key="YOUR_API_KEY", + ) + client.projects.stats.update_stats( + id=1, + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/projects/{jsonable_encoder(id)}/update-stats", + method="GET", + params={ + "stat_type": stat_type, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + typing.Dict[str, typing.Optional[typing.Any]], + construct_type( + type_=typing.Dict[str, typing.Optional[typing.Any]], # 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 user_prediction_agreement( + self, + id: int, + user_pk: int, + *, + per_label: typing.Optional[bool] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> StatsUserPredictionAgreementResponse: + """ + Get prediction agreement statistics for a specific user within a project. + + Parameters + ---------- + id : int + + user_pk : int + + per_label : typing.Optional[bool] + Calculate agreement per label + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + StatsUserPredictionAgreementResponse + Individual user prediction agreement statistics + + Examples + -------- + from label_studio_sdk import LabelStudio + + client = LabelStudio( + api_key="YOUR_API_KEY", + ) + client.projects.stats.user_prediction_agreement( + id=1, + user_pk=1, + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/projects/{jsonable_encoder(id)}/user-stats/{jsonable_encoder(user_pk)}/prediction", + method="GET", + params={ + "per_label": per_label, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + StatsUserPredictionAgreementResponse, + construct_type( + type_=StatsUserPredictionAgreementResponse, # 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 user_review_score( + self, + id: int, + user_pk: int, + *, + per_label: typing.Optional[bool] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> StatsUserReviewScoreResponse: + """ + Get review score statistics for a specific user within a project. + + Parameters + ---------- + id : int + + user_pk : int + + per_label : typing.Optional[bool] + Calculate agreement per label + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + StatsUserReviewScoreResponse + Individual user review score statistics + + Examples + -------- + from label_studio_sdk import LabelStudio + + client = LabelStudio( + api_key="YOUR_API_KEY", + ) + client.projects.stats.user_review_score( + id=1, + user_pk=1, + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/projects/{jsonable_encoder(id)}/user-stats/{jsonable_encoder(user_pk)}/review_score", + method="GET", + params={ + "per_label": per_label, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + StatsUserReviewScoreResponse, + construct_type( + type_=StatsUserReviewScoreResponse, # 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 user_ground_truth_agreement( + self, + id: int, + user_pk: int, + *, + per_label: typing.Optional[bool] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> StatsUserGroundTruthAgreementResponse: + """ + Get ground truth agreement statistics for a specific user within a project. + + Parameters + ---------- + id : int + + user_pk : int + + per_label : typing.Optional[bool] + Calculate agreement per label + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + StatsUserGroundTruthAgreementResponse + Individual user ground truth agreement statistics + + Examples + -------- + from label_studio_sdk import LabelStudio + + client = LabelStudio( + api_key="YOUR_API_KEY", + ) + client.projects.stats.user_ground_truth_agreement( + id=1, + user_pk=1, + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/projects/{jsonable_encoder(id)}/users/{jsonable_encoder(user_pk)}/stats/agreement-groundtruth", + method="GET", + params={ + "per_label": per_label, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + StatsUserGroundTruthAgreementResponse, + construct_type( + type_=StatsUserGroundTruthAgreementResponse, # 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 AsyncStatsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def iaa( + self, + id: int, + *, + expand: typing.Optional[str] = None, + per_label: typing.Optional[bool] = None, + std: typing.Optional[bool] = None, + task: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> StatsIaaResponse: + """ + Get Inter-Annotator Agreement (IAA) matrix for a project, showing agreement between all annotators. + + Parameters + ---------- + id : int + + expand : typing.Optional[str] + Comma-separated list of fields to expand + + per_label : typing.Optional[bool] + Calculate IAA per label + + std : typing.Optional[bool] + Include standard deviation in results + + task : typing.Optional[str] + Comma-separated list of task IDs to filter by + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + StatsIaaResponse + Inter-Annotator Agreement matrix + + Examples + -------- + import asyncio + + from label_studio_sdk import AsyncLabelStudio + + client = AsyncLabelStudio( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.projects.stats.iaa( + id=1, + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/projects/{jsonable_encoder(id)}/stats/IAA", + method="GET", + params={ + "expand": expand, + "per_label": per_label, + "std": std, + "task": task, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + StatsIaaResponse, + construct_type( + type_=StatsIaaResponse, # 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 agreement_annotator( + self, id: int, user_id: int, *, request_options: typing.Optional[RequestOptions] = None + ) -> StatsAgreementAnnotatorResponse: + """ + Get agreement statistics for a specific annotator within a project. + + Parameters + ---------- + id : int + + user_id : int + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + StatsAgreementAnnotatorResponse + Individual annotator agreement statistics + + Examples + -------- + import asyncio + + from label_studio_sdk import AsyncLabelStudio + + client = AsyncLabelStudio( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.projects.stats.agreement_annotator( + id=1, + user_id=1, + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/projects/{jsonable_encoder(id)}/stats/agreement_annotator/{jsonable_encoder(user_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + StatsAgreementAnnotatorResponse, + construct_type( + type_=StatsAgreementAnnotatorResponse, # 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 data_filters( + self, id: int, *, request_options: typing.Optional[RequestOptions] = None + ) -> StatsDataFiltersResponse: + """ + Get statistics about user data filters and their usage within a project. + + Parameters + ---------- + id : int + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + StatsDataFiltersResponse + User data filter statistics + + Examples + -------- + import asyncio + + from label_studio_sdk import AsyncLabelStudio + + client = AsyncLabelStudio( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.projects.stats.data_filters( + id=1, + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/projects/{jsonable_encoder(id)}/stats/data_filter", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + StatsDataFiltersResponse, + construct_type( + type_=StatsDataFiltersResponse, # 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 finished_tasks( + self, id: int, *, user_pk: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None + ) -> StatsFinishedTasksResponse: + """ + Get statistics about finished tasks for a project. + + Parameters + ---------- + id : int + + user_pk : typing.Optional[int] + User ID to filter statistics by (optional) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + StatsFinishedTasksResponse + Finished tasks statistics + + Examples + -------- + import asyncio + + from label_studio_sdk import AsyncLabelStudio + + client = AsyncLabelStudio( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.projects.stats.finished_tasks( + id=1, + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/projects/{jsonable_encoder(id)}/stats/finished", + method="GET", + params={ + "user_pk": user_pk, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + StatsFinishedTasksResponse, + construct_type( + type_=StatsFinishedTasksResponse, # 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 lead_time( + self, id: int, *, request_options: typing.Optional[RequestOptions] = None + ) -> StatsLeadTimeResponse: + """ + Get lead time statistics across the project, including average annotation time. + + Parameters + ---------- + id : int + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + StatsLeadTimeResponse + Lead time statistics + + Examples + -------- + import asyncio + + from label_studio_sdk import AsyncLabelStudio + + client = AsyncLabelStudio( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.projects.stats.lead_time( + id=1, + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/projects/{jsonable_encoder(id)}/stats/lead_time", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + StatsLeadTimeResponse, + construct_type( + type_=StatsLeadTimeResponse, # 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 total_agreement( + self, + id: int, + *, + per_label: typing.Optional[bool] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> StatsTotalAgreementResponse: + """ + Overall or per-label total agreement across the project. + + NOTE: due to an open issue in Fern, SDK clients will raise ApiError upon handling a 204 response. As a workaround, wrap call to this function in a try-except block. + + Parameters + ---------- + id : int + + per_label : typing.Optional[bool] + Return agreement per label + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + StatsTotalAgreementResponse + Total agreement + + Examples + -------- + import asyncio - client = LabelStudio( + from label_studio_sdk import AsyncLabelStudio + + client = AsyncLabelStudio( api_key="YOUR_API_KEY", ) - client.projects.stats.total_agreement( - id=1, - ) + + + async def main() -> None: + await client.projects.stats.total_agreement( + id=1, + ) + + + asyncio.run(main()) """ - _response = self._client_wrapper.httpx_client.request( + _response = await self._client_wrapper.httpx_client.request( f"api/projects/{jsonable_encoder(id)}/stats/total_agreement", method="GET", params={ @@ -149,47 +986,169 @@ def total_agreement( raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) + async def update_stats( + self, + id: int, + *, + stat_type: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> typing.Dict[str, typing.Optional[typing.Any]]: + """ + Start stats recalculation for given project -class AsyncStatsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper + Parameters + ---------- + id : int - async def iaa( + stat_type : typing.Optional[str] + Stat type to recalculate. Possible values: label, stats + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + typing.Dict[str, typing.Optional[typing.Any]] + Successful response returns job id + + Examples + -------- + import asyncio + + from label_studio_sdk import AsyncLabelStudio + + client = AsyncLabelStudio( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.projects.stats.update_stats( + id=1, + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/projects/{jsonable_encoder(id)}/update-stats", + method="GET", + params={ + "stat_type": stat_type, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + typing.Dict[str, typing.Optional[typing.Any]], + construct_type( + type_=typing.Dict[str, typing.Optional[typing.Any]], # 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 user_prediction_agreement( self, id: int, + user_pk: int, *, - expand: typing.Optional[str] = None, per_label: typing.Optional[bool] = None, - std: typing.Optional[bool] = None, - task: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> StatsIaaResponse: + ) -> StatsUserPredictionAgreementResponse: """ - Get Inter-Annotator Agreement (IAA) matrix for a project, showing agreement between all annotators. + Get prediction agreement statistics for a specific user within a project. Parameters ---------- id : int - expand : typing.Optional[str] - Comma-separated list of fields to expand + user_pk : int per_label : typing.Optional[bool] - Calculate IAA per label + Calculate agreement per label - std : typing.Optional[bool] - Include standard deviation in results + request_options : typing.Optional[RequestOptions] + Request-specific configuration. - task : typing.Optional[str] - Comma-separated list of task IDs to filter by + Returns + ------- + StatsUserPredictionAgreementResponse + Individual user prediction agreement statistics + + Examples + -------- + import asyncio + + from label_studio_sdk import AsyncLabelStudio + + client = AsyncLabelStudio( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.projects.stats.user_prediction_agreement( + id=1, + user_pk=1, + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/projects/{jsonable_encoder(id)}/user-stats/{jsonable_encoder(user_pk)}/prediction", + method="GET", + params={ + "per_label": per_label, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + StatsUserPredictionAgreementResponse, + construct_type( + type_=StatsUserPredictionAgreementResponse, # 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 user_review_score( + self, + id: int, + user_pk: int, + *, + per_label: typing.Optional[bool] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> StatsUserReviewScoreResponse: + """ + Get review score statistics for a specific user within a project. + + Parameters + ---------- + id : int + + user_pk : int + + per_label : typing.Optional[bool] + Calculate agreement per label request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - StatsIaaResponse - Inter-Annotator Agreement matrix + StatsUserReviewScoreResponse + Individual user review score statistics Examples -------- @@ -203,30 +1162,28 @@ async def iaa( async def main() -> None: - await client.projects.stats.iaa( + await client.projects.stats.user_review_score( id=1, + user_pk=1, ) asyncio.run(main()) """ _response = await self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/stats/IAA", + f"api/projects/{jsonable_encoder(id)}/user-stats/{jsonable_encoder(user_pk)}/review_score", method="GET", params={ - "expand": expand, "per_label": per_label, - "std": std, - "task": task, }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: return typing.cast( - StatsIaaResponse, + StatsUserReviewScoreResponse, construct_type( - type_=StatsIaaResponse, # type: ignore + type_=StatsUserReviewScoreResponse, # type: ignore object_=_response.json(), ), ) @@ -235,32 +1192,33 @@ async def main() -> None: raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) - async def total_agreement( + async def user_ground_truth_agreement( self, id: int, + user_pk: int, *, per_label: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> StatsTotalAgreementResponse: + ) -> StatsUserGroundTruthAgreementResponse: """ - Overall or per-label total agreement across the project. - - NOTE: due to an open issue in Fern, SDK clients will raise ApiError upon handling a 204 response. As a workaround, wrap call to this function in a try-except block. + Get ground truth agreement statistics for a specific user within a project. Parameters ---------- id : int + user_pk : int + per_label : typing.Optional[bool] - Return agreement per label + Calculate agreement per label request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - StatsTotalAgreementResponse - Total agreement + StatsUserGroundTruthAgreementResponse + Individual user ground truth agreement statistics Examples -------- @@ -274,15 +1232,16 @@ async def total_agreement( async def main() -> None: - await client.projects.stats.total_agreement( + await client.projects.stats.user_ground_truth_agreement( id=1, + user_pk=1, ) asyncio.run(main()) """ _response = await self._client_wrapper.httpx_client.request( - f"api/projects/{jsonable_encoder(id)}/stats/total_agreement", + f"api/projects/{jsonable_encoder(id)}/users/{jsonable_encoder(user_pk)}/stats/agreement-groundtruth", method="GET", params={ "per_label": per_label, @@ -292,9 +1251,9 @@ async def main() -> None: try: if 200 <= _response.status_code < 300: return typing.cast( - StatsTotalAgreementResponse, + StatsUserGroundTruthAgreementResponse, construct_type( - type_=StatsTotalAgreementResponse, # type: ignore + type_=StatsUserGroundTruthAgreementResponse, # type: ignore object_=_response.json(), ), ) diff --git a/src/label_studio_sdk/projects/stats/types/__init__.py b/src/label_studio_sdk/projects/stats/types/__init__.py index 6c85c31f5..85fe87687 100644 --- a/src/label_studio_sdk/projects/stats/types/__init__.py +++ b/src/label_studio_sdk/projects/stats/types/__init__.py @@ -1,19 +1,49 @@ # This file was auto-generated by Fern from our API Definition. +from .stats_agreement_annotator_response import StatsAgreementAnnotatorResponse +from .stats_data_filters_response import StatsDataFiltersResponse +from .stats_data_filters_response_user_filters import StatsDataFiltersResponseUserFilters +from .stats_data_filters_response_user_filters_stats_item import StatsDataFiltersResponseUserFiltersStatsItem +from .stats_finished_tasks_response import StatsFinishedTasksResponse from .stats_iaa_response import StatsIaaResponse from .stats_iaa_response_common_tasks import StatsIaaResponseCommonTasks from .stats_iaa_response_iaa import StatsIaaResponseIaa from .stats_iaa_response_std import StatsIaaResponseStd +from .stats_lead_time_response import StatsLeadTimeResponse +from .stats_lead_time_response_lead_time_stats_item import StatsLeadTimeResponseLeadTimeStatsItem from .stats_total_agreement_response import StatsTotalAgreementResponse from .stats_total_agreement_response_one import StatsTotalAgreementResponseOne from .stats_total_agreement_response_zero import StatsTotalAgreementResponseZero +from .stats_user_ground_truth_agreement_response import StatsUserGroundTruthAgreementResponse +from .stats_user_ground_truth_agreement_response_agreement import StatsUserGroundTruthAgreementResponseAgreement +from .stats_user_prediction_agreement_response import StatsUserPredictionAgreementResponse +from .stats_user_prediction_agreement_response_average_prediction_agreement_per_user import ( + StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser, +) +from .stats_user_review_score_response import StatsUserReviewScoreResponse +from .stats_user_review_score_response_performance_score import StatsUserReviewScoreResponsePerformanceScore +from .stats_user_review_score_response_review_score import StatsUserReviewScoreResponseReviewScore __all__ = [ + "StatsAgreementAnnotatorResponse", + "StatsDataFiltersResponse", + "StatsDataFiltersResponseUserFilters", + "StatsDataFiltersResponseUserFiltersStatsItem", + "StatsFinishedTasksResponse", "StatsIaaResponse", "StatsIaaResponseCommonTasks", "StatsIaaResponseIaa", "StatsIaaResponseStd", + "StatsLeadTimeResponse", + "StatsLeadTimeResponseLeadTimeStatsItem", "StatsTotalAgreementResponse", "StatsTotalAgreementResponseOne", "StatsTotalAgreementResponseZero", + "StatsUserGroundTruthAgreementResponse", + "StatsUserGroundTruthAgreementResponseAgreement", + "StatsUserPredictionAgreementResponse", + "StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser", + "StatsUserReviewScoreResponse", + "StatsUserReviewScoreResponsePerformanceScore", + "StatsUserReviewScoreResponseReviewScore", ] diff --git a/src/label_studio_sdk/projects/stats/types/stats_agreement_annotator_response.py b/src/label_studio_sdk/projects/stats/types/stats_agreement_annotator_response.py new file mode 100644 index 000000000..2b349891f --- /dev/null +++ b/src/label_studio_sdk/projects/stats/types/stats_agreement_annotator_response.py @@ -0,0 +1,26 @@ +# This file was auto-generated by Fern from our API Definition. + +from ....core.unchecked_base_model import UncheckedBaseModel +import typing_extensions +import typing +from ....core.serialization import FieldMetadata +import pydantic +from ....core.pydantic_utilities import IS_PYDANTIC_V2 + + +class StatsAgreementAnnotatorResponse(UncheckedBaseModel): + agreement_per_annotator: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="Agreement_per_annotator") + ] = pydantic.Field(default=None) + """ + Agreement score for the annotator (0-1) + """ + + 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/projects/stats/types/stats_data_filters_response.py b/src/label_studio_sdk/projects/stats/types/stats_data_filters_response.py new file mode 100644 index 000000000..acefc57bc --- /dev/null +++ b/src/label_studio_sdk/projects/stats/types/stats_data_filters_response.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +from ....core.unchecked_base_model import UncheckedBaseModel +import typing +from .stats_data_filters_response_user_filters import StatsDataFiltersResponseUserFilters +import pydantic +from ....core.pydantic_utilities import IS_PYDANTIC_V2 + + +class StatsDataFiltersResponse(UncheckedBaseModel): + user_filters: typing.Optional[StatsDataFiltersResponseUserFilters] = pydantic.Field(default=None) + """ + Data filter statistics by user and model + """ + + 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/projects/stats/types/stats_data_filters_response_user_filters.py b/src/label_studio_sdk/projects/stats/types/stats_data_filters_response_user_filters.py new file mode 100644 index 000000000..d1937add9 --- /dev/null +++ b/src/label_studio_sdk/projects/stats/types/stats_data_filters_response_user_filters.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +from ....core.unchecked_base_model import UncheckedBaseModel +import typing +from .stats_data_filters_response_user_filters_stats_item import StatsDataFiltersResponseUserFiltersStatsItem +import pydantic +from ....core.pydantic_utilities import IS_PYDANTIC_V2 + + +class StatsDataFiltersResponseUserFilters(UncheckedBaseModel): + """ + Data filter statistics by user and model + """ + + stats: typing.Optional[typing.List[StatsDataFiltersResponseUserFiltersStatsItem]] = pydantic.Field(default=None) + """ + List of filter configurations for users and models + """ + + tasks_with_annotations: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field( + default=None + ) + """ + Default filter tab for tasks with annotations + """ + + 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/projects/stats/types/stats_data_filters_response_user_filters_stats_item.py b/src/label_studio_sdk/projects/stats/types/stats_data_filters_response_user_filters_stats_item.py new file mode 100644 index 000000000..5839cd96c --- /dev/null +++ b/src/label_studio_sdk/projects/stats/types/stats_data_filters_response_user_filters_stats_item.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +from ....core.unchecked_base_model import UncheckedBaseModel +import typing +import pydantic +from ....core.pydantic_utilities import IS_PYDANTIC_V2 + + +class StatsDataFiltersResponseUserFiltersStatsItem(UncheckedBaseModel): + id: typing.Optional[str] = pydantic.Field(default=None) + """ + User ID or model version identifier (e.g., "model:1.0") + """ + + 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/projects/stats/types/stats_finished_tasks_response.py b/src/label_studio_sdk/projects/stats/types/stats_finished_tasks_response.py new file mode 100644 index 000000000..65e7cdb7a --- /dev/null +++ b/src/label_studio_sdk/projects/stats/types/stats_finished_tasks_response.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +from ....core.unchecked_base_model import UncheckedBaseModel +import typing +import pydantic +from ....core.pydantic_utilities import IS_PYDANTIC_V2 + + +class StatsFinishedTasksResponse(UncheckedBaseModel): + finished: typing.Optional[int] = pydantic.Field(default=None) + """ + Number of finished tasks + """ + + id: typing.Optional[int] = pydantic.Field(default=None) + """ + User ID + """ + + progress: typing.Optional[int] = pydantic.Field(default=None) + """ + Progress percentage (0-100) + """ + + 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/projects/stats/types/stats_lead_time_response.py b/src/label_studio_sdk/projects/stats/types/stats_lead_time_response.py new file mode 100644 index 000000000..d0175fb94 --- /dev/null +++ b/src/label_studio_sdk/projects/stats/types/stats_lead_time_response.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +from ....core.unchecked_base_model import UncheckedBaseModel +import typing +from .stats_lead_time_response_lead_time_stats_item import StatsLeadTimeResponseLeadTimeStatsItem +import pydantic +from ....core.pydantic_utilities import IS_PYDANTIC_V2 + + +class StatsLeadTimeResponse(UncheckedBaseModel): + lead_time_stats: typing.Optional[typing.List[StatsLeadTimeResponseLeadTimeStatsItem]] = pydantic.Field(default=None) + """ + Lead time statistics including mean, median, and distribution + """ + + 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/projects/stats/types/stats_lead_time_response_lead_time_stats_item.py b/src/label_studio_sdk/projects/stats/types/stats_lead_time_response_lead_time_stats_item.py new file mode 100644 index 000000000..d4fbca4b2 --- /dev/null +++ b/src/label_studio_sdk/projects/stats/types/stats_lead_time_response_lead_time_stats_item.py @@ -0,0 +1,37 @@ +# This file was auto-generated by Fern from our API Definition. + +from ....core.unchecked_base_model import UncheckedBaseModel +import typing +import pydantic +from ....core.pydantic_utilities import IS_PYDANTIC_V2 + + +class StatsLeadTimeResponseLeadTimeStatsItem(UncheckedBaseModel): + mean_time: typing.Optional[float] = pydantic.Field(default=None) + """ + Average lead time for the user + """ + + median_time: typing.Optional[float] = pydantic.Field(default=None) + """ + Median lead time for the user + """ + + sum_lead_time: typing.Optional[float] = pydantic.Field(default=None) + """ + Total lead time for the user + """ + + user_id: typing.Optional[int] = pydantic.Field(default=None) + """ + User ID + """ + + 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/projects/stats/types/stats_user_ground_truth_agreement_response.py b/src/label_studio_sdk/projects/stats/types/stats_user_ground_truth_agreement_response.py new file mode 100644 index 000000000..cf78669ea --- /dev/null +++ b/src/label_studio_sdk/projects/stats/types/stats_user_ground_truth_agreement_response.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +from ....core.unchecked_base_model import UncheckedBaseModel +import typing +from .stats_user_ground_truth_agreement_response_agreement import StatsUserGroundTruthAgreementResponseAgreement +from ....core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class StatsUserGroundTruthAgreementResponse(UncheckedBaseModel): + agreement: typing.Optional[StatsUserGroundTruthAgreementResponseAgreement] = None + + 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/projects/stats/types/stats_user_ground_truth_agreement_response_agreement.py b/src/label_studio_sdk/projects/stats/types/stats_user_ground_truth_agreement_response_agreement.py new file mode 100644 index 000000000..e96b04a42 --- /dev/null +++ b/src/label_studio_sdk/projects/stats/types/stats_user_ground_truth_agreement_response_agreement.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +StatsUserGroundTruthAgreementResponseAgreement = typing.Union[float, typing.Dict[str, float]] diff --git a/src/label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response.py b/src/label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response.py new file mode 100644 index 000000000..71efcb3d3 --- /dev/null +++ b/src/label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +from ....core.unchecked_base_model import UncheckedBaseModel +import typing +from .stats_user_prediction_agreement_response_average_prediction_agreement_per_user import ( + StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser, +) +from ....core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class StatsUserPredictionAgreementResponse(UncheckedBaseModel): + average_prediction_agreement_per_user: typing.Optional[ + StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser + ] = None + + 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/projects/stats/types/stats_user_prediction_agreement_response_average_prediction_agreement_per_user.py b/src/label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response_average_prediction_agreement_per_user.py new file mode 100644 index 000000000..553a16b31 --- /dev/null +++ b/src/label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response_average_prediction_agreement_per_user.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +StatsUserPredictionAgreementResponseAveragePredictionAgreementPerUser = typing.Union[float, typing.Dict[str, float]] diff --git a/src/label_studio_sdk/projects/stats/types/stats_user_review_score_response.py b/src/label_studio_sdk/projects/stats/types/stats_user_review_score_response.py new file mode 100644 index 000000000..de7dcf7e9 --- /dev/null +++ b/src/label_studio_sdk/projects/stats/types/stats_user_review_score_response.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +from ....core.unchecked_base_model import UncheckedBaseModel +import typing +from .stats_user_review_score_response_performance_score import StatsUserReviewScoreResponsePerformanceScore +from .stats_user_review_score_response_review_score import StatsUserReviewScoreResponseReviewScore +from ....core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class StatsUserReviewScoreResponse(UncheckedBaseModel): + performance_score: typing.Optional[StatsUserReviewScoreResponsePerformanceScore] = None + review_score: typing.Optional[StatsUserReviewScoreResponseReviewScore] = None + + 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/projects/stats/types/stats_user_review_score_response_performance_score.py b/src/label_studio_sdk/projects/stats/types/stats_user_review_score_response_performance_score.py new file mode 100644 index 000000000..cca02c711 --- /dev/null +++ b/src/label_studio_sdk/projects/stats/types/stats_user_review_score_response_performance_score.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +StatsUserReviewScoreResponsePerformanceScore = typing.Union[float, typing.Dict[str, float]] diff --git a/src/label_studio_sdk/projects/stats/types/stats_user_review_score_response_review_score.py b/src/label_studio_sdk/projects/stats/types/stats_user_review_score_response_review_score.py new file mode 100644 index 000000000..75909433d --- /dev/null +++ b/src/label_studio_sdk/projects/stats/types/stats_user_review_score_response_review_score.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +StatsUserReviewScoreResponseReviewScore = typing.Union[float, typing.Dict[str, float]] diff --git a/src/label_studio_sdk/types/__init__.py b/src/label_studio_sdk/types/__init__.py index 916608b86..f539e9f73 100644 --- a/src/label_studio_sdk/types/__init__.py +++ b/src/label_studio_sdk/types/__init__.py @@ -43,13 +43,14 @@ from .comment import Comment from .comment_request import CommentRequest from .comment_serializer_with_expanded_user import CommentSerializerWithExpandedUser +from .configurable_permission_option import ConfigurablePermissionOption +from .configurable_permission_option_default import ConfigurablePermissionOptionDefault from .converted_format import ConvertedFormat from .converted_format_request import ConvertedFormatRequest from .count_limit import CountLimit from .custom_scripts_editable_by_enum import CustomScriptsEditableByEnum from .default_role import DefaultRole from .default_role_custom_scripts_editable_by import DefaultRoleCustomScriptsEditableBy -from .default_role_enum import DefaultRoleEnum from .edition_enum import EditionEnum from .export import Export from .file_upload import FileUpload @@ -139,6 +140,8 @@ from .organization_invite import OrganizationInvite from .organization_member import OrganizationMember from .organization_membership import OrganizationMembership +from .organization_permission import OrganizationPermission +from .organization_permission_request import OrganizationPermissionRequest from .paginated_all_roles_project_list_list import PaginatedAllRolesProjectListList from .paginated_annotation_history_list import PaginatedAnnotationHistoryList from .paginated_lse_organization_member_list_list import PaginatedLseOrganizationMemberListList @@ -265,13 +268,14 @@ "Comment", "CommentRequest", "CommentSerializerWithExpandedUser", + "ConfigurablePermissionOption", + "ConfigurablePermissionOptionDefault", "ConvertedFormat", "ConvertedFormatRequest", "CountLimit", "CustomScriptsEditableByEnum", "DefaultRole", "DefaultRoleCustomScriptsEditableBy", - "DefaultRoleEnum", "EditionEnum", "Export", "FileUpload", @@ -361,6 +365,8 @@ "OrganizationInvite", "OrganizationMember", "OrganizationMembership", + "OrganizationPermission", + "OrganizationPermissionRequest", "PaginatedAllRolesProjectListList", "PaginatedAnnotationHistoryList", "PaginatedLseOrganizationMemberListList", diff --git a/src/label_studio_sdk/types/configurable_permission_option.py b/src/label_studio_sdk/types/configurable_permission_option.py new file mode 100644 index 000000000..db9475f8e --- /dev/null +++ b/src/label_studio_sdk/types/configurable_permission_option.py @@ -0,0 +1,25 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.unchecked_base_model import UncheckedBaseModel +import typing +from .configurable_permission_option_default import ConfigurablePermissionOptionDefault +from .role9e7enum import Role9E7Enum +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ConfigurablePermissionOption(UncheckedBaseModel): + default: typing.Optional[ConfigurablePermissionOptionDefault] = None + label: typing.Optional[str] = None + options: typing.List[Role9E7Enum] + permission: str + tooltip: typing.Optional[str] = None + + 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/configurable_permission_option_default.py b/src/label_studio_sdk/types/configurable_permission_option_default.py new file mode 100644 index 000000000..ee182d47a --- /dev/null +++ b/src/label_studio_sdk/types/configurable_permission_option_default.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from .role9e7enum import Role9E7Enum +from .null_enum import NullEnum + +ConfigurablePermissionOptionDefault = typing.Union[Role9E7Enum, NullEnum] diff --git a/src/label_studio_sdk/types/default_role.py b/src/label_studio_sdk/types/default_role.py index fe031178a..0ad8ea3ac 100644 --- a/src/label_studio_sdk/types/default_role.py +++ b/src/label_studio_sdk/types/default_role.py @@ -5,7 +5,7 @@ import datetime as dt import pydantic from .default_role_custom_scripts_editable_by import DefaultRoleCustomScriptsEditableBy -from .default_role_enum import DefaultRoleEnum +from .role9e7enum import Role9E7Enum from ..core.pydantic_utilities import IS_PYDANTIC_V2 @@ -28,7 +28,7 @@ class DefaultRole(UncheckedBaseModel): Set to current time to enabled custom scripts for this organization. Can only be enabled if no organization members are active members of any other organizations; otherwise an error will be raised. If this occurs, contact the LEAP team for assistance with enabling custom scripts. """ - default_role: typing.Optional[DefaultRoleEnum] = pydantic.Field(default=None) + default_role: typing.Optional[Role9E7Enum] = pydantic.Field(default=None) """ Default membership role for invited users diff --git a/src/label_studio_sdk/types/default_role_enum.py b/src/label_studio_sdk/types/default_role_enum.py deleted file mode 100644 index 37e91a29c..000000000 --- a/src/label_studio_sdk/types/default_role_enum.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -DefaultRoleEnum = typing.Union[typing.Literal["OW", "AD", "MA", "RE", "AN", "DI", "NO"], typing.Any] diff --git a/src/label_studio_sdk/types/lse_organization.py b/src/label_studio_sdk/types/lse_organization.py index cfd182c7c..511a055e9 100644 --- a/src/label_studio_sdk/types/lse_organization.py +++ b/src/label_studio_sdk/types/lse_organization.py @@ -6,7 +6,7 @@ import typing from .lse_organization_custom_scripts_editable_by import LseOrganizationCustomScriptsEditableBy import pydantic -from .default_role_enum import DefaultRoleEnum +from .role9e7enum import Role9E7Enum from ..core.pydantic_utilities import IS_PYDANTIC_V2 @@ -22,7 +22,7 @@ class LseOrganization(UncheckedBaseModel): """ custom_scripts_enabled: str - default_role: typing.Optional[DefaultRoleEnum] = pydantic.Field(default=None) + default_role: typing.Optional[Role9E7Enum] = pydantic.Field(default=None) """ Default membership role for invited users diff --git a/src/label_studio_sdk/types/organization_permission.py b/src/label_studio_sdk/types/organization_permission.py new file mode 100644 index 000000000..e9ca4c416 --- /dev/null +++ b/src/label_studio_sdk/types/organization_permission.py @@ -0,0 +1,31 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.unchecked_base_model import UncheckedBaseModel +import typing +from .role9e7enum import Role9E7Enum +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class OrganizationPermission(UncheckedBaseModel): + default_role: str + id: int + label: str + options: str + organization: int + permission: str + roles: typing.Optional[typing.List[Role9E7Enum]] = pydantic.Field(default=None) + """ + Explicit roles that have this permission within the organization. + """ + + tooltip: str + + 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/organization_permission_request.py b/src/label_studio_sdk/types/organization_permission_request.py new file mode 100644 index 000000000..6f333242a --- /dev/null +++ b/src/label_studio_sdk/types/organization_permission_request.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.unchecked_base_model import UncheckedBaseModel +import typing +from .role9e7enum import Role9E7Enum +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class OrganizationPermissionRequest(UncheckedBaseModel): + permission: str + roles: typing.Optional[typing.List[Role9E7Enum]] = pydantic.Field(default=None) + """ + Explicit roles that have this permission within the organization. + """ + + 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/tests/organizations/test_permissions.py b/tests/organizations/test_permissions.py new file mode 100644 index 000000000..813475542 --- /dev/null +++ b/tests/organizations/test_permissions.py @@ -0,0 +1,183 @@ +# 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 = [ + { + "default_role": "default_role", + "id": 1, + "label": "label", + "options": "options", + "organization": 1, + "permission": "permission", + "roles": ["OW"], + "tooltip": "tooltip", + } + ] + expected_types: typing.Tuple[typing.Any, typing.Any] = ( + "list", + { + 0: { + "default_role": None, + "id": "integer", + "label": None, + "options": None, + "organization": "integer", + "permission": None, + "roles": ("list", {0: None}), + "tooltip": None, + } + }, + ) + response = client.organizations.permissions.list(id=1) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.organizations.permissions.list(id=1) + validate_response(async_response, expected_response, expected_types) + + +async def test_create(client: LabelStudio, async_client: AsyncLabelStudio) -> None: + expected_response: typing.Any = { + "default_role": "default_role", + "id": 1, + "label": "label", + "options": "options", + "organization": 1, + "permission": "permission", + "roles": ["OW"], + "tooltip": "tooltip", + } + expected_types: typing.Any = { + "default_role": None, + "id": "integer", + "label": None, + "options": None, + "organization": "integer", + "permission": None, + "roles": ("list", {0: None}), + "tooltip": None, + } + response = client.organizations.permissions.create(id=1, permission="permission") + validate_response(response, expected_response, expected_types) + + async_response = await async_client.organizations.permissions.create(id=1, permission="permission") + validate_response(async_response, expected_response, expected_types) + + +async def test_get_options(client: LabelStudio, async_client: AsyncLabelStudio) -> None: + expected_response: typing.Any = [ + {"default": "OW", "label": "label", "options": ["OW"], "permission": "permission", "tooltip": "tooltip"} + ] + expected_types: typing.Tuple[typing.Any, typing.Any] = ( + "list", + {0: {"default": None, "label": None, "options": ("list", {0: None}), "permission": None, "tooltip": None}}, + ) + response = client.organizations.permissions.get_options(id=1) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.organizations.permissions.get_options(id=1) + validate_response(async_response, expected_response, expected_types) + + +async def test_get(client: LabelStudio, async_client: AsyncLabelStudio) -> None: + expected_response: typing.Any = { + "default_role": "default_role", + "id": 1, + "label": "label", + "options": "options", + "organization": 1, + "permission": "permission", + "roles": ["OW"], + "tooltip": "tooltip", + } + expected_types: typing.Any = { + "default_role": None, + "id": "integer", + "label": None, + "options": None, + "organization": "integer", + "permission": None, + "roles": ("list", {0: None}), + "tooltip": None, + } + response = client.organizations.permissions.get(id=1, permission="permission") + validate_response(response, expected_response, expected_types) + + async_response = await async_client.organizations.permissions.get(id=1, permission="permission") + validate_response(async_response, expected_response, expected_types) + + +async def test_replace(client: LabelStudio, async_client: AsyncLabelStudio) -> None: + expected_response: typing.Any = { + "default_role": "default_role", + "id": 1, + "label": "label", + "options": "options", + "organization": 1, + "permission": "permission", + "roles": ["OW"], + "tooltip": "tooltip", + } + expected_types: typing.Any = { + "default_role": None, + "id": "integer", + "label": None, + "options": None, + "organization": "integer", + "permission": None, + "roles": ("list", {0: None}), + "tooltip": None, + } + response = client.organizations.permissions.replace(id=1, permission_="permission", permission="permission") + validate_response(response, expected_response, expected_types) + + async_response = await async_client.organizations.permissions.replace( + id=1, permission_="permission", permission="permission" + ) + validate_response(async_response, expected_response, expected_types) + + +async def test_delete(client: LabelStudio, async_client: AsyncLabelStudio) -> None: + # Type ignore to avoid mypy complaining about the function not being meant to return a value + assert ( + client.organizations.permissions.delete(id=1, permission="permission") # type: ignore[func-returns-value] + is None + ) + + assert ( + await async_client.organizations.permissions.delete(id=1, permission="permission") # type: ignore[func-returns-value] + is None + ) + + +async def test_update(client: LabelStudio, async_client: AsyncLabelStudio) -> None: + expected_response: typing.Any = { + "default_role": "default_role", + "id": 1, + "label": "label", + "options": "options", + "organization": 1, + "permission": "permission", + "roles": ["OW"], + "tooltip": "tooltip", + } + expected_types: typing.Any = { + "default_role": None, + "id": "integer", + "label": None, + "options": None, + "organization": "integer", + "permission": None, + "roles": ("list", {0: None}), + "tooltip": None, + } + response = client.organizations.permissions.update(id=1, permission="permission") + validate_response(response, expected_response, expected_types) + + async_response = await async_client.organizations.permissions.update(id=1, permission="permission") + validate_response(async_response, expected_response, expected_types) diff --git a/tests/projects/test_stats.py b/tests/projects/test_stats.py index f1e74a60a..0a36d76af 100644 --- a/tests/projects/test_stats.py +++ b/tests/projects/test_stats.py @@ -29,6 +29,55 @@ async def test_iaa(client: LabelStudio, async_client: AsyncLabelStudio) -> None: validate_response(async_response, expected_response, expected_types) +async def test_agreement_annotator(client: LabelStudio, async_client: AsyncLabelStudio) -> None: + expected_response: typing.Any = {"Agreement_per_annotator": 1.1} + expected_types: typing.Any = {"Agreement_per_annotator": None} + response = client.projects.stats.agreement_annotator(id=1, user_id=1) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.projects.stats.agreement_annotator(id=1, user_id=1) + validate_response(async_response, expected_response, expected_types) + + +async def test_data_filters(client: LabelStudio, async_client: AsyncLabelStudio) -> None: + expected_response: typing.Any = {"user_filters": {"stats": [{}], "tasks_with_annotations": {"key": "value"}}} + expected_types: typing.Any = { + "user_filters": {"stats": ("list", {0: {}}), "tasks_with_annotations": ("dict", {0: (None, None)})} + } + response = client.projects.stats.data_filters(id=1) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.projects.stats.data_filters(id=1) + validate_response(async_response, expected_response, expected_types) + + +async def test_finished_tasks(client: LabelStudio, async_client: AsyncLabelStudio) -> None: + expected_response: typing.Any = {"finished": 1, "id": 1, "progress": 1} + expected_types: typing.Any = {"finished": "integer", "id": "integer", "progress": "integer"} + response = client.projects.stats.finished_tasks(id=1) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.projects.stats.finished_tasks(id=1) + validate_response(async_response, expected_response, expected_types) + + +async def test_lead_time(client: LabelStudio, async_client: AsyncLabelStudio) -> None: + expected_response: typing.Any = { + "lead_time_stats": [{"mean_time": 1.1, "median_time": 1.1, "sum_lead_time": 1.1, "user_id": 1}] + } + expected_types: typing.Any = { + "lead_time_stats": ( + "list", + {0: {"mean_time": None, "median_time": None, "sum_lead_time": None, "user_id": "integer"}}, + ) + } + response = client.projects.stats.lead_time(id=1) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.projects.stats.lead_time(id=1) + validate_response(async_response, expected_response, expected_types) + + async def test_total_agreement(client: LabelStudio, async_client: AsyncLabelStudio) -> None: expected_response: typing.Any = {"total_agreement": 1.1} expected_types: typing.Any = {"total_agreement": None} @@ -37,3 +86,43 @@ async def test_total_agreement(client: LabelStudio, async_client: AsyncLabelStud async_response = await async_client.projects.stats.total_agreement(id=1) validate_response(async_response, expected_response, expected_types) + + +async def test_update_stats(client: LabelStudio, async_client: AsyncLabelStudio) -> None: + expected_response: typing.Any = {"key": "value"} + expected_types: typing.Tuple[typing.Any, typing.Any] = ("dict", {0: (None, None)}) + response = client.projects.stats.update_stats(id=1) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.projects.stats.update_stats(id=1) + validate_response(async_response, expected_response, expected_types) + + +async def test_user_prediction_agreement(client: LabelStudio, async_client: AsyncLabelStudio) -> None: + expected_response: typing.Any = {"average_prediction_agreement_per_user": 1.1} + expected_types: typing.Any = {"average_prediction_agreement_per_user": None} + response = client.projects.stats.user_prediction_agreement(id=1, user_pk=1) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.projects.stats.user_prediction_agreement(id=1, user_pk=1) + validate_response(async_response, expected_response, expected_types) + + +async def test_user_review_score(client: LabelStudio, async_client: AsyncLabelStudio) -> None: + expected_response: typing.Any = {"performance_score": 1.1, "review_score": 1.1} + expected_types: typing.Any = {"performance_score": None, "review_score": None} + response = client.projects.stats.user_review_score(id=1, user_pk=1) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.projects.stats.user_review_score(id=1, user_pk=1) + validate_response(async_response, expected_response, expected_types) + + +async def test_user_ground_truth_agreement(client: LabelStudio, async_client: AsyncLabelStudio) -> None: + expected_response: typing.Any = {"agreement": 1.1} + expected_types: typing.Any = {"agreement": None} + response = client.projects.stats.user_ground_truth_agreement(id=1, user_pk=1) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.projects.stats.user_ground_truth_agreement(id=1, user_pk=1) + validate_response(async_response, expected_response, expected_types) From 444b0274d48606c9039d841c532ea407b5176e74 Mon Sep 17 00:00:00 2001 From: fern-api <115122769+fern-api[bot]@users.noreply.github.com> Date: Fri, 19 Sep 2025 20:15:13 +0000 Subject: [PATCH 3/6] SDK regeneration From 45ea7f9c071cbe0b6eb89f44c385856c0bf6cbe5 Mon Sep 17 00:00:00 2001 From: fern-api <115122769+fern-api[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 21:28:02 +0000 Subject: [PATCH 4/6] SDK regeneration --- .mock/definition/blueprints.yml | 4 +- .mock/openapi/openapi.yaml | 4 +- pyproject.toml | 2 +- reference.md | 173 ------------- src/label_studio_sdk/__init__.py | 4 - src/label_studio_sdk/base_client.py | 4 - src/label_studio_sdk/blueprints/__init__.py | 2 - src/label_studio_sdk/blueprints/client.py | 272 -------------------- src/label_studio_sdk/types/__init__.py | 2 - src/label_studio_sdk/types/blueprint.py | 41 --- tests/test_blueprints.py | 51 ---- 11 files changed, 5 insertions(+), 554 deletions(-) delete mode 100644 src/label_studio_sdk/blueprints/__init__.py delete mode 100644 src/label_studio_sdk/blueprints/client.py delete mode 100644 src/label_studio_sdk/types/blueprint.py delete mode 100644 tests/test_blueprints.py diff --git a/.mock/definition/blueprints.yml b/.mock/definition/blueprints.yml index 99ddd0d56..3fca5ba5f 100644 --- a/.mock/definition/blueprints.yml +++ b/.mock/definition/blueprints.yml @@ -49,7 +49,7 @@ service: title: title updated_at: '2024-01-15T09:30:00Z' audiences: - - public + - internal delete: path: /api/blueprints/{id}/ method: DELETE @@ -64,7 +64,7 @@ service: - path-parameters: id: id audiences: - - public + - internal api_blueprints_create_project_retrieve: path: /api/blueprints/{share_id}/create-project method: GET diff --git a/.mock/openapi/openapi.yaml b/.mock/openapi/openapi.yaml index ec48b1bda..8aca78439 100644 --- a/.mock/openapi/openapi.yaml +++ b/.mock/openapi/openapi.yaml @@ -876,7 +876,7 @@ paths: tags: - Blueprints x-fern-audiences: - - public + - internal x-fern-sdk-group-name: blueprints x-fern-sdk-method-name: create /api/blueprints/{id}/: @@ -898,7 +898,7 @@ paths: tags: - Blueprints x-fern-audiences: - - public + - internal x-fern-sdk-group-name: blueprints x-fern-sdk-method-name: delete /api/blueprints/{share_id}/create-project: diff --git a/pyproject.toml b/pyproject.toml index 06b82fdcf..faa6b2026 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ name = "label-studio-sdk" [tool.poetry] name = "label-studio-sdk" -version = "2.0.9.dev" +version = "2.0.9" description = "" readme = "README.md" authors = [] diff --git a/reference.md b/reference.md index 53cf6dd37..b03f8de19 100644 --- a/reference.md +++ b/reference.md @@ -1680,179 +1680,6 @@ client.billing.info()
- - -
- -## Blueprints -
client.blueprints.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a new blueprint -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.blueprints.create( - project=1, -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**project:** `int` - -
-
- -
-
- -**created_by:** `typing.Optional[int]` - -
-
- -
-
- -**description:** `typing.Optional[str]` — Project description - -
-
- -
-
- -**label_config:** `typing.Optional[str]` — Labeling configuration in XML format - -
-
- -
-
- -**title:** `typing.Optional[str]` — Blueprint name. Must be between 3 and 50 characters long. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.blueprints.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a blueprint by ID -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from label_studio_sdk import LabelStudio - -client = LabelStudio( - api_key="YOUR_API_KEY", -) -client.blueprints.delete( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**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 4fe4748d8..d2fc5ef39 100644 --- a/src/label_studio_sdk/__init__.py +++ b/src/label_studio_sdk/__init__.py @@ -35,7 +35,6 @@ BillingFlags, BillingInfoResponse, BlankEnum, - Blueprint, BlueprintList, BudgetResetPeriodEnum, ChildFilter, @@ -240,7 +239,6 @@ annotation_reviews, annotations, billing, - blueprints, comments, export_storage, files, @@ -394,7 +392,6 @@ "BillingFlags", "BillingInfoResponse", "BlankEnum", - "Blueprint", "BlueprintList", "BudgetResetPeriodEnum", "ChildFilter", @@ -649,7 +646,6 @@ "annotation_reviews", "annotations", "billing", - "blueprints", "comments", "export_storage", "files", diff --git a/src/label_studio_sdk/base_client.py b/src/label_studio_sdk/base_client.py index 97c219e18..a3ae28d4b 100644 --- a/src/label_studio_sdk/base_client.py +++ b/src/label_studio_sdk/base_client.py @@ -11,7 +11,6 @@ from .annotation_reviews.client import AnnotationReviewsClient from .annotations.client import AnnotationsClient from .billing.client import BillingClient -from .blueprints.client import BlueprintsClient from .comments.client import CommentsClient from .users.client import UsersClient from .actions.client import ActionsClient @@ -40,7 +39,6 @@ from .annotation_reviews.client import AsyncAnnotationReviewsClient from .annotations.client import AsyncAnnotationsClient from .billing.client import AsyncBillingClient -from .blueprints.client import AsyncBlueprintsClient from .comments.client import AsyncCommentsClient from .users.client import AsyncUsersClient from .actions.client import AsyncActionsClient @@ -132,7 +130,6 @@ def __init__( self.annotation_reviews = AnnotationReviewsClient(client_wrapper=self._client_wrapper) self.annotations = AnnotationsClient(client_wrapper=self._client_wrapper) self.billing = BillingClient(client_wrapper=self._client_wrapper) - self.blueprints = BlueprintsClient(client_wrapper=self._client_wrapper) self.comments = CommentsClient(client_wrapper=self._client_wrapper) self.users = UsersClient(client_wrapper=self._client_wrapper) self.actions = ActionsClient(client_wrapper=self._client_wrapper) @@ -224,7 +221,6 @@ def __init__( self.annotation_reviews = AsyncAnnotationReviewsClient(client_wrapper=self._client_wrapper) self.annotations = AsyncAnnotationsClient(client_wrapper=self._client_wrapper) self.billing = AsyncBillingClient(client_wrapper=self._client_wrapper) - self.blueprints = AsyncBlueprintsClient(client_wrapper=self._client_wrapper) self.comments = AsyncCommentsClient(client_wrapper=self._client_wrapper) self.users = AsyncUsersClient(client_wrapper=self._client_wrapper) self.actions = AsyncActionsClient(client_wrapper=self._client_wrapper) diff --git a/src/label_studio_sdk/blueprints/__init__.py b/src/label_studio_sdk/blueprints/__init__.py deleted file mode 100644 index f3ea2659b..000000000 --- a/src/label_studio_sdk/blueprints/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - diff --git a/src/label_studio_sdk/blueprints/client.py b/src/label_studio_sdk/blueprints/client.py deleted file mode 100644 index 20f1d8b17..000000000 --- a/src/label_studio_sdk/blueprints/client.py +++ /dev/null @@ -1,272 +0,0 @@ -# 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.blueprint import Blueprint -from ..core.unchecked_base_model import construct_type -from json.decoder import JSONDecodeError -from ..core.api_error import ApiError -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 BlueprintsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def create( - self, - *, - project: int, - created_by: typing.Optional[int] = OMIT, - description: typing.Optional[str] = OMIT, - label_config: typing.Optional[str] = OMIT, - title: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> Blueprint: - """ - Create a new blueprint - - Parameters - ---------- - project : int - - created_by : typing.Optional[int] - - description : typing.Optional[str] - Project description - - label_config : typing.Optional[str] - Labeling configuration in XML format - - title : typing.Optional[str] - Blueprint name. Must be between 3 and 50 characters long. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Blueprint - - - Examples - -------- - from label_studio_sdk import LabelStudio - - client = LabelStudio( - api_key="YOUR_API_KEY", - ) - client.blueprints.create( - project=1, - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/blueprints/", - method="POST", - json={ - "created_by": created_by, - "description": description, - "label_config": label_config, - "project": project, - "title": title, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - Blueprint, - construct_type( - type_=Blueprint, # 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 delete(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: - """ - Delete a blueprint by ID - - Parameters - ---------- - id : str - - 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.blueprints.delete( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/blueprints/{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) - - -class AsyncBlueprintsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def create( - self, - *, - project: int, - created_by: typing.Optional[int] = OMIT, - description: typing.Optional[str] = OMIT, - label_config: typing.Optional[str] = OMIT, - title: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> Blueprint: - """ - Create a new blueprint - - Parameters - ---------- - project : int - - created_by : typing.Optional[int] - - description : typing.Optional[str] - Project description - - label_config : typing.Optional[str] - Labeling configuration in XML format - - title : typing.Optional[str] - Blueprint name. Must be between 3 and 50 characters long. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Blueprint - - - Examples - -------- - import asyncio - - from label_studio_sdk import AsyncLabelStudio - - client = AsyncLabelStudio( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.blueprints.create( - project=1, - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/blueprints/", - method="POST", - json={ - "created_by": created_by, - "description": description, - "label_config": label_config, - "project": project, - "title": title, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - Blueprint, - construct_type( - type_=Blueprint, # 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 delete(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: - """ - Delete a blueprint by ID - - Parameters - ---------- - id : str - - 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.blueprints.delete( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/blueprints/{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) diff --git a/src/label_studio_sdk/types/__init__.py b/src/label_studio_sdk/types/__init__.py index f539e9f73..3ed6a7578 100644 --- a/src/label_studio_sdk/types/__init__.py +++ b/src/label_studio_sdk/types/__init__.py @@ -36,7 +36,6 @@ from .billing_flags import BillingFlags from .billing_info_response import BillingInfoResponse from .blank_enum import BlankEnum -from .blueprint import Blueprint from .blueprint_list import BlueprintList from .budget_reset_period_enum import BudgetResetPeriodEnum from .child_filter import ChildFilter @@ -261,7 +260,6 @@ "BillingFlags", "BillingInfoResponse", "BlankEnum", - "Blueprint", "BlueprintList", "BudgetResetPeriodEnum", "ChildFilter", diff --git a/src/label_studio_sdk/types/blueprint.py b/src/label_studio_sdk/types/blueprint.py deleted file mode 100644 index 1ab2a859d..000000000 --- a/src/label_studio_sdk/types/blueprint.py +++ /dev/null @@ -1,41 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ..core.unchecked_base_model import UncheckedBaseModel -import datetime as dt -import typing -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2 - - -class Blueprint(UncheckedBaseModel): - created_at: dt.datetime - created_by: typing.Optional[int] = None - description: typing.Optional[str] = pydantic.Field(default=None) - """ - Project description - """ - - id: int - label_config: typing.Optional[str] = pydantic.Field(default=None) - """ - Labeling configuration in XML format - """ - - project: int - share_id: str - short_url: str - title: typing.Optional[str] = pydantic.Field(default=None) - """ - Blueprint name. Must be between 3 and 50 characters long. - """ - - updated_at: dt.datetime - - 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/tests/test_blueprints.py b/tests/test_blueprints.py deleted file mode 100644 index 761d4b5d8..000000000 --- a/tests/test_blueprints.py +++ /dev/null @@ -1,51 +0,0 @@ -# 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_create(client: LabelStudio, async_client: AsyncLabelStudio) -> None: - expected_response: typing.Any = { - "created_at": "2024-01-15T09:30:00Z", - "created_by": 1, - "description": "description", - "id": 1, - "label_config": "label_config", - "project": 1, - "share_id": "share_id", - "short_url": "short_url", - "title": "title", - "updated_at": "2024-01-15T09:30:00Z", - } - expected_types: typing.Any = { - "created_at": "datetime", - "created_by": "integer", - "description": None, - "id": "integer", - "label_config": None, - "project": "integer", - "share_id": None, - "short_url": None, - "title": None, - "updated_at": "datetime", - } - response = client.blueprints.create(project=1) - validate_response(response, expected_response, expected_types) - - async_response = await async_client.blueprints.create(project=1) - validate_response(async_response, expected_response, expected_types) - - -async def test_delete(client: LabelStudio, async_client: AsyncLabelStudio) -> None: - # Type ignore to avoid mypy complaining about the function not being meant to return a value - assert ( - client.blueprints.delete(id="id") # type: ignore[func-returns-value] - is None - ) - - assert ( - await async_client.blueprints.delete(id="id") # type: ignore[func-returns-value] - is None - ) From 1c4e7c8c8fdc958e95e3ac861d6bb61da14ff59d Mon Sep 17 00:00:00 2001 From: fern-api <115122769+fern-api[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 22:17:59 +0000 Subject: [PATCH 5/6] SDK regeneration From 0976d1ae89b0c0ebfa5a845facf948277c7190bf Mon Sep 17 00:00:00 2001 From: fern-api <115122769+fern-api[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 22:20:41 +0000 Subject: [PATCH 6/6] SDK regeneration --- .mock/definition/__package__.yml | 6 - .mock/definition/blueprints.yml | 4 +- .mock/definition/importStorage/azureSpi.yml | 8 - .mock/definition/prompts/versions.yml | 7 + .mock/openapi/openapi.yaml | 22 +- reference.md | 208 ++++++++++++-- src/label_studio_sdk/__init__.py | 4 + src/label_studio_sdk/base_client.py | 4 + src/label_studio_sdk/blueprints/__init__.py | 2 + src/label_studio_sdk/blueprints/client.py | 272 ++++++++++++++++++ .../import_storage/azure_spi/client.py | 30 -- .../prompts/versions/client.py | 20 +- src/label_studio_sdk/types/__init__.py | 2 + .../azure_service_principal_import_storage.py | 5 - ...ervice_principal_import_storage_request.py | 5 - src/label_studio_sdk/types/blueprint.py | 41 +++ tests/import_storage/test_azure_spi.py | 10 - tests/prompts/test_versions.py | 4 +- tests/test_blueprints.py | 51 ++++ 19 files changed, 594 insertions(+), 111 deletions(-) create mode 100644 src/label_studio_sdk/blueprints/__init__.py create mode 100644 src/label_studio_sdk/blueprints/client.py create mode 100644 src/label_studio_sdk/types/blueprint.py create mode 100644 tests/test_blueprints.py diff --git a/.mock/definition/__package__.yml b/.mock/definition/__package__.yml index 4bad0c059..23b5c85fd 100644 --- a/.mock/definition/__package__.yml +++ b/.mock/definition/__package__.yml @@ -1249,9 +1249,6 @@ types: project: type: integer docs: A unique integer value identifying this project. - recursive_scan: - type: optional - docs: Perform recursive scan regex_filter: type: optional docs: Cloud storage regex for filtering objects @@ -1328,9 +1325,6 @@ types: project: type: integer docs: A unique integer value identifying this project. - recursive_scan: - type: optional - docs: Perform recursive scan regex_filter: type: optional docs: Cloud storage regex for filtering objects diff --git a/.mock/definition/blueprints.yml b/.mock/definition/blueprints.yml index 3fca5ba5f..99ddd0d56 100644 --- a/.mock/definition/blueprints.yml +++ b/.mock/definition/blueprints.yml @@ -49,7 +49,7 @@ service: title: title updated_at: '2024-01-15T09:30:00Z' audiences: - - internal + - public delete: path: /api/blueprints/{id}/ method: DELETE @@ -64,7 +64,7 @@ service: - path-parameters: id: id audiences: - - internal + - public api_blueprints_create_project_retrieve: path: /api/blueprints/{share_id}/create-project method: GET diff --git a/.mock/definition/importStorage/azureSpi.yml b/.mock/definition/importStorage/azureSpi.yml index 7ae699522..f88cad861 100644 --- a/.mock/definition/importStorage/azureSpi.yml +++ b/.mock/definition/importStorage/azureSpi.yml @@ -45,7 +45,6 @@ service: presign: true presign_ttl: 1 project: 1 - recursive_scan: true regex_filter: regex_filter status: initialized synchronizable: true @@ -92,7 +91,6 @@ service: presign: true presign_ttl: 1 project: 1 - recursive_scan: true regex_filter: regex_filter status: initialized synchronizable: true @@ -158,7 +156,6 @@ service: presign: true presign_ttl: 1 project: 1 - recursive_scan: true regex_filter: regex_filter status: initialized synchronizable: true @@ -248,9 +245,6 @@ service: project: type: optional docs: A unique integer value identifying this project. - recursive_scan: - type: optional - docs: Perform recursive scan regex_filter: type: optional docs: Cloud storage regex for filtering objects @@ -301,7 +295,6 @@ service: presign: true presign_ttl: 1 project: 1 - recursive_scan: true regex_filter: regex_filter status: initialized synchronizable: true @@ -349,7 +342,6 @@ service: presign: true presign_ttl: 1 project: 1 - recursive_scan: true regex_filter: regex_filter status: initialized synchronizable: true diff --git a/.mock/definition/prompts/versions.yml b/.mock/definition/prompts/versions.yml index 95119f0fa..da6eafc7e 100644 --- a/.mock/definition/prompts/versions.yml +++ b/.mock/definition/prompts/versions.yml @@ -33,12 +33,19 @@ service: ordering: type: optional docs: Which field to use when ordering the results. + prompt_id: + type: integer + docs: >- + A unique integer value identifying the model ID to list versions + for. response: docs: '' type: list examples: - path-parameters: prompt_id: 1 + query-parameters: + prompt_id: 1 response: body: - created_at: '2024-01-15T09:30:00Z' diff --git a/.mock/openapi/openapi.yaml b/.mock/openapi/openapi.yaml index 8aca78439..5edf09d63 100644 --- a/.mock/openapi/openapi.yaml +++ b/.mock/openapi/openapi.yaml @@ -876,7 +876,7 @@ paths: tags: - Blueprints x-fern-audiences: - - internal + - public x-fern-sdk-group-name: blueprints x-fern-sdk-method-name: create /api/blueprints/{id}/: @@ -898,7 +898,7 @@ paths: tags: - Blueprints x-fern-audiences: - - internal + - public x-fern-sdk-group-name: blueprints x-fern-sdk-method-name: delete /api/blueprints/{share_id}/create-project: @@ -10058,6 +10058,12 @@ paths: required: true schema: type: integer + - description: A unique integer value identifying the model ID to list versions for. + in: query + name: prompt_id + required: true + schema: + type: integer responses: '200': content: @@ -18885,10 +18891,6 @@ components: project: description: A unique integer value identifying this project. type: integer - recursive_scan: - description: Perform recursive scan - nullable: true - type: boolean regex_filter: description: Cloud storage regex for filtering objects nullable: true @@ -18984,10 +18986,6 @@ components: project: description: A unique integer value identifying this project. type: integer - recursive_scan: - description: Perform recursive scan - nullable: true - type: boolean regex_filter: description: Cloud storage regex for filtering objects nullable: true @@ -25819,10 +25817,6 @@ components: project: description: A unique integer value identifying this project. type: integer - recursive_scan: - description: Perform recursive scan - nullable: true - type: boolean regex_filter: description: Cloud storage regex for filtering objects nullable: true diff --git a/reference.md b/reference.md index b03f8de19..3ef779234 100644 --- a/reference.md +++ b/reference.md @@ -1680,6 +1680,179 @@ client.billing.info() + + +
+ +## Blueprints +
client.blueprints.create(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Create a new blueprint +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.blueprints.create( + project=1, +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project:** `int` + +
+
+ +
+
+ +**created_by:** `typing.Optional[int]` + +
+
+ +
+
+ +**description:** `typing.Optional[str]` — Project description + +
+
+ +
+
+ +**label_config:** `typing.Optional[str]` — Labeling configuration in XML format + +
+
+ +
+
+ +**title:** `typing.Optional[str]` — Blueprint name. Must be between 3 and 50 characters long. + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.blueprints.delete(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Delete a blueprint by ID +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from label_studio_sdk import LabelStudio + +client = LabelStudio( + api_key="YOUR_API_KEY", +) +client.blueprints.delete( + id="id", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**id:** `str` + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ +
@@ -19899,14 +20072,6 @@ client.import_storage.azure_spi.create(
-**recursive_scan:** `typing.Optional[bool]` — Perform recursive scan - -
-
- -
-
- **regex_filter:** `typing.Optional[str]` — Cloud storage regex for filtering objects
@@ -20137,14 +20302,6 @@ client.import_storage.azure_spi.validate(
-**recursive_scan:** `typing.Optional[bool]` — Perform recursive scan - -
-
- -
-
- **regex_filter:** `typing.Optional[str]` — Cloud storage regex for filtering objects
@@ -20523,14 +20680,6 @@ client.import_storage.azure_spi.update(
-**recursive_scan:** `typing.Optional[bool]` — Perform recursive scan - -
-
- -
-
- **regex_filter:** `typing.Optional[str]` — Cloud storage regex for filtering objects
@@ -30398,6 +30547,7 @@ client = LabelStudio( api_key="YOUR_API_KEY", ) client.prompts.versions.list( + prompt_id_=1, prompt_id=1, ) @@ -30415,7 +30565,15 @@ client.prompts.versions.list(
-**prompt_id:** `int` +**prompt_id_:** `int` + +
+
+ +
+
+ +**prompt_id:** `int` — A unique integer value identifying the model ID to list versions for.
diff --git a/src/label_studio_sdk/__init__.py b/src/label_studio_sdk/__init__.py index d2fc5ef39..4fe4748d8 100644 --- a/src/label_studio_sdk/__init__.py +++ b/src/label_studio_sdk/__init__.py @@ -35,6 +35,7 @@ BillingFlags, BillingInfoResponse, BlankEnum, + Blueprint, BlueprintList, BudgetResetPeriodEnum, ChildFilter, @@ -239,6 +240,7 @@ annotation_reviews, annotations, billing, + blueprints, comments, export_storage, files, @@ -392,6 +394,7 @@ "BillingFlags", "BillingInfoResponse", "BlankEnum", + "Blueprint", "BlueprintList", "BudgetResetPeriodEnum", "ChildFilter", @@ -646,6 +649,7 @@ "annotation_reviews", "annotations", "billing", + "blueprints", "comments", "export_storage", "files", diff --git a/src/label_studio_sdk/base_client.py b/src/label_studio_sdk/base_client.py index a3ae28d4b..97c219e18 100644 --- a/src/label_studio_sdk/base_client.py +++ b/src/label_studio_sdk/base_client.py @@ -11,6 +11,7 @@ from .annotation_reviews.client import AnnotationReviewsClient from .annotations.client import AnnotationsClient from .billing.client import BillingClient +from .blueprints.client import BlueprintsClient from .comments.client import CommentsClient from .users.client import UsersClient from .actions.client import ActionsClient @@ -39,6 +40,7 @@ from .annotation_reviews.client import AsyncAnnotationReviewsClient from .annotations.client import AsyncAnnotationsClient from .billing.client import AsyncBillingClient +from .blueprints.client import AsyncBlueprintsClient from .comments.client import AsyncCommentsClient from .users.client import AsyncUsersClient from .actions.client import AsyncActionsClient @@ -130,6 +132,7 @@ def __init__( self.annotation_reviews = AnnotationReviewsClient(client_wrapper=self._client_wrapper) self.annotations = AnnotationsClient(client_wrapper=self._client_wrapper) self.billing = BillingClient(client_wrapper=self._client_wrapper) + self.blueprints = BlueprintsClient(client_wrapper=self._client_wrapper) self.comments = CommentsClient(client_wrapper=self._client_wrapper) self.users = UsersClient(client_wrapper=self._client_wrapper) self.actions = ActionsClient(client_wrapper=self._client_wrapper) @@ -221,6 +224,7 @@ def __init__( self.annotation_reviews = AsyncAnnotationReviewsClient(client_wrapper=self._client_wrapper) self.annotations = AsyncAnnotationsClient(client_wrapper=self._client_wrapper) self.billing = AsyncBillingClient(client_wrapper=self._client_wrapper) + self.blueprints = AsyncBlueprintsClient(client_wrapper=self._client_wrapper) self.comments = AsyncCommentsClient(client_wrapper=self._client_wrapper) self.users = AsyncUsersClient(client_wrapper=self._client_wrapper) self.actions = AsyncActionsClient(client_wrapper=self._client_wrapper) diff --git a/src/label_studio_sdk/blueprints/__init__.py b/src/label_studio_sdk/blueprints/__init__.py new file mode 100644 index 000000000..f3ea2659b --- /dev/null +++ b/src/label_studio_sdk/blueprints/__init__.py @@ -0,0 +1,2 @@ +# This file was auto-generated by Fern from our API Definition. + diff --git a/src/label_studio_sdk/blueprints/client.py b/src/label_studio_sdk/blueprints/client.py new file mode 100644 index 000000000..20f1d8b17 --- /dev/null +++ b/src/label_studio_sdk/blueprints/client.py @@ -0,0 +1,272 @@ +# 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.blueprint import Blueprint +from ..core.unchecked_base_model import construct_type +from json.decoder import JSONDecodeError +from ..core.api_error import ApiError +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 BlueprintsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def create( + self, + *, + project: int, + created_by: typing.Optional[int] = OMIT, + description: typing.Optional[str] = OMIT, + label_config: typing.Optional[str] = OMIT, + title: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Blueprint: + """ + Create a new blueprint + + Parameters + ---------- + project : int + + created_by : typing.Optional[int] + + description : typing.Optional[str] + Project description + + label_config : typing.Optional[str] + Labeling configuration in XML format + + title : typing.Optional[str] + Blueprint name. Must be between 3 and 50 characters long. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Blueprint + + + Examples + -------- + from label_studio_sdk import LabelStudio + + client = LabelStudio( + api_key="YOUR_API_KEY", + ) + client.blueprints.create( + project=1, + ) + """ + _response = self._client_wrapper.httpx_client.request( + "api/blueprints/", + method="POST", + json={ + "created_by": created_by, + "description": description, + "label_config": label_config, + "project": project, + "title": title, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Blueprint, + construct_type( + type_=Blueprint, # 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 delete(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: + """ + Delete a blueprint by ID + + Parameters + ---------- + id : str + + 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.blueprints.delete( + id="id", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"api/blueprints/{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) + + +class AsyncBlueprintsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def create( + self, + *, + project: int, + created_by: typing.Optional[int] = OMIT, + description: typing.Optional[str] = OMIT, + label_config: typing.Optional[str] = OMIT, + title: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Blueprint: + """ + Create a new blueprint + + Parameters + ---------- + project : int + + created_by : typing.Optional[int] + + description : typing.Optional[str] + Project description + + label_config : typing.Optional[str] + Labeling configuration in XML format + + title : typing.Optional[str] + Blueprint name. Must be between 3 and 50 characters long. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Blueprint + + + Examples + -------- + import asyncio + + from label_studio_sdk import AsyncLabelStudio + + client = AsyncLabelStudio( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.blueprints.create( + project=1, + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + "api/blueprints/", + method="POST", + json={ + "created_by": created_by, + "description": description, + "label_config": label_config, + "project": project, + "title": title, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Blueprint, + construct_type( + type_=Blueprint, # 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 delete(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: + """ + Delete a blueprint by ID + + Parameters + ---------- + id : str + + 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.blueprints.delete( + id="id", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/blueprints/{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) diff --git a/src/label_studio_sdk/import_storage/azure_spi/client.py b/src/label_studio_sdk/import_storage/azure_spi/client.py index e941444dc..2dcc6a22d 100644 --- a/src/label_studio_sdk/import_storage/azure_spi/client.py +++ b/src/label_studio_sdk/import_storage/azure_spi/client.py @@ -94,7 +94,6 @@ def create( prefix: typing.Optional[str] = OMIT, presign: typing.Optional[bool] = OMIT, presign_ttl: typing.Optional[int] = OMIT, - recursive_scan: typing.Optional[bool] = OMIT, regex_filter: typing.Optional[str] = OMIT, status: typing.Optional[StatusC5AEnum] = OMIT, synchronizable: typing.Optional[bool] = OMIT, @@ -147,9 +146,6 @@ def create( presign_ttl : typing.Optional[int] Presigned URLs TTL (in minutes) - recursive_scan : typing.Optional[bool] - Perform recursive scan - regex_filter : typing.Optional[str] Cloud storage regex for filtering objects @@ -208,7 +204,6 @@ def create( "presign": presign, "presign_ttl": presign_ttl, "project": project, - "recursive_scan": recursive_scan, "regex_filter": regex_filter, "status": status, "synchronizable": synchronizable, @@ -251,7 +246,6 @@ def validate( prefix: typing.Optional[str] = OMIT, presign: typing.Optional[bool] = OMIT, presign_ttl: typing.Optional[int] = OMIT, - recursive_scan: typing.Optional[bool] = OMIT, regex_filter: typing.Optional[str] = OMIT, status: typing.Optional[StatusC5AEnum] = OMIT, synchronizable: typing.Optional[bool] = OMIT, @@ -304,9 +298,6 @@ def validate( presign_ttl : typing.Optional[int] Presigned URLs TTL (in minutes) - recursive_scan : typing.Optional[bool] - Perform recursive scan - regex_filter : typing.Optional[str] Cloud storage regex for filtering objects @@ -364,7 +355,6 @@ def validate( "presign": presign, "presign_ttl": presign_ttl, "project": project, - "recursive_scan": recursive_scan, "regex_filter": regex_filter, "status": status, "synchronizable": synchronizable, @@ -489,7 +479,6 @@ def update( presign: typing.Optional[bool] = OMIT, presign_ttl: typing.Optional[int] = OMIT, project: typing.Optional[int] = OMIT, - recursive_scan: typing.Optional[bool] = OMIT, regex_filter: typing.Optional[str] = OMIT, status: typing.Optional[StatusC5AEnum] = OMIT, synchronizable: typing.Optional[bool] = OMIT, @@ -544,9 +533,6 @@ def update( project : typing.Optional[int] A unique integer value identifying this project. - recursive_scan : typing.Optional[bool] - Perform recursive scan - regex_filter : typing.Optional[str] Cloud storage regex for filtering objects @@ -605,7 +591,6 @@ def update( "presign": presign, "presign_ttl": presign_ttl, "project": project, - "recursive_scan": recursive_scan, "regex_filter": regex_filter, "status": status, "synchronizable": synchronizable, @@ -770,7 +755,6 @@ async def create( prefix: typing.Optional[str] = OMIT, presign: typing.Optional[bool] = OMIT, presign_ttl: typing.Optional[int] = OMIT, - recursive_scan: typing.Optional[bool] = OMIT, regex_filter: typing.Optional[str] = OMIT, status: typing.Optional[StatusC5AEnum] = OMIT, synchronizable: typing.Optional[bool] = OMIT, @@ -823,9 +807,6 @@ async def create( presign_ttl : typing.Optional[int] Presigned URLs TTL (in minutes) - recursive_scan : typing.Optional[bool] - Perform recursive scan - regex_filter : typing.Optional[str] Cloud storage regex for filtering objects @@ -892,7 +873,6 @@ async def main() -> None: "presign": presign, "presign_ttl": presign_ttl, "project": project, - "recursive_scan": recursive_scan, "regex_filter": regex_filter, "status": status, "synchronizable": synchronizable, @@ -935,7 +915,6 @@ async def validate( prefix: typing.Optional[str] = OMIT, presign: typing.Optional[bool] = OMIT, presign_ttl: typing.Optional[int] = OMIT, - recursive_scan: typing.Optional[bool] = OMIT, regex_filter: typing.Optional[str] = OMIT, status: typing.Optional[StatusC5AEnum] = OMIT, synchronizable: typing.Optional[bool] = OMIT, @@ -988,9 +967,6 @@ async def validate( presign_ttl : typing.Optional[int] Presigned URLs TTL (in minutes) - recursive_scan : typing.Optional[bool] - Perform recursive scan - regex_filter : typing.Optional[str] Cloud storage regex for filtering objects @@ -1056,7 +1032,6 @@ async def main() -> None: "presign": presign, "presign_ttl": presign_ttl, "project": project, - "recursive_scan": recursive_scan, "regex_filter": regex_filter, "status": status, "synchronizable": synchronizable, @@ -1197,7 +1172,6 @@ async def update( presign: typing.Optional[bool] = OMIT, presign_ttl: typing.Optional[int] = OMIT, project: typing.Optional[int] = OMIT, - recursive_scan: typing.Optional[bool] = OMIT, regex_filter: typing.Optional[str] = OMIT, status: typing.Optional[StatusC5AEnum] = OMIT, synchronizable: typing.Optional[bool] = OMIT, @@ -1252,9 +1226,6 @@ async def update( project : typing.Optional[int] A unique integer value identifying this project. - recursive_scan : typing.Optional[bool] - Perform recursive scan - regex_filter : typing.Optional[str] Cloud storage regex for filtering objects @@ -1321,7 +1292,6 @@ async def main() -> None: "presign": presign, "presign_ttl": presign_ttl, "project": project, - "recursive_scan": recursive_scan, "regex_filter": regex_filter, "status": status, "synchronizable": synchronizable, diff --git a/src/label_studio_sdk/prompts/versions/client.py b/src/label_studio_sdk/prompts/versions/client.py index 0185ec11a..641b8b08d 100644 --- a/src/label_studio_sdk/prompts/versions/client.py +++ b/src/label_studio_sdk/prompts/versions/client.py @@ -62,8 +62,9 @@ def get_default_version_name(self, id: int, *, request_options: typing.Optional[ def list( self, - prompt_id: int, + prompt_id_: int, *, + prompt_id: int, ordering: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> typing.List[ThirdPartyModelVersion]: @@ -72,7 +73,10 @@ def list( Parameters ---------- + prompt_id_ : int + prompt_id : int + A unique integer value identifying the model ID to list versions for. ordering : typing.Optional[str] Which field to use when ordering the results. @@ -93,14 +97,16 @@ def list( api_key="YOUR_API_KEY", ) client.prompts.versions.list( + prompt_id_=1, prompt_id=1, ) """ _response = self._client_wrapper.httpx_client.request( - f"api/prompts/{jsonable_encoder(prompt_id)}/versions", + f"api/prompts/{jsonable_encoder(prompt_id_)}/versions", method="GET", params={ "ordering": ordering, + "prompt_id": prompt_id, }, request_options=request_options, ) @@ -668,8 +674,9 @@ async def main() -> None: async def list( self, - prompt_id: int, + prompt_id_: int, *, + prompt_id: int, ordering: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> typing.List[ThirdPartyModelVersion]: @@ -678,7 +685,10 @@ async def list( Parameters ---------- + prompt_id_ : int + prompt_id : int + A unique integer value identifying the model ID to list versions for. ordering : typing.Optional[str] Which field to use when ordering the results. @@ -704,6 +714,7 @@ async def list( async def main() -> None: await client.prompts.versions.list( + prompt_id_=1, prompt_id=1, ) @@ -711,10 +722,11 @@ async def main() -> None: asyncio.run(main()) """ _response = await self._client_wrapper.httpx_client.request( - f"api/prompts/{jsonable_encoder(prompt_id)}/versions", + f"api/prompts/{jsonable_encoder(prompt_id_)}/versions", method="GET", params={ "ordering": ordering, + "prompt_id": prompt_id, }, request_options=request_options, ) diff --git a/src/label_studio_sdk/types/__init__.py b/src/label_studio_sdk/types/__init__.py index 3ed6a7578..f539e9f73 100644 --- a/src/label_studio_sdk/types/__init__.py +++ b/src/label_studio_sdk/types/__init__.py @@ -36,6 +36,7 @@ from .billing_flags import BillingFlags from .billing_info_response import BillingInfoResponse from .blank_enum import BlankEnum +from .blueprint import Blueprint from .blueprint_list import BlueprintList from .budget_reset_period_enum import BudgetResetPeriodEnum from .child_filter import ChildFilter @@ -260,6 +261,7 @@ "BillingFlags", "BillingInfoResponse", "BlankEnum", + "Blueprint", "BlueprintList", "BudgetResetPeriodEnum", "ChildFilter", diff --git a/src/label_studio_sdk/types/azure_service_principal_import_storage.py b/src/label_studio_sdk/types/azure_service_principal_import_storage.py index b70c09bc7..72b915bbe 100644 --- a/src/label_studio_sdk/types/azure_service_principal_import_storage.py +++ b/src/label_studio_sdk/types/azure_service_principal_import_storage.py @@ -72,11 +72,6 @@ class AzureServicePrincipalImportStorage(UncheckedBaseModel): A unique integer value identifying this project. """ - recursive_scan: typing.Optional[bool] = pydantic.Field(default=None) - """ - Perform recursive scan - """ - regex_filter: typing.Optional[str] = pydantic.Field(default=None) """ Cloud storage regex for filtering objects diff --git a/src/label_studio_sdk/types/azure_service_principal_import_storage_request.py b/src/label_studio_sdk/types/azure_service_principal_import_storage_request.py index 626970cb6..ddf5ea445 100644 --- a/src/label_studio_sdk/types/azure_service_principal_import_storage_request.py +++ b/src/label_studio_sdk/types/azure_service_principal_import_storage_request.py @@ -66,11 +66,6 @@ class AzureServicePrincipalImportStorageRequest(UncheckedBaseModel): A unique integer value identifying this project. """ - recursive_scan: typing.Optional[bool] = pydantic.Field(default=None) - """ - Perform recursive scan - """ - regex_filter: typing.Optional[str] = pydantic.Field(default=None) """ Cloud storage regex for filtering objects diff --git a/src/label_studio_sdk/types/blueprint.py b/src/label_studio_sdk/types/blueprint.py new file mode 100644 index 000000000..1ab2a859d --- /dev/null +++ b/src/label_studio_sdk/types/blueprint.py @@ -0,0 +1,41 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.unchecked_base_model import UncheckedBaseModel +import datetime as dt +import typing +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class Blueprint(UncheckedBaseModel): + created_at: dt.datetime + created_by: typing.Optional[int] = None + description: typing.Optional[str] = pydantic.Field(default=None) + """ + Project description + """ + + id: int + label_config: typing.Optional[str] = pydantic.Field(default=None) + """ + Labeling configuration in XML format + """ + + project: int + share_id: str + short_url: str + title: typing.Optional[str] = pydantic.Field(default=None) + """ + Blueprint name. Must be between 3 and 50 characters long. + """ + + updated_at: dt.datetime + + 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/tests/import_storage/test_azure_spi.py b/tests/import_storage/test_azure_spi.py index 71d9828cd..0a98ba502 100644 --- a/tests/import_storage/test_azure_spi.py +++ b/tests/import_storage/test_azure_spi.py @@ -24,7 +24,6 @@ async def test_list_(client: LabelStudio, async_client: AsyncLabelStudio) -> Non "presign": True, "presign_ttl": 1, "project": 1, - "recursive_scan": True, "regex_filter": "regex_filter", "status": "initialized", "synchronizable": True, @@ -55,7 +54,6 @@ async def test_list_(client: LabelStudio, async_client: AsyncLabelStudio) -> Non "presign": None, "presign_ttl": "integer", "project": "integer", - "recursive_scan": None, "regex_filter": None, "status": None, "synchronizable": None, @@ -92,7 +90,6 @@ async def test_create(client: LabelStudio, async_client: AsyncLabelStudio) -> No "presign": True, "presign_ttl": 1, "project": 1, - "recursive_scan": True, "regex_filter": "regex_filter", "status": "initialized", "synchronizable": True, @@ -119,7 +116,6 @@ async def test_create(client: LabelStudio, async_client: AsyncLabelStudio) -> No "presign": None, "presign_ttl": "integer", "project": "integer", - "recursive_scan": None, "regex_filter": None, "status": None, "synchronizable": None, @@ -167,7 +163,6 @@ async def test_get(client: LabelStudio, async_client: AsyncLabelStudio) -> None: "presign": True, "presign_ttl": 1, "project": 1, - "recursive_scan": True, "regex_filter": "regex_filter", "status": "initialized", "synchronizable": True, @@ -194,7 +189,6 @@ async def test_get(client: LabelStudio, async_client: AsyncLabelStudio) -> None: "presign": None, "presign_ttl": "integer", "project": "integer", - "recursive_scan": None, "regex_filter": None, "status": None, "synchronizable": None, @@ -242,7 +236,6 @@ async def test_update(client: LabelStudio, async_client: AsyncLabelStudio) -> No "presign": True, "presign_ttl": 1, "project": 1, - "recursive_scan": True, "regex_filter": "regex_filter", "status": "initialized", "synchronizable": True, @@ -269,7 +262,6 @@ async def test_update(client: LabelStudio, async_client: AsyncLabelStudio) -> No "presign": None, "presign_ttl": "integer", "project": "integer", - "recursive_scan": None, "regex_filter": None, "status": None, "synchronizable": None, @@ -304,7 +296,6 @@ async def test_sync(client: LabelStudio, async_client: AsyncLabelStudio) -> None "presign": True, "presign_ttl": 1, "project": 1, - "recursive_scan": True, "regex_filter": "regex_filter", "status": "initialized", "synchronizable": True, @@ -331,7 +322,6 @@ async def test_sync(client: LabelStudio, async_client: AsyncLabelStudio) -> None "presign": None, "presign_ttl": "integer", "project": "integer", - "recursive_scan": None, "regex_filter": None, "status": None, "synchronizable": None, diff --git a/tests/prompts/test_versions.py b/tests/prompts/test_versions.py index b240ce8da..06a4c79a1 100644 --- a/tests/prompts/test_versions.py +++ b/tests/prompts/test_versions.py @@ -61,10 +61,10 @@ async def test_list_(client: LabelStudio, async_client: AsyncLabelStudio) -> Non } }, ) - response = client.prompts.versions.list(prompt_id=1) + response = client.prompts.versions.list(prompt_id_=1, prompt_id=1) validate_response(response, expected_response, expected_types) - async_response = await async_client.prompts.versions.list(prompt_id=1) + async_response = await async_client.prompts.versions.list(prompt_id_=1, prompt_id=1) validate_response(async_response, expected_response, expected_types) diff --git a/tests/test_blueprints.py b/tests/test_blueprints.py new file mode 100644 index 000000000..761d4b5d8 --- /dev/null +++ b/tests/test_blueprints.py @@ -0,0 +1,51 @@ +# 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_create(client: LabelStudio, async_client: AsyncLabelStudio) -> None: + expected_response: typing.Any = { + "created_at": "2024-01-15T09:30:00Z", + "created_by": 1, + "description": "description", + "id": 1, + "label_config": "label_config", + "project": 1, + "share_id": "share_id", + "short_url": "short_url", + "title": "title", + "updated_at": "2024-01-15T09:30:00Z", + } + expected_types: typing.Any = { + "created_at": "datetime", + "created_by": "integer", + "description": None, + "id": "integer", + "label_config": None, + "project": "integer", + "share_id": None, + "short_url": None, + "title": None, + "updated_at": "datetime", + } + response = client.blueprints.create(project=1) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.blueprints.create(project=1) + validate_response(async_response, expected_response, expected_types) + + +async def test_delete(client: LabelStudio, async_client: AsyncLabelStudio) -> None: + # Type ignore to avoid mypy complaining about the function not being meant to return a value + assert ( + client.blueprints.delete(id="id") # type: ignore[func-returns-value] + is None + ) + + assert ( + await async_client.blueprints.delete(id="id") # type: ignore[func-returns-value] + is None + )