From 8ce8c2a80ae828399fd0aaca85f0ca9f68918480 Mon Sep 17 00:00:00 2001 From: Lemi Boyce Date: Tue, 24 Sep 2024 02:03:53 -0400 Subject: [PATCH 1/5] typed method arguments and responses --- README.md | 4 +- data/Motion REST API swagger.json | 1705 +++++++++++++++++++++++++++++ src/motion/client.py | 16 +- src/motion/models/__init__.py | 143 +++ src/motion/resources/base.py | 11 +- src/motion/resources/comment.py | 21 + src/motion/resources/project.py | 26 + src/motion/resources/schedule.py | 7 +- src/motion/resources/task.py | 115 +- src/motion/resources/user.py | 21 +- src/motion/resources/workspace.py | 21 +- 11 files changed, 2053 insertions(+), 37 deletions(-) create mode 100644 data/Motion REST API swagger.json create mode 100644 src/motion/models/__init__.py diff --git a/README.md b/README.md index 325c846..7adbaae 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,6 @@ motion.tasks.delete('task-id') ### Roadmap - [x] Initial implementation -- [ ] Named arguments for all methods +- [x] Named arguments for all methods - [ ] Async support -- [ ] Convert responses to Pydantic models \ No newline at end of file +- [x] Convert responses to Pydantic models \ No newline at end of file diff --git a/data/Motion REST API swagger.json b/data/Motion REST API swagger.json new file mode 100644 index 0000000..3125929 --- /dev/null +++ b/data/Motion REST API swagger.json @@ -0,0 +1,1705 @@ +{ + "openapi": "3.0.0", + "paths": { + "/comments": { + "post": { + "operationId": "CommentsController_postComment", + "summary": "Create Comment", + "description": "## Comment Content Input\n\nWhen posting a comment, the content will be treated as [GitHub Flavored Markdown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax).\n", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommentPost" + } + } + } + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Comment" + } + } + } + } + }, + "tags": [ + "Comments" + ] + }, + "get": { + "operationId": "CommentsController_getComments", + "summary": "List Comments", + "parameters": [ + { + "name": "cursor", + "required": false, + "in": "query", + "description": "Use if a previous request returned a cursor. Will page through results", + "schema": { + "type": "string" + } + }, + { + "name": "taskId", + "required": true, + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListComments" + } + } + } + } + }, + "tags": [ + "Comments" + ] + } + }, + "/projects/{projectId}": { + "get": { + "operationId": "ProjectsController_getSingleProject", + "summary": "Retrieve Project", + "parameters": [ + { + "name": "projectId", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Project" + } + } + } + } + }, + "tags": [ + "Projects" + ] + } + }, + "/projects": { + "get": { + "operationId": "ProjectsController_get", + "summary": "List Projects", + "parameters": [ + { + "name": "cursor", + "required": false, + "in": "query", + "description": "Use if a previous request returned a cursor. Will page through results", + "schema": { + "type": "string" + } + }, + { + "name": "workspaceId", + "required": true, + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListProjects" + } + } + } + } + }, + "tags": [ + "Projects" + ] + }, + "post": { + "operationId": "ProjectsController_post", + "summary": "Create Project", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectPost" + } + } + } + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Project" + } + } + } + } + }, + "tags": [ + "Projects" + ] + } + }, + "/recurring-tasks": { + "post": { + "operationId": "RecurringTasksController_postRecurringTask", + "summary": "Create a Recurring Task", + "description": "## Description Input\n\nWhen passing in a task description, the input will be treated as [GitHub Flavored Markdown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax).\n\n# Defining Frequencies\n\nIn order to give our API all the power that motion has to offer, we allow calls to create recurring tasks in the same way you can through the UI.\n\n## Defining specific days for a frequency\n\n\n\n> ### Note\n>\n> Defining days should always be used along with a specific frequency type as defined below.\n> A array of days should never be used on its own. See examples below.\n\nWhen picking a set of specific week days, we expect it to be defined as an array with a subset of the following values.\n\n- MO - Monday\n- TU - Tuesday\n- WE - Wednesday\n- TH - Thursday\n- FR - Friday\n- SA - Saturday\n- SU - Sunday\n\nExample - `[MO, FR, SU]` would mean Monday, Friday and Sunday.\n\n## Defining a daily frequency\n\n- `daily_every_day`\n- `daily_every_week_day`\n- `daily_specific_days_$DAYS_ARRAY$`\n - Ex: `daily_specific_days_[MO, TU, FR]`\n\n## Defining a weekly frequency\n\n- `weekly_any_day`\n- `weekly_any_week_day`\n- `weekly_specific_days_$DAYS_ARRAY$`\n - Ex: `weekly_specific_days_[MO, TU, FR]`\n\n## Defining a bi-weekly frequency\n\n- `biweekly_first_week_specific_days_$DAYS_ARRAY$`\n - Ex: `biweekly_first_week_specific_days_[MO, TU, FR]`\n- `biweekly_first_week_any_day`\n- `biweekly_first_week_any_week_day`\n- `biweekly_second_week_any_day`\n- `biweekly_second_week_any_week_day`\n\n## Defining a monthly frequency\n\n### Specific Week Day Options\n\nWhen choosing the 1st, 2nd, 3rd, 4th or last day of the week for the month, it takes the form of any of the following where $DAY$ can be substituted for the day code mentioned above.\n\n- `monthly_first_$DAY$`\n- `monthly_second_$DAY$`\n- `monthly_third_$DAY$`\n- `monthly_fourth_$DAY$`\n- `monthly_last_$DAY$`\n\n**Example**\n`monthly_first_MO`\n\n### Specific Day Options\n\nWhen choosing a specific day of the month, for example the 6th, it would be defined with just the number like below.\n\nExamples:\n\n- `monthly_1`\n- `monthly_15`\n- `monthly_31`\n\nIn the case you choose a numeric value for a month that does not have that many days, we will default to the last day of the month.\n\n### Specific Week Options\n\n**Any Day**\n\n- `monthly_any_day_first_week`\n- `monthly_any_day_second_week`\n- `monthly_any_day_third_week`\n- `monthly_any_day_fourth_week`\n- `monthly_any_day_last_week`\n\n**Any Week Day**\n\n- `monthly_any_week_day_first_week`\n- `monthly_any_week_day_second_week`\n- `monthly_any_week_day_third_week`\n- `monthly_any_week_day_fourth_week`\n- `monthly_any_week_day_last_week`\n\n### Other Options\n\n- `monthly_last_day_of_month`\n- `monthly_any_week_day_of_month`\n- `monthly_any_day_of_month`\n\n## Defining a quarterly frequency\n\n### First Days\n\n- `quarterly_first_day`\n- `quarterly_first_week_day`\n- `quarterly_first_$DAY$`\n - Ex. `quarterly_first_MO`\n\n### Last Days\n\n- `quarterly_last_day`\n- `quarterly_last_week_day`\n- `quarterly_last_$DAY$`\n - Ex. `quarterly_last_MO`\n\n### Other Options\n\n- `quarterly_any_day_first_week`\n- `quarterly_any_day_second_week`\n- `quarterly_any_day_last_week`\n- `quarterly_any_day_first_month`\n- `quarterly_any_day_second_month`\n- `quarterly_any_day_third_month`\n", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RecurringTasksPost" + } + } + } + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RecurringTask" + } + } + } + } + }, + "tags": [ + "Recurring Tasks" + ] + }, + "get": { + "operationId": "RecurringTasksController_listRecurringTasks", + "summary": "List Recurring Tasks", + "parameters": [ + { + "name": "cursor", + "required": false, + "in": "query", + "description": "Use if a previous request returned a cursor. Will page through results", + "schema": { + "type": "string" + } + }, + { + "name": "workspaceId", + "required": true, + "in": "query", + "description": "The id of the workspace you want tasks from.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListRecurringTasks" + } + } + } + } + }, + "tags": [ + "Recurring Tasks" + ] + } + }, + "/recurring-tasks/{taskId}": { + "delete": { + "operationId": "RecurringTasksController_deleteTask", + "summary": "Delete a Recurring Task", + "parameters": [ + { + "name": "taskId", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "" + } + }, + "tags": [ + "Recurring Tasks" + ] + } + }, + "/schedules": { + "get": { + "operationId": "SchedulesController_getMySchedules", + "summary": "Get schedules", + "description": "Get a list of schedules for your user", + "parameters": [], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Schedule" + } + } + } + } + } + }, + "tags": [ + "Schedules" + ] + } + }, + "/statuses": { + "get": { + "operationId": "StatusesController_get", + "summary": "List statuses for a workspace", + "parameters": [ + { + "name": "workspaceId", + "required": true, + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Status" + } + } + } + } + } + }, + "tags": [ + "Workspaces" + ] + } + }, + "/tasks/{taskId}": { + "patch": { + "operationId": "TasksController_updateTask", + "summary": "Update a Task", + "parameters": [ + { + "name": "taskId", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskPatch" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Task" + } + } + } + } + }, + "tags": [ + "Tasks" + ] + }, + "get": { + "operationId": "TasksController_getById", + "summary": "Retrieve a Task", + "parameters": [ + { + "name": "taskId", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Task" + } + } + } + } + }, + "tags": [ + "Tasks" + ] + }, + "delete": { + "operationId": "TasksController_deleteTask", + "summary": "Delete a Task", + "parameters": [ + { + "name": "taskId", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "" + } + }, + "tags": [ + "Tasks" + ] + } + }, + "/tasks": { + "post": { + "operationId": "TasksController_post", + "summary": "Create Task", + "description": "## Description Input\n\nWhen passing in a task description, the input will be treated as [GitHub Flavored Markdown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax).\n", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskPost" + } + } + } + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Task" + } + } + } + } + }, + "tags": [ + "Tasks" + ] + }, + "get": { + "operationId": "TasksController_get", + "summary": "List Tasks", + "description": "\n\n> ### Note\n>\n> By default, all tasks that are completed are left out unless\n> specifically filtered for via the status.\n", + "parameters": [ + { + "name": "cursor", + "required": false, + "in": "query", + "description": "Use if a previous request returned a cursor. Will page through results", + "schema": { + "type": "string" + } + }, + { + "name": "label", + "required": false, + "in": "query", + "description": "Limit tasks returned by label on the task", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Limit tasks returned by statuses that exist on tasks, cannot specify this ('status')\nAND includeAllStatuses in the same request", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "includeAllStatuses", + "required": false, + "in": "query", + "description": "Limit tasks returned by statuses that exist on tasks, cannot specify this ('includeAllStatuses')\nAND status in the same request", + "schema": { + "type": "boolean" + } + }, + { + "name": "workspaceId", + "required": false, + "in": "query", + "description": "The id of the workspace you want tasks from. If not provided, will return tasks from all workspaces the user is a member of.", + "schema": { + "type": "string" + } + }, + { + "name": "projectId", + "required": false, + "in": "query", + "description": "Limit tasks returned to a given project", + "schema": { + "type": "string" + } + }, + { + "name": "name", + "required": false, + "in": "query", + "description": "Limit tasks returned to those that contain this string. Case in-sensitive", + "schema": { + "type": "string" + } + }, + { + "name": "assigneeId", + "required": false, + "in": "query", + "description": "Limit tasks returned to a specific assignee", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListTasks" + } + } + } + } + }, + "tags": [ + "Tasks" + ] + } + }, + "/tasks/{taskId}/assignee": { + "delete": { + "operationId": "TasksController_deleteAssignee", + "summary": "Unassign a task", + "description": "\n\n> ### Note\n>\n> For simplicity, use this endpoint to unassign a task\n> instead of the generic update task endpoint.\n> This also prevents bugs and accidental unassignments.\n", + "parameters": [ + { + "name": "taskId", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "" + } + }, + "tags": [ + "Tasks" + ] + } + }, + "/tasks/{taskId}/move": { + "patch": { + "operationId": "TasksController_moveTask", + "summary": "Move Workspace", + "description": "### Notes\n\nWhen moving tasks from one workspace to another,\nthe tasks project, status, and label(s) and assignee will all be reset\n", + "parameters": [ + { + "name": "taskId", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MoveTask" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Task" + } + } + } + } + }, + "tags": [ + "Tasks" + ] + } + }, + "/users": { + "get": { + "operationId": "UsersController_get", + "summary": "List users", + "parameters": [ + { + "name": "cursor", + "required": false, + "in": "query", + "description": "Use if a previous request returned a cursor. Will page through results", + "schema": { + "type": "string" + } + }, + { + "name": "workspaceId", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "teamId", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListUsers" + } + } + } + } + }, + "tags": [ + "Users" + ] + } + }, + "/users/me": { + "get": { + "operationId": "UsersController_getMe", + "summary": "Get My User", + "parameters": [], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + } + }, + "tags": [ + "Users" + ] + } + }, + "/workspaces": { + "get": { + "operationId": "WorkspacesController_get", + "summary": "List workspaces", + "parameters": [ + { + "name": "cursor", + "required": false, + "in": "query", + "description": "Use if a previous request returned a cursor. Will page through results", + "schema": { + "type": "string" + } + }, + { + "name": "ids", + "required": false, + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListWorkspaces" + } + } + } + } + }, + "tags": [ + "Workspaces" + ] + } + } + }, + "info": { + "title": "Motion REST API", + "description": "\n\n> ### Rate Limit Information\n>\n> The Motion API is currently rate limited to 12 requests per minute per user. In the event a user exceeds this rate limit 3 times\n> in a singe 24 hour period, their API access will be disabled and will require that they contact support to have it re-enabled.\n\n\n\n> ### Note on Date Formats\n>\n> All dates that the Motion API works with are in the format of ISO 8601. **Motion will always return dates in UTC.**\n", + "version": "1.0.0", + "contact": {} + }, + "tags": [ + { + "name": "Tasks", + "description": "" + }, + { + "name": "Recurring Tasks", + "description": "" + }, + { + "name": "Comments", + "description": "" + }, + { + "name": "Projects", + "description": "" + }, + { + "name": "Workspaces", + "description": "" + }, + { + "name": "Users", + "description": "" + }, + { + "name": "Schedules", + "description": "" + } + ], + "servers": [ + { + "url": "https://api.usemotion.com/v1" + } + ], + "components": { + "securitySchemes": { + "Motion_API_Key": { + "in": "header", + "name": "X-API-Key", + "type": "apiKey" + } + }, + "schemas": { + "CommentPost": { + "type": "object", + "properties": { + "taskId": { + "type": "string" + }, + "content": { + "type": "string" + } + }, + "required": [ + "taskId", + "content" + ] + }, + "User": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "email": { + "type": "string" + } + }, + "required": [ + "id", + "name" + ] + }, + "Comment": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "taskId": { + "type": "string" + }, + "content": { + "type": "string" + }, + "creator": { + "description": "The user that created this comment", + "allOf": [ + { + "$ref": "#/components/schemas/User" + } + ] + }, + "createdAt": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "taskId", + "content", + "creator", + "createdAt" + ] + }, + "MetaResult": { + "type": "object", + "properties": { + "nextCursor": { + "type": "string", + "description": "Returned if there are more entities to return. Pass back with the cursor param set to continue paging." + }, + "pageSize": { + "type": "number", + "description": "Maximum number of entities delivered per page" + } + }, + "required": [ + "pageSize" + ] + }, + "ListComments": { + "type": "object", + "properties": { + "comments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Comment" + } + }, + "meta": { + "description": "Information about the result. Contains information necessary for pagination.", + "allOf": [ + { + "$ref": "#/components/schemas/MetaResult" + } + ] + } + }, + "required": [ + "comments" + ] + }, + "Status": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "isDefaultStatus": { + "type": "boolean" + }, + "isResolvedStatus": { + "type": "boolean" + } + }, + "required": [ + "name", + "isDefaultStatus", + "isResolvedStatus" + ] + }, + "Project": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "workspaceId": { + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/Status" + } + }, + "required": [ + "id", + "name", + "status" + ] + }, + "ListProjects": { + "type": "object", + "properties": { + "projects": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Project" + } + }, + "meta": { + "description": "Information about the result. Contains information necessary for pagination.", + "allOf": [ + { + "$ref": "#/components/schemas/MetaResult" + } + ] + } + }, + "required": [ + "projects" + ] + }, + "ProjectPost": { + "type": "object", + "properties": { + "dueDate": { + "type": "string", + "description": "ISO 8601 Due date on the task", + "example": "2024-03-12T10:52:55.714-06:00", + "format": "date-time" + }, + "name": { + "type": "string", + "minLength": 1 + }, + "workspaceId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "status": { + "type": "string" + }, + "priority": { + "type": "string", + "default": "MEDIUM", + "enum": [ + "ASAP", + "HIGH", + "MEDIUM", + "LOW" + ] + } + }, + "required": [ + "name", + "workspaceId", + "priority" + ] + }, + "RecurringTasksPost": { + "type": "object", + "properties": { + "frequency": { + "type": "string", + "description": "Frequency in which the task should be scheduled. Please carefully read how to construct above." + }, + "deadlineType": { + "type": "string", + "default": "SOFT", + "enum": [ + "HARD", + "SOFT" + ] + }, + "duration": { + "default": 30, + "description": "A duration can be one of the following... \"REMINDER\", or a integer greater than 0", + "oneOf": [ + { + "enum": [ + "REMINDER" + ], + "type": "string" + }, + { + "minimum": 1, + "type": "number" + } + ] + }, + "startingOn": { + "type": "string", + "default": "2024-03-12T06:00:00.000Z", + "description": "ISO 8601 Date which is trimmed to the start of the day passed", + "example": "2024-03-12", + "format": "date-time" + }, + "idealTime": { + "type": "string" + }, + "schedule": { + "type": "string", + "description": "Schedule the task must adhere to", + "default": "Work Hours" + }, + "name": { + "type": "string", + "description": "Name / title of the task", + "minLength": 1 + }, + "workspaceId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "priority": { + "type": "string", + "default": "MEDIUM", + "enum": [ + "HIGH", + "MEDIUM" + ] + }, + "assigneeId": { + "type": "string", + "description": "The user id the task should be assigned too" + } + }, + "required": [ + "frequency", + "name", + "workspaceId", + "priority", + "assigneeId" + ] + }, + "Label": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "Workspace": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "teamId": { + "type": "string" + }, + "statuses": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Status" + } + }, + "labels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Label" + } + }, + "type": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "statuses", + "labels", + "type" + ] + }, + "RecurringTask": { + "type": "object", + "properties": { + "workspace": { + "$ref": "#/components/schemas/Workspace" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "creator": { + "description": "The user that created this task", + "allOf": [ + { + "$ref": "#/components/schemas/User" + } + ] + }, + "assignee": { + "$ref": "#/components/schemas/User" + }, + "project": { + "$ref": "#/components/schemas/Project" + }, + "status": { + "$ref": "#/components/schemas/Status" + }, + "priority": { + "type": "string", + "enum": [ + "ASAP", + "HIGH", + "MEDIUM", + "LOW" + ] + }, + "labels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Label" + } + } + }, + "required": [ + "workspace", + "id", + "name", + "creator", + "assignee", + "status", + "priority", + "labels" + ] + }, + "ListRecurringTasks": { + "type": "object", + "properties": { + "tasks": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RecurringTask" + } + }, + "meta": { + "description": "Information about the result. Contains information necessary for pagination.", + "allOf": [ + { + "$ref": "#/components/schemas/MetaResult" + } + ] + } + }, + "required": [ + "tasks" + ] + }, + "DailySchedule": { + "type": "object", + "properties": { + "start": { + "type": "string", + "description": "24 hour time format. HH:mm", + "example": "08:30" + }, + "end": { + "type": "string", + "description": "24 hour time format. HH:mm", + "example": "18:00" + } + }, + "required": [ + "start", + "end" + ] + }, + "ScheduleBreakout": { + "type": "object", + "properties": { + "monday": { + "description": "Array could be empty if there is no range for this day", + "type": "array", + "items": { + "$ref": "#/components/schemas/DailySchedule" + } + }, + "tuesday": { + "description": "Array could be empty if there is no range for this day", + "type": "array", + "items": { + "$ref": "#/components/schemas/DailySchedule" + } + }, + "wednesday": { + "description": "Array could be empty if there is no range for this day", + "type": "array", + "items": { + "$ref": "#/components/schemas/DailySchedule" + } + }, + "thursday": { + "description": "Array could be empty if there is no range for this day", + "type": "array", + "items": { + "$ref": "#/components/schemas/DailySchedule" + } + }, + "friday": { + "description": "Array could be empty if there is no range for this day", + "type": "array", + "items": { + "$ref": "#/components/schemas/DailySchedule" + } + }, + "saturday": { + "description": "Array could be empty if there is no range for this day", + "type": "array", + "items": { + "$ref": "#/components/schemas/DailySchedule" + } + }, + "sunday": { + "description": "Array could be empty if there is no range for this day", + "type": "array", + "items": { + "$ref": "#/components/schemas/DailySchedule" + } + } + }, + "required": [ + "monday", + "tuesday", + "wednesday", + "thursday", + "friday", + "saturday", + "sunday" + ] + }, + "Schedule": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "isDefaultTimezone": { + "type": "boolean" + }, + "timezone": { + "type": "string" + }, + "schedule": { + "description": "Schedule broken out by day. It is possible for a day to have more than one start/end time", + "allOf": [ + { + "$ref": "#/components/schemas/ScheduleBreakout" + } + ] + } + }, + "required": [ + "name", + "isDefaultTimezone", + "timezone", + "schedule" + ] + }, + "AutoScheduledInfo": { + "type": "object", + "properties": { + "startDate": { + "type": "string", + "default": "2024-03-12T06:00:00.000Z", + "description": "ISO 8601 Date which is trimmed to the start of the day passed", + "example": "2024-03-12", + "format": "date-time" + }, + "deadlineType": { + "type": "string", + "default": "SOFT", + "enum": [ + "HARD", + "SOFT", + "NONE" + ] + }, + "schedule": { + "type": "string", + "description": "Schedule the task must adhere to. Schedule MUST be 'Work Hours' if scheduling the task for another user.", + "default": "Work Hours" + } + } + }, + "TaskPatch": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "Name / title of the task" + }, + "dueDate": { + "type": "string", + "description": "ISO 8601 Due date on the task. REQUIRED for scheduled tasks", + "example": "2024-03-12T10:52:55.724-06:00", + "format": "date-time" + }, + "assigneeId": { + "type": "string", + "nullable": true, + "description": "The user id the task should be assigned to, setting the value to null will remove the assignee" + }, + "duration": { + "description": "A duration can be one of the following... \"NONE\", \"REMINDER\", or a integer greater than 0", + "oneOf": [ + { + "enum": [ + "NONE", + "REMINDER" + ], + "type": "string" + }, + { + "minimum": 1, + "type": "number" + } + ] + }, + "status": { + "type": "string", + "description": "Defaults to workspace default status." + }, + "autoScheduled": { + "nullable": true, + "description": "Set values to turn auto scheduling on, set value to null if you want to turn auto scheduling off. The status for the task must have auto scheduling enabled.", + "allOf": [ + { + "$ref": "#/components/schemas/AutoScheduledInfo" + } + ] + }, + "projectId": { + "type": "string" + }, + "description": { + "type": "string", + "description": "Input as GitHub Flavored Markdown" + }, + "priority": { + "type": "string", + "enum": [ + "ASAP", + "HIGH", + "MEDIUM", + "LOW" + ] + }, + "labels": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "Task": { + "type": "object", + "properties": { + "duration": { + "default": 30, + "description": "A duration can be one of the following... \"NONE\", \"REMINDER\", or a integer greater than 0", + "oneOf": [ + { + "enum": [ + "NONE", + "REMINDER" + ], + "type": "string" + }, + { + "minimum": 1, + "type": "number" + } + ] + }, + "workspace": { + "$ref": "#/components/schemas/Workspace" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "dueDate": { + "format": "date-time", + "type": "string" + }, + "deadlineType": { + "type": "string", + "default": "SOFT", + "enum": [ + "HARD", + "SOFT", + "NONE" + ] + }, + "parentRecurringTaskId": { + "type": "string" + }, + "completed": { + "type": "boolean" + }, + "creator": { + "description": "The user that created this task", + "allOf": [ + { + "$ref": "#/components/schemas/User" + } + ] + }, + "project": { + "$ref": "#/components/schemas/Project" + }, + "status": { + "$ref": "#/components/schemas/Status" + }, + "priority": { + "type": "string", + "enum": [ + "ASAP", + "HIGH", + "MEDIUM", + "LOW" + ] + }, + "labels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Label" + } + }, + "assignees": { + "type": "array", + "items": { + "$ref": "#/components/schemas/User" + } + }, + "scheduledStart": { + "format": "date-time", + "type": "string", + "description": "The time that motion has scheduled this task to start" + }, + "createdTime": { + "format": "date-time", + "type": "string", + "description": "The time that the task was created" + }, + "scheduledEnd": { + "format": "date-time", + "type": "string", + "description": "The time that motion has scheduled this task to end" + }, + "schedulingIssue": { + "type": "boolean", + "description": "Returns true if Motion was unable to schedule this task. Check Motion directly to address" + } + }, + "required": [ + "workspace", + "id", + "name", + "dueDate", + "deadlineType", + "parentRecurringTaskId", + "completed", + "creator", + "status", + "priority", + "labels", + "assignees", + "createdTime", + "schedulingIssue" + ] + }, + "TaskPost": { + "type": "object", + "properties": { + "dueDate": { + "type": "string", + "description": "ISO 8601 Due date on the task. REQUIRED for scheduled tasks", + "example": "2024-03-12T10:52:55.724-06:00", + "format": "date-time" + }, + "duration": { + "default": 30, + "description": "A duration can be one of the following... \"NONE\", \"REMINDER\", or a integer greater than 0", + "oneOf": [ + { + "enum": [ + "NONE", + "REMINDER" + ], + "type": "string" + }, + { + "minimum": 1, + "type": "number" + } + ] + }, + "status": { + "type": "string", + "description": "Defaults to workspace default status." + }, + "autoScheduled": { + "nullable": true, + "description": "Set values to turn auto scheduling on, set value to null if you want to turn auto scheduling off. The status for the task must have auto scheduling enabled.", + "allOf": [ + { + "$ref": "#/components/schemas/AutoScheduledInfo" + } + ] + }, + "name": { + "type": "string", + "description": "Name / title of the task", + "minLength": 1 + }, + "projectId": { + "type": "string" + }, + "workspaceId": { + "type": "string" + }, + "description": { + "type": "string", + "description": "Input as GitHub Flavored Markdown" + }, + "priority": { + "type": "string", + "default": "MEDIUM", + "enum": [ + "ASAP", + "HIGH", + "MEDIUM", + "LOW" + ] + }, + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "assigneeId": { + "type": "string", + "description": "The user id the task should be assigned to" + } + }, + "required": [ + "name", + "workspaceId" + ] + }, + "ListTasks": { + "type": "object", + "properties": { + "tasks": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Task" + } + }, + "meta": { + "description": "Information about the result. Contains information necessary for pagination.", + "allOf": [ + { + "$ref": "#/components/schemas/MetaResult" + } + ] + } + }, + "required": [ + "tasks" + ] + }, + "MoveTask": { + "type": "object", + "properties": { + "workspaceId": { + "type": "string" + }, + "assigneeId": { + "type": "string", + "description": "The user id the task should be assigned to" + } + }, + "required": [ + "workspaceId" + ] + }, + "ListUsers": { + "type": "object", + "properties": { + "users": { + "type": "array", + "items": { + "$ref": "#/components/schemas/User" + } + }, + "meta": { + "description": "Information about the result. Contains information necessary for pagination.", + "allOf": [ + { + "$ref": "#/components/schemas/MetaResult" + } + ] + } + }, + "required": [ + "users" + ] + }, + "ListWorkspaces": { + "type": "object", + "properties": { + "workspaces": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Workspace" + } + }, + "meta": { + "description": "Information about the result. Contains information necessary for pagination.", + "allOf": [ + { + "$ref": "#/components/schemas/MetaResult" + } + ] + } + }, + "required": [ + "workspaces" + ] + } + } + }, + "security": [ + { + "Motion_API_Key": [] + } + ] +} \ No newline at end of file diff --git a/src/motion/client.py b/src/motion/client.py index facaa49..a12f9b2 100644 --- a/src/motion/client.py +++ b/src/motion/client.py @@ -1,17 +1,23 @@ from enum import Enum -from typing import Any +from typing import Any, Generic, TypedDict, TypeVar from urllib.parse import urljoin import requests from requests import Response +T = TypeVar("T") + + +class GenericTypedDict(TypedDict, Generic[T]): + pass + class HttpMethod(Enum): GET = "GET" - POST = "POST" PUT = "PUT" - DELETE = "DELETE" + POST = "POST" PATCH = "PATCH" + DELETE = "DELETE" class HttpClient: @@ -24,7 +30,7 @@ def call_api( self, method: HttpMethod, path: str, - data: dict[str, Any] | None = None, + data: GenericTypedDict | None = None, params: dict[str, Any] | None = None, ) -> Response: """ @@ -36,6 +42,6 @@ def call_api( method=method.value, url=url, json=data, - params=params, + params=params, # type: ignore headers={"X-API-Key": self._api_key}, ) diff --git a/src/motion/models/__init__.py b/src/motion/models/__init__.py new file mode 100644 index 0000000..c9efe7a --- /dev/null +++ b/src/motion/models/__init__.py @@ -0,0 +1,143 @@ +from datetime import datetime +from typing import List, Optional, Union + +from pydantic import BaseModel, Field + + +class User(BaseModel): + id: str + name: str + email: Optional[str] = None + + +class Label(BaseModel): + name: str + + +class Status(BaseModel): + name: str + isDefaultStatus: bool + isResolvedStatus: bool + + +class Project(BaseModel): + id: str + name: str + description: Optional[str] = None + workspaceId: Optional[str] = None + status: Status + + +class Workspace(BaseModel): + id: str + name: str + teamId: Optional[str] = None + statuses: List[Status] + labels: List[Label] + type: str + + +class MetaResult(BaseModel): + nextCursor: Optional[str] = Field( + None, + description="Returned if there are more entities to return. Pass back with the cursor param set to continue paging.", + ) + pageSize: int = Field( + ..., + description="Maximum number of entities delivered per page", + ) + + +class Comment(BaseModel): + id: str + taskId: str + content: str + creator: User + createdAt: datetime + + +class ListComments(BaseModel): + comments: List[Comment] + meta: Optional[MetaResult] = None + + +class ListProjects(BaseModel): + projects: List[Project] + meta: Optional[MetaResult] = None + + +class RecurringTask(BaseModel): + workspace: Workspace + id: str + name: str + description: Optional[str] = None + creator: User + assignee: User + project: Optional[Project] = None + status: Status + priority: str + labels: List[Label] + + +class ListRecurringTasks(BaseModel): + tasks: List[RecurringTask] + meta: Optional[MetaResult] = None + + +class DailySchedule(BaseModel): + start: str + end: str + + +class ScheduleBreakout(BaseModel): + monday: List[DailySchedule] + tuesday: List[DailySchedule] + wednesday: List[DailySchedule] + thursday: List[DailySchedule] + friday: List[DailySchedule] + saturday: List[DailySchedule] + sunday: List[DailySchedule] + + +class Schedule(BaseModel): + name: str + isDefaultTimezone: bool + timezone: str + schedule: ScheduleBreakout + + +class Task(BaseModel): + duration: Union[str, int] + workspace: Workspace + id: str + name: str + description: Optional[str] = None + dueDate: datetime + deadlineType: str + parentRecurringTaskId: Optional[str] = None + completed: bool + creator: User + project: Optional[Project] = None + status: Status + priority: str + labels: List[Label] + assignees: List[User] + scheduledStart: Optional[datetime] = None + createdTime: datetime + scheduledEnd: Optional[datetime] = None + schedulingIssue: bool + + +class ListTasks(BaseModel): + tasks: List[Task] + meta: Optional[MetaResult] = None + + +class ListUsers(BaseModel): + users: List[User] + meta: Optional[MetaResult] = None + + +class ListWorkspaces(BaseModel): + workspaces: List[Workspace] + meta: Optional[MetaResult] = None diff --git a/src/motion/resources/base.py b/src/motion/resources/base.py index c0d0a0a..7fa29d2 100644 --- a/src/motion/resources/base.py +++ b/src/motion/resources/base.py @@ -1,9 +1,8 @@ from abc import ABC -from typing import Any from requests import Response -from ..client import HttpClient, HttpMethod +from ..client import GenericTypedDict, HttpClient, HttpMethod class Resource(ABC): @@ -20,14 +19,14 @@ def __init__(self, client: HttpClient) -> None: self.base_path is not None ), "base_path must be defined on resource" - def create(self, data: dict[str, Any]) -> Response: + def create(self, data: GenericTypedDict) -> Response: return self._client.call_api( HttpMethod.POST, self.base_path, data=data, ) - def update(self, object_id: str, data: dict[str, Any]) -> Response: + def update(self, object_id: str, data: GenericTypedDict) -> Response: return self._client.call_api( HttpMethod.PUT, path=f"{self.base_path}/{object_id}", @@ -40,11 +39,11 @@ def delete(self, object_id: str) -> Response: path=f"{self.base_path}/{object_id}", ) - def list(self, params: dict[str, Any] | None = None) -> Response: + def list(self, params: GenericTypedDict | None = None) -> Response: return self._client.call_api( HttpMethod.GET, path=self.base_path, - params=params, + params=params, # type: ignore ) def retrieve(self, object_id: str) -> Response: diff --git a/src/motion/resources/comment.py b/src/motion/resources/comment.py index 4e20ebd..14402ad 100644 --- a/src/motion/resources/comment.py +++ b/src/motion/resources/comment.py @@ -1,5 +1,26 @@ +from typing import TypedDict + +from ..models import Comment, ListComments from .base import Resource +class CommentCreate(TypedDict): + taskId: str + content: str + + +class CommentListParams(TypedDict, total=False): + cursor: str + taskId: str + + class CommentResource(Resource): base_path = "/comments" + + def create(self, data: CommentCreate) -> Comment: + response = super().create(data) + return Comment.model_validate(response.json()) + + def list(self, params: CommentListParams | None = None) -> ListComments: + response = super().list(params) + return ListComments.model_validate(response.json()) diff --git a/src/motion/resources/project.py b/src/motion/resources/project.py index 31b74a7..203f2c0 100644 --- a/src/motion/resources/project.py +++ b/src/motion/resources/project.py @@ -1,5 +1,31 @@ +from typing import TypedDict, List from .base import Resource +from ..models import Project, ListProjects +class ProjectCreate(TypedDict): + name: str + workspaceId: str + description: str | None + labels: List[str] | None + status: str | None + priority: str + +class ProjectListParams(TypedDict, total=False): + cursor: str + workspaceId: str + class ProjectResource(Resource): base_path = "/projects" + + def create(self, data: ProjectCreate) -> Project: + response = super().create(data) + return Project.model_validate(response.json()) + + def list(self, params: ProjectListParams | None = None) -> ListProjects: + response = super().list(params) + return ListProjects.model_validate(response.json()) + + def retrieve(self, object_id: str) -> Project: + response = super().retrieve(object_id) + return Project.model_validate(response.json()) diff --git a/src/motion/resources/schedule.py b/src/motion/resources/schedule.py index a34d8a7..d65fe3f 100644 --- a/src/motion/resources/schedule.py +++ b/src/motion/resources/schedule.py @@ -1,5 +1,10 @@ +from typing import List from .base import Resource - +from ..models import Schedule class ScheduleResource(Resource): base_path = "/schedules" + + def list(self) -> List[Schedule]: + response = super().list() + return [Schedule.model_validate(item) for item in response.json()] diff --git a/src/motion/resources/task.py b/src/motion/resources/task.py index 2d2df9a..1b4b733 100644 --- a/src/motion/resources/task.py +++ b/src/motion/resources/task.py @@ -1,33 +1,118 @@ -from requests import Response +from typing import Any, List, TypedDict from ..client import HttpMethod +from ..models import ListRecurringTasks, ListTasks, RecurringTask, Task from .base import Resource +class TaskCreate(TypedDict, total=False): + name: str + workspaceId: str + dueDate: str + duration: int | str + status: str + autoScheduled: dict[str, Any] | None + projectId: str | None + description: str | None + priority: str + labels: List[str] | None + assigneeId: str | None + + +class TaskUpdate(TypedDict, total=False): + name: str + dueDate: str + assigneeId: str | None + duration: int | str + status: str + autoScheduled: dict[str, Any] | None + projectId: str + description: str + priority: str + labels: List[str] + + +class TaskListParams(TypedDict, total=False): + cursor: str + label: str + status: List[str] + includeAllStatuses: bool + workspaceId: str + projectId: str + name: str + assigneeId: str + + +class TaskMoveWorkspace(TypedDict): + workspaceId: str + assigneeId: str | None + + +class RecurringTaskCreate(TypedDict): + frequency: str + deadlineType: str + duration: int | str + startingOn: str + idealTime: str | None + schedule: str + name: str + workspaceId: str + description: str | None + priority: str + assigneeId: str + + +class RecurringTaskListParams(TypedDict, total=False): + cursor: str + workspaceId: str + + class TaskResource(Resource): base_path = "/tasks" - def unassign_task(self, task_id: str) -> Response: - return self._client.call_api( + def create(self, data: TaskCreate) -> Task: + response = super().create(data) + return Task.model_validate(response.json()) + + def update(self, object_id: str, data: TaskUpdate) -> Task: + response = super().update(object_id, data) + return Task.model_validate(response.json()) + + def list(self, params: TaskListParams | None = None) -> ListTasks: + response = super().list(params) + return ListTasks.model_validate(response.json()) + + def retrieve(self, object_id: str) -> Task: + response = super().retrieve(object_id) + return Task.model_validate(response.json()) + + def unassign_task(self, task_id: str) -> None: + self._client.call_api( HttpMethod.DELETE, path=f"{self.base_path}/{task_id}/assignee", ) - def move_workspace( - self, - task_id: str, - workspace_id: str, - assignee_id: str, - ) -> Response: - return self._client.call_api( + def move_workspace(self, task_id: str, data: TaskMoveWorkspace) -> Task: + response = self._client.call_api( HttpMethod.PATCH, path=f"{self.base_path}/{task_id}/move", - data={ - "assigneeId": assignee_id, - "workspaceId": workspace_id, - }, + data=data, ) + return Task.model_validate(response.json()) class RecurringTaskResource(Resource): - base_path = "/recurringTasks" + base_path = "/recurring-tasks" + + def create(self, data: RecurringTaskCreate) -> RecurringTask: + response = super().create(data) + return RecurringTask.model_validate(response.json()) + + def list( + self, params: RecurringTaskListParams | None = None + ) -> ListRecurringTasks: + response = super().list(params) + return ListRecurringTasks.model_validate(response.json()) + + def delete(self, object_id: str) -> None: + super().delete(object_id) diff --git a/src/motion/resources/user.py b/src/motion/resources/user.py index c519633..04aff7c 100644 --- a/src/motion/resources/user.py +++ b/src/motion/resources/user.py @@ -1,13 +1,26 @@ -from requests import Response -from .base import Resource +from typing import TypedDict + from ..client import HttpMethod +from ..models import ListUsers, User +from .base import Resource + + +class UserListParams(TypedDict, total=False): + cursor: str + workspaceId: str + teamId: str class UserResource(Resource): base_path = "/users" - def get_self(self) -> Response: - return self._client.call_api( + def get_self(self) -> User: + response = self._client.call_api( HttpMethod.GET, path=f"{self.base_path}/me", ) + return User.model_validate(response.json()) + + def list(self, params: UserListParams | None = None) -> ListUsers: + response = super().list(params) + return ListUsers.model_validate(response.json()) diff --git a/src/motion/resources/workspace.py b/src/motion/resources/workspace.py index 54948b2..b9225ae 100644 --- a/src/motion/resources/workspace.py +++ b/src/motion/resources/workspace.py @@ -1,15 +1,28 @@ -from requests import Response +from typing import TypedDict, List from ..client import HttpMethod +from ..models import ListWorkspaces, Status from .base import Resource +class WorkspaceListParams(TypedDict, total=False): + cursor: str + ids: List[str] + + class WorkspaceResource(Resource): base_path = "/workspaces" - def list_statuses(self, workspace_id: str) -> Response: - return self._client.call_api( + def list( + self, params: WorkspaceListParams | None = None + ) -> ListWorkspaces: + response = super().list(params) + return ListWorkspaces.model_validate(response.json()) + + def list_statuses(self, workspace_id: str) -> List[Status]: + response = self._client.call_api( HttpMethod.GET, - path=f"{self.base_path}/statuses", + path="/statuses", params={"workspaceId": workspace_id}, ) + return [Status.model_validate(item) for item in response.json()] From d4192e82e33fc3b79093d49668308b8558262d65 Mon Sep 17 00:00:00 2001 From: Lemi Boyce Date: Tue, 24 Sep 2024 02:06:04 -0400 Subject: [PATCH 2/5] raise for status --- src/motion/client.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/motion/client.py b/src/motion/client.py index a12f9b2..ca41468 100644 --- a/src/motion/client.py +++ b/src/motion/client.py @@ -38,10 +38,12 @@ def call_api( """ path = path[1:] if path.startswith("/") else path url = urljoin(self._base_url, f"/{self._api_version}/{path}") - return requests.request( + response = requests.request( method=method.value, url=url, json=data, params=params, # type: ignore headers={"X-API-Key": self._api_key}, ) + response.raise_for_status() + return response From 8cc1357dd397b30c24e7cad2c1c9c78c537fed22 Mon Sep 17 00:00:00 2001 From: Lemi Boyce Date: Tue, 24 Sep 2024 02:10:24 -0400 Subject: [PATCH 3/5] add test workflow --- .github/workflows/release.yaml | 6 ++-- .github/workflows/test.yaml | 25 ++++++++++++++ poetry.lock | 61 +++++++++++++++++++++++++++++++-- pyproject.toml | 1 + tests/conftest.py | 6 ++++ tests/test_comment_resource.py | 47 +++++++++++++++++++++++++ tests/test_project_resource.py | 61 +++++++++++++++++++++++++++++++++ tests/test_schedule_resource.py | 37 ++++++++++++++++++++ tests/test_user_resource.py | 47 +++++++++++++++++++++++++ 9 files changed, 286 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/test.yaml create mode 100644 tests/conftest.py create mode 100644 tests/test_comment_resource.py create mode 100644 tests/test_project_resource.py create mode 100644 tests/test_schedule_resource.py create mode 100644 tests/test_user_resource.py diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index b902dff..3f91430 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,7 +1,7 @@ name: PyPI Release on: release: - types: [ created ] + types: [created] jobs: pypi-publish: runs-on: ubuntu-latest @@ -13,7 +13,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: '3.11' + python-version: "3.11" - name: Install dependencies run: | curl -sSL https://install.python-poetry.org | python3 - @@ -24,4 +24,4 @@ jobs: run: | poetry build - name: Publish package distributions to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 \ No newline at end of file + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..0d2dd42 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,25 @@ +name: Test +on: + push: + branches: [main] +jobs: + test: + runs-on: ubuntu-latest + environment: release + permissions: + id-token: write + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + - name: Install dependencies + run: | + curl -sSL https://install.python-poetry.org | python3 - + python -m pip install --upgrade pip + pip install setuptools wheel twine + poetry install + - name: Run tests + run: | + poetry run pytest diff --git a/poetry.lock b/poetry.lock index 38194d6..95b04b6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "annotated-types" @@ -163,6 +163,17 @@ files = [ {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + [[package]] name = "idna" version = "3.6" @@ -174,6 +185,17 @@ files = [ {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, ] +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + [[package]] name = "lsprotocol" version = "2023.0.1" @@ -200,6 +222,21 @@ files = [ {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + [[package]] name = "pydantic" version = "2.6.1" @@ -328,6 +365,26 @@ lsprotocol = "2023.0.1" [package.extras] ws = ["websockets (>=11.0.3)"] +[[package]] +name = "pytest" +version = "8.3.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, + {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=1.5,<2" + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + [[package]] name = "requests" version = "2.31.0" @@ -427,4 +484,4 @@ zstd = ["zstandard (>=0.18.0)"] [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "d824129b4e568b44d07fa4b188dfca57a5740ec65cc28b2335a8ce7e84cfcd65" +content-hash = "08bcb245c25ffc5aaa7232c65dc54aceed558a147b63b4c434d261171935df3e" diff --git a/pyproject.toml b/pyproject.toml index 3134a1e..c2b7f1c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ pydantic = "^2.6.1" [tool.poetry.group.dev.dependencies] ruff = "^0.2.2" ruff-lsp = "^0.0.52" +pytest = "^8.3.3" [tool.ruff] line-length = 79 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..bc3331a --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,6 @@ +import pytest +from unittest.mock import Mock + +@pytest.fixture +def mock_client(): + return Mock() \ No newline at end of file diff --git a/tests/test_comment_resource.py b/tests/test_comment_resource.py new file mode 100644 index 0000000..ceeb10f --- /dev/null +++ b/tests/test_comment_resource.py @@ -0,0 +1,47 @@ +import pytest +from datetime import datetime +from motion.resources.comment import CommentResource +from motion.models import Comment, ListComments, User + +@pytest.fixture +def comment_resource(mock_client): + return CommentResource(mock_client) + +def test_create_comment(comment_resource, mock_client): + mock_client.call_api.return_value.json.return_value = { + "id": "123", + "taskId": "task123", + "content": "Test comment", + "creator": {"id": "user1", "name": "John Doe"}, + "createdAt": "2023-06-01T12:00:00Z" + } + + comment = comment_resource.create({"taskId": "task123", "content": "Test comment"}) + + assert isinstance(comment, Comment) + assert comment.id == "123" + assert comment.taskId == "task123" + assert comment.content == "Test comment" + assert isinstance(comment.creator, User) + assert isinstance(comment.createdAt, datetime) + +def test_list_comments(comment_resource, mock_client): + mock_client.call_api.return_value.json.return_value = { + "comments": [ + { + "id": "123", + "taskId": "task123", + "content": "Test comment", + "creator": {"id": "user1", "name": "John Doe"}, + "createdAt": "2023-06-01T12:00:00Z" + } + ], + "meta": {"pageSize": 10} + } + + comments = comment_resource.list({"taskId": "task123"}) + + assert isinstance(comments, ListComments) + assert len(comments.comments) == 1 + assert isinstance(comments.comments[0], Comment) + assert comments.meta.pageSize == 10 \ No newline at end of file diff --git a/tests/test_project_resource.py b/tests/test_project_resource.py new file mode 100644 index 0000000..8c10fc3 --- /dev/null +++ b/tests/test_project_resource.py @@ -0,0 +1,61 @@ +import pytest +from motion.resources.project import ProjectResource +from motion.models import Project, ListProjects, Status + +@pytest.fixture +def project_resource(mock_client): + return ProjectResource(mock_client) + +def test_create_project(project_resource, mock_client): + mock_client.call_api.return_value.json.return_value = { + "id": "proj123", + "name": "Test Project", + "description": "A test project", + "workspaceId": "ws123", + "status": {"name": "In Progress", "isDefaultStatus": False, "isResolvedStatus": False} + } + + project = project_resource.create({ + "name": "Test Project", + "workspaceId": "ws123", + "description": "A test project", + "priority": "MEDIUM" + }) + + assert isinstance(project, Project) + assert project.id == "proj123" + assert project.name == "Test Project" + assert project.workspaceId == "ws123" + assert isinstance(project.status, Status) + +def test_list_projects(project_resource, mock_client): + mock_client.call_api.return_value.json.return_value = { + "projects": [ + { + "id": "proj123", + "name": "Test Project", + "status": {"name": "In Progress", "isDefaultStatus": False, "isResolvedStatus": False} + } + ], + "meta": {"pageSize": 10} + } + + projects = project_resource.list({"workspaceId": "ws123"}) + + assert isinstance(projects, ListProjects) + assert len(projects.projects) == 1 + assert isinstance(projects.projects[0], Project) + assert projects.meta.pageSize == 10 + +def test_retrieve_project(project_resource, mock_client): + mock_client.call_api.return_value.json.return_value = { + "id": "proj123", + "name": "Test Project", + "status": {"name": "In Progress", "isDefaultStatus": False, "isResolvedStatus": False} + } + + project = project_resource.retrieve("proj123") + + assert isinstance(project, Project) + assert project.id == "proj123" + assert project.name == "Test Project" \ No newline at end of file diff --git a/tests/test_schedule_resource.py b/tests/test_schedule_resource.py new file mode 100644 index 0000000..c3d6c5e --- /dev/null +++ b/tests/test_schedule_resource.py @@ -0,0 +1,37 @@ +import pytest +from motion.resources.schedule import ScheduleResource +from motion.models import Schedule + +@pytest.fixture +def schedule_resource(mock_client): + return ScheduleResource(mock_client) + +def test_list_schedules(schedule_resource, mock_client): + mock_client.call_api.return_value.json.return_value = [ + { + "name": "Work Hours", + "isDefaultTimezone": True, + "timezone": "America/New_York", + "schedule": { + "monday": [{"start": "09:00", "end": "17:00"}], + "tuesday": [{"start": "09:00", "end": "17:00"}], + "wednesday": [{"start": "09:00", "end": "17:00"}], + "thursday": [{"start": "09:00", "end": "17:00"}], + "friday": [{"start": "09:00", "end": "17:00"}], + "saturday": [], + "sunday": [] + } + } + ] + + schedules = schedule_resource.list() + + assert isinstance(schedules, list) + assert len(schedules) == 1 + assert isinstance(schedules[0], Schedule) + assert schedules[0].name == "Work Hours" + assert schedules[0].isDefaultTimezone == True + assert schedules[0].timezone == "America/New_York" + assert len(schedules[0].schedule.monday) == 1 + assert schedules[0].schedule.monday[0].start == "09:00" + assert schedules[0].schedule.monday[0].end == "17:00" \ No newline at end of file diff --git a/tests/test_user_resource.py b/tests/test_user_resource.py new file mode 100644 index 0000000..5dfc60a --- /dev/null +++ b/tests/test_user_resource.py @@ -0,0 +1,47 @@ +import pytest +from motion.resources.user import UserResource +from motion.models import User, ListUsers + +@pytest.fixture +def user_resource(mock_client): + return UserResource(mock_client) + +def test_get_self(user_resource, mock_client): + mock_client.call_api.return_value.json.return_value = { + "id": "user1", + "name": "John Doe", + "email": "john@example.com" + } + + user = user_resource.get_self() + + assert isinstance(user, User) + assert user.id == "user1" + assert user.name == "John Doe" + assert user.email == "john@example.com" + +def test_list_users(user_resource, mock_client): + mock_client.call_api.return_value.json.return_value = { + "users": [ + { + "id": "user1", + "name": "John Doe", + "email": "john@example.com" + }, + { + "id": "user2", + "name": "Jane Doe", + "email": "jane@example.com" + } + ], + "meta": {"pageSize": 10} + } + + users = user_resource.list({"workspaceId": "ws123"}) + + assert isinstance(users, ListUsers) + assert len(users.users) == 2 + assert isinstance(users.users[0], User) + assert users.users[0].id == "user1" + assert users.users[1].id == "user2" + assert users.meta.pageSize == 10 \ No newline at end of file From 5e265e31d712806cfcc604cb3a2ac706d6bebc00 Mon Sep 17 00:00:00 2001 From: Lemi Boyce Date: Tue, 24 Sep 2024 02:16:33 -0400 Subject: [PATCH 4/5] bump deps --- poetry.lock | 317 ++++++++++++++++++++++++++----------------------- pyproject.toml | 10 +- 2 files changed, 173 insertions(+), 154 deletions(-) diff --git a/poetry.lock b/poetry.lock index 95b04b6..44ac721 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,43 +2,43 @@ [[package]] name = "annotated-types" -version = "0.6.0" +version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" files = [ - {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, - {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, ] [[package]] name = "attrs" -version = "23.2.0" +version = "24.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, - {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, ] [package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] -tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] [[package]] name = "cattrs" -version = "23.2.3" +version = "24.1.2" description = "Composable complex class support for attrs and dataclasses." optional = false python-versions = ">=3.8" files = [ - {file = "cattrs-23.2.3-py3-none-any.whl", hash = "sha256:0341994d94971052e9ee70662542699a3162ea1e0c62f7ce1b4a57f563685108"}, - {file = "cattrs-23.2.3.tar.gz", hash = "sha256:a934090d95abaa9e911dac357e3a8699e0b4b14f8529bcc7d2b1ad9d51672b9f"}, + {file = "cattrs-24.1.2-py3-none-any.whl", hash = "sha256:67c7495b760168d931a10233f979b28dc04daf853b30752246f4f8471c6d68d0"}, + {file = "cattrs-24.1.2.tar.gz", hash = "sha256:8028cfe1ff5382df59dd36474a86e02d817b06eaf8af84555441bac915d2ef85"}, ] [package.dependencies] @@ -48,6 +48,7 @@ attrs = ">=23.1.0" bson = ["pymongo (>=4.4.0)"] cbor2 = ["cbor2 (>=5.4.6)"] msgpack = ["msgpack (>=1.0.5)"] +msgspec = ["msgspec (>=0.18.5)"] orjson = ["orjson (>=3.9.2)"] pyyaml = ["pyyaml (>=6.0)"] tomlkit = ["tomlkit (>=0.11.8)"] @@ -55,13 +56,13 @@ ujson = ["ujson (>=5.7.0)"] [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] @@ -176,15 +177,18 @@ files = [ [[package]] name = "idna" -version = "3.6" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "iniconfig" version = "2.0.0" @@ -213,13 +217,13 @@ cattrs = "!=23.2.1" [[package]] name = "packaging" -version = "23.2" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -239,109 +243,123 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pydantic" -version = "2.6.1" +version = "2.9.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.6.1-py3-none-any.whl", hash = "sha256:0b6a909df3192245cb736509a92ff69e4fef76116feffec68e93a567347bae6f"}, - {file = "pydantic-2.6.1.tar.gz", hash = "sha256:4fd5c182a2488dc63e6d32737ff19937888001e2a6d86e94b3f233104a5d1fa9"}, + {file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"}, + {file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"}, ] [package.dependencies] -annotated-types = ">=0.4.0" -pydantic-core = "2.16.2" -typing-extensions = ">=4.6.1" +annotated-types = ">=0.6.0" +pydantic-core = "2.23.4" +typing-extensions = [ + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, +] [package.extras] email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.16.2" -description = "" +version = "2.23.4" +description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.16.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3fab4e75b8c525a4776e7630b9ee48aea50107fea6ca9f593c98da3f4d11bf7c"}, - {file = "pydantic_core-2.16.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8bde5b48c65b8e807409e6f20baee5d2cd880e0fad00b1a811ebc43e39a00ab2"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2924b89b16420712e9bb8192396026a8fbd6d8726224f918353ac19c4c043d2a"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16aa02e7a0f539098e215fc193c8926c897175d64c7926d00a36188917717a05"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:936a787f83db1f2115ee829dd615c4f684ee48ac4de5779ab4300994d8af325b"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:459d6be6134ce3b38e0ef76f8a672924460c455d45f1ad8fdade36796df1ddc8"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9ee4febb249c591d07b2d4dd36ebcad0ccd128962aaa1801508320896575ef"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40a0bd0bed96dae5712dab2aba7d334a6c67cbcac2ddfca7dbcc4a8176445990"}, - {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:870dbfa94de9b8866b37b867a2cb37a60c401d9deb4a9ea392abf11a1f98037b"}, - {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:308974fdf98046db28440eb3377abba274808bf66262e042c412eb2adf852731"}, - {file = "pydantic_core-2.16.2-cp310-none-win32.whl", hash = "sha256:a477932664d9611d7a0816cc3c0eb1f8856f8a42435488280dfbf4395e141485"}, - {file = "pydantic_core-2.16.2-cp310-none-win_amd64.whl", hash = "sha256:8f9142a6ed83d90c94a3efd7af8873bf7cefed2d3d44387bf848888482e2d25f"}, - {file = "pydantic_core-2.16.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:406fac1d09edc613020ce9cf3f2ccf1a1b2f57ab00552b4c18e3d5276c67eb11"}, - {file = "pydantic_core-2.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce232a6170dd6532096cadbf6185271e4e8c70fc9217ebe105923ac105da9978"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90fec23b4b05a09ad988e7a4f4e081711a90eb2a55b9c984d8b74597599180f"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8aafeedb6597a163a9c9727d8a8bd363a93277701b7bfd2749fbefee2396469e"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9957433c3a1b67bdd4c63717eaf174ebb749510d5ea612cd4e83f2d9142f3fc8"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0d7a9165167269758145756db43a133608a531b1e5bb6a626b9ee24bc38a8f7"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dffaf740fe2e147fedcb6b561353a16243e654f7fe8e701b1b9db148242e1272"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ed79883b4328b7f0bd142733d99c8e6b22703e908ec63d930b06be3a0e7113"}, - {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cf903310a34e14651c9de056fcc12ce090560864d5a2bb0174b971685684e1d8"}, - {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:46b0d5520dbcafea9a8645a8164658777686c5c524d381d983317d29687cce97"}, - {file = "pydantic_core-2.16.2-cp311-none-win32.whl", hash = "sha256:70651ff6e663428cea902dac297066d5c6e5423fda345a4ca62430575364d62b"}, - {file = "pydantic_core-2.16.2-cp311-none-win_amd64.whl", hash = "sha256:98dc6f4f2095fc7ad277782a7c2c88296badcad92316b5a6e530930b1d475ebc"}, - {file = "pydantic_core-2.16.2-cp311-none-win_arm64.whl", hash = "sha256:ef6113cd31411eaf9b39fc5a8848e71c72656fd418882488598758b2c8c6dfa0"}, - {file = "pydantic_core-2.16.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:88646cae28eb1dd5cd1e09605680c2b043b64d7481cdad7f5003ebef401a3039"}, - {file = "pydantic_core-2.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7b883af50eaa6bb3299780651e5be921e88050ccf00e3e583b1e92020333304b"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bf26c2e2ea59d32807081ad51968133af3025c4ba5753e6a794683d2c91bf6e"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99af961d72ac731aae2a1b55ccbdae0733d816f8bfb97b41909e143de735f522"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02906e7306cb8c5901a1feb61f9ab5e5c690dbbeaa04d84c1b9ae2a01ebe9379"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5362d099c244a2d2f9659fb3c9db7c735f0004765bbe06b99be69fbd87c3f15"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ac426704840877a285d03a445e162eb258924f014e2f074e209d9b4ff7bf380"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b94cbda27267423411c928208e89adddf2ea5dd5f74b9528513f0358bba019cb"}, - {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6db58c22ac6c81aeac33912fb1af0e930bc9774166cdd56eade913d5f2fff35e"}, - {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396fdf88b1b503c9c59c84a08b6833ec0c3b5ad1a83230252a9e17b7dfb4cffc"}, - {file = "pydantic_core-2.16.2-cp312-none-win32.whl", hash = "sha256:7c31669e0c8cc68400ef0c730c3a1e11317ba76b892deeefaf52dcb41d56ed5d"}, - {file = "pydantic_core-2.16.2-cp312-none-win_amd64.whl", hash = "sha256:a3b7352b48fbc8b446b75f3069124e87f599d25afb8baa96a550256c031bb890"}, - {file = "pydantic_core-2.16.2-cp312-none-win_arm64.whl", hash = "sha256:a9e523474998fb33f7c1a4d55f5504c908d57add624599e095c20fa575b8d943"}, - {file = "pydantic_core-2.16.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ae34418b6b389d601b31153b84dce480351a352e0bb763684a1b993d6be30f17"}, - {file = "pydantic_core-2.16.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:732bd062c9e5d9582a30e8751461c1917dd1ccbdd6cafb032f02c86b20d2e7ec"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b52776a2e3230f4854907a1e0946eec04d41b1fc64069ee774876bbe0eab55"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef551c053692b1e39e3f7950ce2296536728871110e7d75c4e7753fb30ca87f4"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ebb892ed8599b23fa8f1799e13a12c87a97a6c9d0f497525ce9858564c4575a4"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa6c8c582036275997a733427b88031a32ffa5dfc3124dc25a730658c47a572f"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ba0884a91f1aecce75202473ab138724aa4fb26d7707f2e1fa6c3e68c84fbf"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7924e54f7ce5d253d6160090ddc6df25ed2feea25bfb3339b424a9dd591688bc"}, - {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69a7b96b59322a81c2203be537957313b07dd333105b73db0b69212c7d867b4b"}, - {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7e6231aa5bdacda78e96ad7b07d0c312f34ba35d717115f4b4bff6cb87224f0f"}, - {file = "pydantic_core-2.16.2-cp38-none-win32.whl", hash = "sha256:41dac3b9fce187a25c6253ec79a3f9e2a7e761eb08690e90415069ea4a68ff7a"}, - {file = "pydantic_core-2.16.2-cp38-none-win_amd64.whl", hash = "sha256:f685dbc1fdadb1dcd5b5e51e0a378d4685a891b2ddaf8e2bba89bd3a7144e44a"}, - {file = "pydantic_core-2.16.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:55749f745ebf154c0d63d46c8c58594d8894b161928aa41adbb0709c1fe78b77"}, - {file = "pydantic_core-2.16.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b30b0dd58a4509c3bd7eefddf6338565c4905406aee0c6e4a5293841411a1286"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18de31781cdc7e7b28678df7c2d7882f9692ad060bc6ee3c94eb15a5d733f8f7"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5864b0242f74b9dd0b78fd39db1768bc3f00d1ffc14e596fd3e3f2ce43436a33"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8f9186ca45aee030dc8234118b9c0784ad91a0bb27fc4e7d9d6608a5e3d386c"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc6f6c9be0ab6da37bc77c2dda5f14b1d532d5dbef00311ee6e13357a418e646"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa057095f621dad24a1e906747179a69780ef45cc8f69e97463692adbcdae878"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ad84731a26bcfb299f9eab56c7932d46f9cad51c52768cace09e92a19e4cf55"}, - {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3b052c753c4babf2d1edc034c97851f867c87d6f3ea63a12e2700f159f5c41c3"}, - {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e0f686549e32ccdb02ae6f25eee40cc33900910085de6aa3790effd391ae10c2"}, - {file = "pydantic_core-2.16.2-cp39-none-win32.whl", hash = "sha256:7afb844041e707ac9ad9acad2188a90bffce2c770e6dc2318be0c9916aef1469"}, - {file = "pydantic_core-2.16.2-cp39-none-win_amd64.whl", hash = "sha256:9da90d393a8227d717c19f5397688a38635afec89f2e2d7af0df037f3249c39a"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f60f920691a620b03082692c378661947d09415743e437a7478c309eb0e4f82"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:47924039e785a04d4a4fa49455e51b4eb3422d6eaacfde9fc9abf8fdef164e8a"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6294e76b0380bb7a61eb8a39273c40b20beb35e8c87ee101062834ced19c545"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe56851c3f1d6f5384b3051c536cc81b3a93a73faf931f404fef95217cf1e10d"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9d776d30cde7e541b8180103c3f294ef7c1862fd45d81738d156d00551005784"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:72f7919af5de5ecfaf1eba47bf9a5d8aa089a3340277276e5636d16ee97614d7"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:4bfcbde6e06c56b30668a0c872d75a7ef3025dc3c1823a13cf29a0e9b33f67e8"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ff7c97eb7a29aba230389a2661edf2e9e06ce616c7e35aa764879b6894a44b25"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9b5f13857da99325dcabe1cc4e9e6a3d7b2e2c726248ba5dd4be3e8e4a0b6d0e"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a7e41e3ada4cca5f22b478c08e973c930e5e6c7ba3588fb8e35f2398cdcc1545"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60eb8ceaa40a41540b9acae6ae7c1f0a67d233c40dc4359c256ad2ad85bdf5e5"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7beec26729d496a12fd23cf8da9944ee338c8b8a17035a560b585c36fe81af20"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:22c5f022799f3cd6741e24f0443ead92ef42be93ffda0d29b2597208c94c3753"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:eca58e319f4fd6df004762419612122b2c7e7d95ffafc37e890252f869f3fb2a"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed957db4c33bc99895f3a1672eca7e80e8cda8bd1e29a80536b4ec2153fa9804"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:459c0d338cc55d099798618f714b21b7ece17eb1a87879f2da20a3ff4c7628e2"}, - {file = "pydantic_core-2.16.2.tar.gz", hash = "sha256:0ba503850d8b8dcc18391f10de896ae51d37fe5fe43dbfb6a35c5c5cad271a06"}, + {file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"}, + {file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f"}, + {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3"}, + {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071"}, + {file = "pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119"}, + {file = "pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f"}, + {file = "pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8"}, + {file = "pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b"}, + {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0"}, + {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64"}, + {file = "pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f"}, + {file = "pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3"}, + {file = "pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231"}, + {file = "pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126"}, + {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e"}, + {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24"}, + {file = "pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84"}, + {file = "pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9"}, + {file = "pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc"}, + {file = "pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327"}, + {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6"}, + {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f"}, + {file = "pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769"}, + {file = "pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5"}, + {file = "pydantic_core-2.23.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555"}, + {file = "pydantic_core-2.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12"}, + {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2"}, + {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb"}, + {file = "pydantic_core-2.23.4-cp38-none-win32.whl", hash = "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6"}, + {file = "pydantic_core-2.23.4-cp38-none-win_amd64.whl", hash = "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556"}, + {file = "pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a"}, + {file = "pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55"}, + {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040"}, + {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605"}, + {file = "pydantic_core-2.23.4-cp39-none-win32.whl", hash = "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6"}, + {file = "pydantic_core-2.23.4-cp39-none-win_amd64.whl", hash = "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e"}, + {file = "pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863"}, ] [package.dependencies] @@ -349,13 +367,13 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pygls" -version = "1.3.0" +version = "1.3.1" description = "A pythonic generic language server (pronounced like 'pie glass')" optional = false python-versions = ">=3.8" files = [ - {file = "pygls-1.3.0-py3-none-any.whl", hash = "sha256:d4a01414b6ed4e34e7e8fd29b77d3e88c29615df7d0bbff49bf019e15ec04b8f"}, - {file = "pygls-1.3.0.tar.gz", hash = "sha256:1b44ace89c9382437a717534f490eadc6fda7c0c6c16ac1eaaf5568e345e4fb8"}, + {file = "pygls-1.3.1-py3-none-any.whl", hash = "sha256:6e00f11efc56321bdeb6eac04f6d86131f654c7d49124344a9ebb968da3dd91e"}, + {file = "pygls-1.3.1.tar.gz", hash = "sha256:140edceefa0da0e9b3c533547c892a42a7d2fd9217ae848c330c53d266a55018"}, ] [package.dependencies] @@ -387,13 +405,13 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments [[package]] name = "requests" -version = "2.31.0" +version = "2.32.3" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -408,39 +426,40 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "ruff" -version = "0.2.2" +version = "0.6.7" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0a9efb032855ffb3c21f6405751d5e147b0c6b631e3ca3f6b20f917572b97eb6"}, - {file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d450b7fbff85913f866a5384d8912710936e2b96da74541c82c1b458472ddb39"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecd46e3106850a5c26aee114e562c329f9a1fbe9e4821b008c4404f64ff9ce73"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e22676a5b875bd72acd3d11d5fa9075d3a5f53b877fe7b4793e4673499318ba"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1695700d1e25a99d28f7a1636d85bafcc5030bba9d0578c0781ba1790dbcf51c"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b0c232af3d0bd8f521806223723456ffebf8e323bd1e4e82b0befb20ba18388e"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f63d96494eeec2fc70d909393bcd76c69f35334cdbd9e20d089fb3f0640216ca"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a61ea0ff048e06de273b2e45bd72629f470f5da8f71daf09fe481278b175001"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1439c8f407e4f356470e54cdecdca1bd5439a0673792dbe34a2b0a551a2fe3"}, - {file = "ruff-0.2.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:940de32dc8853eba0f67f7198b3e79bc6ba95c2edbfdfac2144c8235114d6726"}, - {file = "ruff-0.2.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c126da55c38dd917621552ab430213bdb3273bb10ddb67bc4b761989210eb6e"}, - {file = "ruff-0.2.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3b65494f7e4bed2e74110dac1f0d17dc8e1f42faaa784e7c58a98e335ec83d7e"}, - {file = "ruff-0.2.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1ec49be4fe6ddac0503833f3ed8930528e26d1e60ad35c2446da372d16651ce9"}, - {file = "ruff-0.2.2-py3-none-win32.whl", hash = "sha256:d920499b576f6c68295bc04e7b17b6544d9d05f196bb3aac4358792ef6f34325"}, - {file = "ruff-0.2.2-py3-none-win_amd64.whl", hash = "sha256:cc9a91ae137d687f43a44c900e5d95e9617cb37d4c989e462980ba27039d239d"}, - {file = "ruff-0.2.2-py3-none-win_arm64.whl", hash = "sha256:c9d15fc41e6054bfc7200478720570078f0b41c9ae4f010bcc16bd6f4d1aacdd"}, - {file = "ruff-0.2.2.tar.gz", hash = "sha256:e62ed7f36b3068a30ba39193a14274cd706bc486fad521276458022f7bccb31d"}, + {file = "ruff-0.6.7-py3-none-linux_armv6l.whl", hash = "sha256:08277b217534bfdcc2e1377f7f933e1c7957453e8a79764d004e44c40db923f2"}, + {file = "ruff-0.6.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c6707a32e03b791f4448dc0dce24b636cbcdee4dd5607adc24e5ee73fd86c00a"}, + {file = "ruff-0.6.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:533d66b7774ef224e7cf91506a7dafcc9e8ec7c059263ec46629e54e7b1f90ab"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17a86aac6f915932d259f7bec79173e356165518859f94649d8c50b81ff087e9"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b3f8822defd260ae2460ea3832b24d37d203c3577f48b055590a426a722d50ef"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ba4efe5c6dbbb58be58dd83feedb83b5e95c00091bf09987b4baf510fee5c99"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:525201b77f94d2b54868f0cbe5edc018e64c22563da6c5c2e5c107a4e85c1c0d"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8854450839f339e1049fdbe15d875384242b8e85d5c6947bb2faad33c651020b"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f0b62056246234d59cbf2ea66e84812dc9ec4540518e37553513392c171cb18"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b1462fa56c832dc0cea5b4041cfc9c97813505d11cce74ebc6d1aae068de36b"}, + {file = "ruff-0.6.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:02b083770e4cdb1495ed313f5694c62808e71764ec6ee5db84eedd82fd32d8f5"}, + {file = "ruff-0.6.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c05fd37013de36dfa883a3854fae57b3113aaa8abf5dea79202675991d48624"}, + {file = "ruff-0.6.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f49c9caa28d9bbfac4a637ae10327b3db00f47d038f3fbb2195c4d682e925b14"}, + {file = "ruff-0.6.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a0e1655868164e114ba43a908fd2d64a271a23660195017c17691fb6355d59bb"}, + {file = "ruff-0.6.7-py3-none-win32.whl", hash = "sha256:a939ca435b49f6966a7dd64b765c9df16f1faed0ca3b6f16acdf7731969deb35"}, + {file = "ruff-0.6.7-py3-none-win_amd64.whl", hash = "sha256:590445eec5653f36248584579c06252ad2e110a5d1f32db5420de35fb0e1c977"}, + {file = "ruff-0.6.7-py3-none-win_arm64.whl", hash = "sha256:b28f0d5e2f771c1fe3c7a45d3f53916fc74a480698c4b5731f0bea61e52137c8"}, + {file = "ruff-0.6.7.tar.gz", hash = "sha256:44e52129d82266fa59b587e2cd74def5637b730a69c4542525dfdecfaae38bd5"}, ] [[package]] name = "ruff-lsp" -version = "0.0.52" +version = "0.0.57" description = "A Language Server Protocol implementation for Ruff." optional = false python-versions = ">=3.7" files = [ - {file = "ruff_lsp-0.0.52-py3-none-any.whl", hash = "sha256:b7a72a4f4defb9037f81100f079ed6be37beaf8d201b5c0798bf54a723b46e56"}, - {file = "ruff_lsp-0.0.52.tar.gz", hash = "sha256:3861c8fb81db005d51c0c15939fae05a6488182847bad936e1cc95bad519d107"}, + {file = "ruff_lsp-0.0.57-py3-none-any.whl", hash = "sha256:0b63007c415a85200a18815a1367f207ceba51a20653b2a7bc63fe6cb4925cb5"}, + {file = "ruff_lsp-0.0.57.tar.gz", hash = "sha256:559b72ba460d0b90aab66ca11785b90ad8c6931509eb56db7dea2a8922bf41a8"}, ] [package.dependencies] @@ -451,28 +470,28 @@ ruff = ">=0.0.274" typing-extensions = "*" [package.extras] -dev = ["mypy (==1.4.1)", "pip-tools (>=6.13.0,<7.0.0)", "pytest (>=7.3.1,<8.0.0)", "pytest-asyncio (==0.21.1)", "python-lsp-jsonrpc (==1.0.0)"] +dev = ["mypy (==1.4.1)", "pip-tools (>=6.13.0,<7.0.0)", "pytest (>=7.3.1,<8.0.0)", "pytest-asyncio (==0.21.2)", "python-lsp-jsonrpc (==1.0.0)"] [[package]] name = "typing-extensions" -version = "4.9.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] name = "urllib3" -version = "2.2.1" +version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, - {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.extras] @@ -484,4 +503,4 @@ zstd = ["zstandard (>=0.18.0)"] [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "08bcb245c25ffc5aaa7232c65dc54aceed558a147b63b4c434d261171935df3e" +content-hash = "c57baf04e7fc77eacf96792ee376da41450de49c77a6322f27d285bc8a3d1a00" diff --git a/pyproject.toml b/pyproject.toml index c2b7f1c..c1077aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,13 +9,13 @@ packages = [{ "include" = "motion", from = "src" }] [tool.poetry.dependencies] python = "^3.11" -requests = "^2.31.0" -pydantic = "^2.6.1" +requests = "^2.32.0" +pydantic = "^2.9.2" [tool.poetry.group.dev.dependencies] -ruff = "^0.2.2" -ruff-lsp = "^0.0.52" -pytest = "^8.3.3" +ruff = "*" +ruff-lsp = "*" +pytest = "*" [tool.ruff] line-length = 79 From 2809fa4b1871346ca9bc53b48fd123d9206d7085 Mon Sep 17 00:00:00 2001 From: Lemi Boyce Date: Tue, 24 Sep 2024 02:17:26 -0400 Subject: [PATCH 5/5] test prs --- .github/workflows/test.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 0d2dd42..6c7a000 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -2,6 +2,8 @@ name: Test on: push: branches: [main] + pull_request: + branches: [main] jobs: test: runs-on: ubuntu-latest