From 25dc4b3261cce31baa0d4022fc7610dc03191cdb Mon Sep 17 00:00:00 2001 From: shgokita Date: Thu, 12 Dec 2024 11:58:54 +0900 Subject: [PATCH 01/12] feat: add get jobs query parameters --- backend/oas/user/openapi.yaml | 143 ++++++++++++++++++--- backend/oas/user/paths/jobs.yaml | 62 ++++++++- backend/oas/user/schemas/jobs.yaml | 64 +++++++++ backend/oqtopus_cloud/user/routers/jobs.py | 118 +++++++++++++---- backend/oqtopus_cloud/user/schemas/jobs.py | 68 ++++++++-- 5 files changed, 395 insertions(+), 60 deletions(-) diff --git a/backend/oas/user/openapi.yaml b/backend/oas/user/openapi.yaml index 910d6ea..ddf09c6 100644 --- a/backend/oas/user/openapi.yaml +++ b/backend/oas/user/openapi.yaml @@ -86,10 +86,63 @@ paths: tags: - job summary: List all quantum jobs - description: List all quantum jobs + description: |- + By default, all available job's properties are returned. Use 'fields' parameter to specify exact list of properties to get for each job. + + List of jobs can be filtered by job creation time or search text with 'startTime', 'endTime' and 'q' parameters. + + Jobs are fetched with the pagination mechanism. This can be configured with 'page' and 'perPage' parameters. Check response's 'Link' header for pagination details. operationId: listJobs security: - BearerAuth: [] + parameters: + - name: fields + in: query + description: |- + Allows to specify an exact list of job properties to fetch for a single job. Each element of the list must be a valid name of job property. + + If parameter is specified and requested job field is not defined for a job null is returned. + + If parameter is omitted all available job properties are returned. Undefined job properties (null properties) are not included in the response. + required: false + schema: + type: string + maxLength: 1024 + example: job_id,status,name + - name: startTime + in: query + description: Allows to filter the list of jobs to fetch by creation time. If specified only jobs with creation time (createdAt property) >= startTime are returned. + required: false + schema: + type: string + format: date-time + example: '2022-10-19T11:45:34+09:00' + - name: endTime + in: query + description: Allows to filter the list of jobs to fetch by to creation time. If specified only jobs with creation time (createdAt property) <= endTime are returned. + required: false + schema: + type: string + format: date-time + example: '2022-10-19T11:45:34+09:00' + - name: q + in: query + description: Allows to filter the list of jobs to fetch by job's name and description. If specified only jobs which name or description contains specified search string are returned. + required: false + schema: + type: string + maxLength: 1024 + example: Bell + - name: order + in: query + description: Specify jobs order according to creation time (createdAt property) + required: false + schema: + type: string + enum: + - DESC + - ASC + default: ASC responses: '200': description: Return a list of submitted quantum jobs @@ -98,7 +151,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/jobs.JobDef' + $ref: '#/components/schemas/jobs.GetJobsResponse' '401': description: Unauthorized content: @@ -647,7 +700,7 @@ components: { "ro_error_mitigation": "pseudo_inverse" } - jobs.JobDef: + jobs.GetJobsResponse: type: object properties: job_id: @@ -681,19 +734,12 @@ components: created_at: type: string format: date-time - example: '2022-10-19T11:45:34Z' + example: '2022-10-19T11:45:34+09:00' updated_at: type: string format: date-time - example: '2022-10-19T11:45:34Z' - required: - - job_id - - name - - job_type - - status - - device_id - - shots - - job_info + example: '2022-10-19T11:45:34+09:00' + required: [] example: job_id: 7af020f6-2e38-4d70-8cf0-4349650ea08c name: Bell State Sampling @@ -712,8 +758,8 @@ components: mitigation_info: '{ "ro_error_mitigation": "pseudo_inverse" }' shots: 1000 status: submitted - created_at: '2022-10-19T11:45:34' - updated_at: '2022-10-19T11:45:34' + created_at: '2022-10-19T11:45:34+09:00' + updated_at: '2022-10-19T11:45:34+09:00' jobs.SubmitJobRequest: type: object properties: @@ -784,6 +830,73 @@ components: type: string required: - detail + jobs.JobDef: + type: object + properties: + job_id: + $ref: '#/components/schemas/jobs.JobId' + name: + type: string + example: Bell State Sampling + description: + type: string + example: Bell State Sampling Example + job_type: + $ref: '#/components/schemas/jobs.JobType' + status: + $ref: '#/components/schemas/jobs.JobStatus' + device_id: + type: string + example: Kawasaki + shots: + type: integer + minimum: 1 + maximum: 10000000 + example: '1000' + job_info: + $ref: '#/components/schemas/jobs.JobInfo' + transpiler_info: + $ref: '#/components/schemas/jobs.TranspilerInfo' + simulator_info: + $ref: '#/components/schemas/jobs.SimulatorInfo' + mitigation_info: + $ref: '#/components/schemas/jobs.MitigationInfo' + created_at: + type: string + format: date-time + example: '2022-10-19T11:45:34Z' + updated_at: + type: string + format: date-time + example: '2022-10-19T11:45:34Z' + required: + - job_id + - name + - job_type + - status + - device_id + - shots + - job_info + example: + job_id: 7af020f6-2e38-4d70-8cf0-4349650ea08c + name: Bell State Sampling + description: Bell State Sampling Example + device_id: Kawasaki, + job_info: + desc: + job_type: estimation + code: OPENQASM 3; qubit[2] q; bit[2] c; h q[0]; cnot q[0], q[1]; c = measure q; + operator: X 0 Y 1 Z 5 I 2 + transpiled_code: '{}' + result: '{}' + reason: '' + transpiler_info: '{ "qubit_allocation": { "0": 12, "1": 16 }, "skip_transpilation": false, "seed_transpilation": 873 },' + simulator_info: '{ "n_qubits": 5, "n_nodes": 12, "n_per_node": 2, "seed_simulation": 39058567, "simulation_opt": { "optimization_method": "light", "optimization_block_size": 1, "optimization_swap_level": 1 } }' + mitigation_info: '{ "ro_error_mitigation": "pseudo_inverse" }' + shots: 1000 + status: submitted + created_at: '2022-10-19T11:45:34' + updated_at: '2022-10-19T11:45:34' success.SuccessResponse: type: object properties: diff --git a/backend/oas/user/paths/jobs.yaml b/backend/oas/user/paths/jobs.yaml index bc24580..c8336d1 100644 --- a/backend/oas/user/paths/jobs.yaml +++ b/backend/oas/user/paths/jobs.yaml @@ -3,10 +3,66 @@ jobs: tags: - job summary: "List all quantum jobs" - description: "List all quantum jobs" + description: |- + By default, all available job's properties are returned. Use 'fields' parameter to specify exact list of properties to get for each job. + + List of jobs can be filtered by job creation time or search text with 'startTime', 'endTime' and 'q' parameters. + + Jobs are fetched with the pagination mechanism. This can be configured with 'page' and 'perPage' parameters. Check response's 'Link' header for pagination details. operationId: listJobs security: - BearerAuth: [] + parameters: + - name: fields + in: query + description: |- + Allows to specify an exact list of job properties to fetch for a single job. Each element of the list must be a valid name of job property. + + If parameter is specified and requested job field is not defined for a job null is returned. + + If parameter is omitted all available job properties are returned. Undefined job properties (null properties) are not included in the response. + required: false + schema: + type: string + maxLength: 1024 + example: "job_id,status,name" + - name: startTime + in: query + description: |- + Allows to filter the list of jobs to fetch by creation time. If specified only jobs with creation time (createdAt property) >= startTime are returned. + required: false + schema: + type: string + format: date-time + example: "2022-10-19T11:45:34+09:00" + - name: endTime + in: query + description: |- + Allows to filter the list of jobs to fetch by to creation time. If specified only jobs with creation time (createdAt property) <= endTime are returned. + required: false + schema: + type: string + format: date-time + example: "2022-10-19T11:45:34+09:00" + - name: q + in: query + description: |- + Allows to filter the list of jobs to fetch by job's name and description. If specified only jobs which name or description contains specified search string are returned. + required: false + schema: + type: string + maxLength: 1024 + example: "Bell" + - name: order + in: query + description: |- + Specify jobs order according to creation time (createdAt property) + required: false + schema: + type: string + enum: + ["DESC", "ASC"] + default: "ASC" responses: "200": description: "Return a list of submitted quantum jobs" @@ -15,13 +71,13 @@ jobs: schema: type: array items: - $ref: "../schemas/jobs.yaml#/jobs.JobDef" + $ref: "../schemas/jobs.yaml#/jobs.GetJobsResponse" "401": description: Unauthorized content: application/json: schema: - $ref: "../schemas/error.yaml#/error.UnauthorizedError" + $ref: '../schemas/error.yaml#/error.UnauthorizedError' example: detail: Unauthorized post: diff --git a/backend/oas/user/schemas/jobs.yaml b/backend/oas/user/schemas/jobs.yaml index cf70524..88e8610 100644 --- a/backend/oas/user/schemas/jobs.yaml +++ b/backend/oas/user/schemas/jobs.yaml @@ -280,3 +280,67 @@ jobs.SubmitJobRequest: - device_id - shots - job_info + +jobs.GetJobsResponse: + type: object + properties: + job_id: + $ref: "#/jobs.JobId" + name: + type: string + example: Bell State Sampling + description: + type: string + example: Bell State Sampling Example + job_type: + $ref: "#/jobs.JobType" + status: + $ref: "#/jobs.JobStatus" + device_id: + type: string + example: "Kawasaki" + shots: + type: integer + minimum: 1 + maximum: 1e7 + example: "1000" + job_info: + $ref: "#/jobs.JobInfo" + transpiler_info: + $ref: "#/jobs.TranspilerInfo" + simulator_info: + $ref: "#/jobs.SimulatorInfo" + mitigation_info: + $ref: "#/jobs.MitigationInfo" + created_at: + type: string + format: date-time + example: 2022-10-19T11:45:34+09:00 + updated_at: + type: string + format: date-time + example: 2022-10-19T11:45:34+09:00 + required: [] + example: + job_id: 7af020f6-2e38-4d70-8cf0-4349650ea08c + name: Bell State Sampling + description: Bell State Sampling Example + device_id: Kawasaki, + job_info: + desc: + job_type: estimation + code: OPENQASM 3; qubit[2] q; bit[2] c; h q[0]; cnot q[0], q[1]; c = measure q; + operator: X 0 Y 1 Z 5 I 2 + transpiled_code: "{}" + result: "{}" + reason: "" + transpiler_info: >- + { "qubit_allocation": { "0": 12, "1": 16 }, "skip_transpilation": false, "seed_transpilation": 873 }, + simulator_info: >- + { "n_qubits": 5, "n_nodes": 12, "n_per_node": 2, "seed_simulation": 39058567, "simulation_opt": { "optimization_method": "light", "optimization_block_size": 1, "optimization_swap_level": 1 } } + mitigation_info: >- + { "ro_error_mitigation": "pseudo_inverse" } + shots: 1000 + status: submitted + created_at: 2022-10-19T11:45:34+09:00 + updated_at: 2022-10-19T11:45:34+09:00 diff --git a/backend/oqtopus_cloud/user/routers/jobs.py b/backend/oqtopus_cloud/user/routers/jobs.py index 6d1a383..fb04fb3 100644 --- a/backend/oqtopus_cloud/user/routers/jobs.py +++ b/backend/oqtopus_cloud/user/routers/jobs.py @@ -1,13 +1,15 @@ import json from datetime import datetime -from typing import Any +from typing import Any, Optional from fastapi import ( APIRouter, Depends, ) from fastapi import Request as Event -from sqlalchemy import select +from fastapi_pagination import Page, add_pagination, paginate +from sqlalchemy import asc, desc, or_, select +from sqlalchemy.engine.row import Row from sqlalchemy.orm import ( Session, ) @@ -28,6 +30,7 @@ NotFoundErrorResponse, ) from oqtopus_cloud.user.schemas.jobs import ( + GetJobsResponse, GetJobStatusResponse, JobDef, JobInfo, @@ -53,27 +56,68 @@ def __init__(self, detail: str): @router.get( "/jobs", - response_model=list[JobDef], + response_model=list[GetJobsResponse], responses={500: {"model": Detail}}, ) @tracer.capture_method def get_jobs( event: Event, + fields: Optional[str] = None, + startTime: Optional[str] = None, + endTime: Optional[str] = None, + q: Optional[str] = None, + order: Optional[str] = None, db: Session = Depends(get_db), -) -> list[JobDef] | ErrorResponse: +) -> list[GetJobsResponse] | ErrorResponse: try: owner = event.state.owner logger.info("invoked!", extra={"owner": owner}) - stmt = select(Job).filter(Job.owner == owner).order_by(Job.created_at) - jobs = db.scalars(stmt).all() - results: list[JobDef] = [] + + # Order Control + if order == "ASC" or order is None: + arg_order = asc(Job.created_at) + elif order == "DESC": + arg_order = desc(Job.created_at) + else: + arg_order = asc(Job.created_at) + + # Fields Control + if fields is not None: + fields_list = fields.split(",") + MAP_SCHEMA_TO_MODEL = {v: k for k, v in MAP_MODEL_TO_SCHEMA.items()} + converted_fields_list = [ + MAP_SCHEMA_TO_MODEL[field] for field in fields_list + ] + columns = [getattr(Job, field) for field in converted_fields_list] + arg_select = columns + else: + arg_select = [Job] + + stmt = select(*arg_select).filter(Job.owner == owner).order_by(arg_order) + + # Filterling Jobs + if startTime is not None: + stime = datetime.fromisoformat(startTime).astimezone(jst) + stmt = stmt.filter(Job.created_at >= stime) + if endTime is not None: + etime = datetime.fromisoformat(endTime).astimezone(jst) + stmt = stmt.filter(Job.created_at <= etime) + if q is not None: + stmt = stmt.filter(or_(Job.name.contains(q), Job.description.contains(q))) + + if fields is not None: + jobs = db.execute(stmt).all() + else: + jobs = db.scalars(stmt).all() + + results = [GetJobsResponse] for job_model, job in [(job, model_to_schema(job)) for job in jobs]: if job is None: logger.warning(f"Failed to encode job model to schema: {job_model.id}") else: + logger.info(f"job_info:{job}") results.append(job) return results - except Exception as e: logger.info(f"error: {str(e)}") return InternalServerErrorResponse(detail=str(e)) @@ -262,7 +306,7 @@ def cancel_job( MAP_MODEL_TO_SCHEMA = { - "id": "id", + "id": "job_id", "owner": "owner", "status": "status", "name": "name", @@ -286,23 +330,41 @@ def decode_job_info(j: Any) -> JobInfo | None: return None -def model_to_schema(model: Job) -> JobDef | None: - job_info = decode_job_info(json.loads(model.job_info)) - if job_info is None: +def model_to_schema(model: Job | Row) -> JobDef | GetJobsResponse | None: + if hasattr(model, "job_info"): + job_info = decode_job_info(json.loads(model.job_info)) + else: + job_info = None + + if type(model) is Job and job_info is not None: + return JobDef( + job_id=model.id, + name=model.name, + description=model.description, + device_id=model.device_id, + shots=model.shots, + job_type=JobType(job_info.desc.job_type), + job_info=job_info, + status=JobStatus(model.status), + transpiler_info=model.transpiler_info, + mitigation_info=model.mitigation_info, + simulator_info=model.simulator_info, + created_at=model.created_at, + updated_at=model.updated_at, + ) + elif type(model) is Row: + dict_model = {} + for k, v in model._mapping.items(): + if k == "id": + dict_model["job_id"] = v + elif k == "job_type": + dict_model[k] = JobType(v) + elif k == "job_info": + dict_model[k] = job_info + elif k == "status": + dict_model[k] = JobStatus(v) + else: + dict_model[k] = v + return GetJobsResponse(**dict_model) + else: return None - - return JobDef( - job_id=model.id, - name=model.name, - description=model.description, - device_id=model.device_id, - shots=model.shots, - job_type=JobType(job_info.desc.job_type), - job_info=job_info, - status=JobStatus(model.status), - transpiler_info=model.transpiler_info, - mitigation_info=model.mitigation_info, - simulator_info=model.simulator_info, - created_at=model.created_at, - updated_at=model.updated_at, - ) diff --git a/backend/oqtopus_cloud/user/schemas/jobs.py b/backend/oqtopus_cloud/user/schemas/jobs.py index d8a5fd3..05ca5b7 100644 --- a/backend/oqtopus_cloud/user/schemas/jobs.py +++ b/backend/oqtopus_cloud/user/schemas/jobs.py @@ -80,17 +80,19 @@ class JobInfo(BaseModel): """ -class JobDef(BaseModel): - job_id: Annotated[str, Field(examples=["7af020f6-2e38-4d70-8cf0-4349650ea08c"])] - name: Annotated[str, Field(examples=["Bell State Sampling"])] +class GetJobsResponse(BaseModel): + job_id: Annotated[ + str | None, Field(examples=["7af020f6-2e38-4d70-8cf0-4349650ea08c"]) + ] = None + name: Annotated[str | None, Field(examples=["Bell State Sampling"])] = None description: Annotated[ str | None, Field(examples=["Bell State Sampling Example"]) ] = None - job_type: JobType - status: JobStatus - device_id: Annotated[str, Field(examples=["Kawasaki"])] - shots: Annotated[int, Field(examples=["1000"], ge=1, le=10000000)] - job_info: JobInfo + job_type: JobType | None = None + status: JobStatus | None = None + device_id: Annotated[str | None, Field(examples=["Kawasaki"])] = None + shots: Annotated[int | None, Field(examples=["1000"], ge=1, le=10000000)] = None + job_info: JobInfo | None = None transpiler_info: Annotated[ str | None, Field( @@ -110,12 +112,12 @@ class JobDef(BaseModel): mitigation_info: Annotated[ str | None, Field(examples=['{\n "ro_error_mitigation": "pseudo_inverse"\n}']) ] = None - created_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34Z"])] = ( - None - ) - updated_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34Z"])] = ( - None - ) + created_at: Annotated[ + datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) + ] = None + updated_at: Annotated[ + datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) + ] = None class SubmitJobRequest(BaseModel): @@ -159,6 +161,44 @@ class SubmitJobResponse(BaseModel): job_id: Annotated[str, Field(examples=["7af020f6-2e38-4d70-8cf0-4349650ea08c"])] +class JobDef(BaseModel): + job_id: Annotated[str, Field(examples=["7af020f6-2e38-4d70-8cf0-4349650ea08c"])] + name: Annotated[str, Field(examples=["Bell State Sampling"])] + description: Annotated[ + str | None, Field(examples=["Bell State Sampling Example"]) + ] = None + job_type: JobType + status: JobStatus + device_id: Annotated[str, Field(examples=["Kawasaki"])] + shots: Annotated[int, Field(examples=["1000"], ge=1, le=10000000)] + job_info: JobInfo + transpiler_info: Annotated[ + str | None, + Field( + examples=[ + '{\n "qubit_allocation": {\n "0": 12,\n "1": 16\n },\n "skip_transpilation": false,\n "seed_transpilation": 873\n}' + ] + ), + ] = None + simulator_info: Annotated[ + str | None, + Field( + examples=[ + '{\n "n_qubits": 5,\n "n_nodes": 12,\n "n_per_node": 2,\n "seed_simulation": 39058567,\n "simulation_opt": {\n "optimization_method": "light",\n "optimization_block_size": 1,\n "optimization_swap_level": 1\n }\n}' + ] + ), + ] = None + mitigation_info: Annotated[ + str | None, Field(examples=['{\n "ro_error_mitigation": "pseudo_inverse"\n}']) + ] = None + created_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34Z"])] = ( + None + ) + updated_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34Z"])] = ( + None + ) + + class GetJobStatusResponse(BaseModel): """ job status From 196038ebb3c97d8d43ba9466dfa68f077481f203 Mon Sep 17 00:00:00 2001 From: shgokita Date: Thu, 12 Dec 2024 11:59:10 +0900 Subject: [PATCH 02/12] tests: add get jobs testing --- .../oqtopus_cloud/user/routers/test_jobs.py | 339 +++++++++++++++++- 1 file changed, 328 insertions(+), 11 deletions(-) diff --git a/backend/tests/oqtopus_cloud/user/routers/test_jobs.py b/backend/tests/oqtopus_cloud/user/routers/test_jobs.py index f04290f..436e302 100644 --- a/backend/tests/oqtopus_cloud/user/routers/test_jobs.py +++ b/backend/tests/oqtopus_cloud/user/routers/test_jobs.py @@ -13,6 +13,7 @@ # model_to_schema, # ) from oqtopus_cloud.user.schemas.jobs import ( + GetJobsResponse, JobDef, JobInfo, JobInfoSampling, @@ -27,12 +28,12 @@ client = TestClient(app) -def _get_model() -> Job: - mode_dict = { - "id": "testjob1id", +def _get_model(n: int) -> Job: + model_dict = { + "id": f"testjob{n}id", "owner": "admin", - "name": "testjob1", - "description": "test job 1", + "name": f"testjob{n}", + "description": f"test job {n}", "device_id": "Kawasaki", "job_type": "sampling", "job_info": json.dumps( @@ -50,9 +51,9 @@ def _get_model() -> Job: ), "status": "submitted", "shots": 1000, - "created_at": datetime(2024, 3, 4, 12, 34, 56), + "created_at": datetime(2024, 3, 3 + n, 12, 34, 56), } - return Job(**mode_dict) + return Job(**model_dict) def test_get_job_404( @@ -69,6 +70,322 @@ def test_get_job_404( assert response.json() == {"detail": "job not found with the given id"} +def test_get_jobs_simple( + test_db, +): + """_summary_ + Simple GET /jobs tests + """ + + test_db.flush() + test_db.add(_get_model(1)) + test_db.add(_get_model(2)) + test_db.commit() + + response = client.get("/jobs") + adapter = TypeAdapter(List[JobDef]) + actual = adapter.validate_python(response.json()) + + expect = [ + JobDef( + job_id="testjob1id", + name="testjob1", + description="test job 1", + device_id="Kawasaki", + job_type=JobType.sampling, + job_info=JobInfo( + desc=JobInfoSampling(job_type="sampling", code="code"), + ), + transpiler_info=json.dumps({"this_is": "transpiler_info"}), + simulator_info=json.dumps({"this_is": "simulator_info"}), + mitigation_info=json.dumps( + {"field1": "value1", "field2": "value2", "field3": "value3"} + ), + status=JobStatus.submitted, + shots=1000, + created_at=datetime(2024, 3, 4, 12, 34, 56), + updated_at=None, + ), + JobDef( + job_id="testjob2id", + name="testjob2", + description="test job 2", + device_id="Kawasaki", + job_type=JobType.sampling, + job_info=JobInfo( + desc=JobInfoSampling(job_type="sampling", code="code"), + ), + transpiler_info=json.dumps({"this_is": "transpiler_info"}), + simulator_info=json.dumps({"this_is": "simulator_info"}), + mitigation_info=json.dumps( + {"field1": "value1", "field2": "value2", "field3": "value3"} + ), + status=JobStatus.submitted, + shots=1000, + created_at=datetime(2024, 3, 5, 12, 34, 56), + updated_at=None, + ), + ] + + assert response.status_code == 200 + assert actual == expect + + +def test_get_jobs_filtering_fields( + test_db, +): + """_summary_ + GET job_id, status and name by ASC order + """ + + test_db.flush() + test_db.add(_get_model(1)) + test_db.add(_get_model(2)) + test_db.commit() + + response = client.get("/jobs?fields=job_id%2Cstatus%2Cname&order=ASC") + adapter = TypeAdapter(List[GetJobsResponse]) + actual = adapter.validate_python(response.json()) + expect = [ + GetJobsResponse( + job_id="testjob1id", + name="testjob1", + status=JobStatus.submitted, + ), + GetJobsResponse( + job_id="testjob2id", + name="testjob2", + status=JobStatus.submitted, + ), + ] + + assert response.status_code == 200 + assert actual == expect + + +def test_get_jobs_filtering_startTime( + test_db, +): + """_summary_ + filterling startime, expect only testjob2 will be got + """ + + test_db.flush() + test_db.add(_get_model(1)) + test_db.add(_get_model(2)) + test_db.commit() + + response = client.get("/jobs?startTime=2024-03-05T07%3A04%3A24%2B09%3A00&order=ASC") + adapter = TypeAdapter(List[GetJobsResponse]) + actual = adapter.validate_python(response.json()) + expect = [ + GetJobsResponse( + job_id="testjob2id", + name="testjob2", + description="test job 2", + device_id="Kawasaki", + job_type=JobType.sampling, + job_info=JobInfo( + desc=JobInfoSampling(job_type="sampling", code="code"), + ), + transpiler_info=json.dumps({"this_is": "transpiler_info"}), + simulator_info=json.dumps({"this_is": "simulator_info"}), + mitigation_info=json.dumps( + {"field1": "value1", "field2": "value2", "field3": "value3"} + ), + status=JobStatus.submitted, + shots=1000, + created_at=datetime(2024, 3, 5, 12, 34, 56), + updated_at=None, + ), + ] + + assert response.status_code == 200 + assert actual == expect + + +def test_get_jobs_filtering_endTime( + test_db, +): + """_summary_ + filterling endtime, expect only testjob1 will be got + """ + + test_db.flush() + test_db.add(_get_model(1)) + test_db.add(_get_model(2)) + test_db.commit() + + response = client.get("/jobs?endTime=2024-03-05T07%3A04%3A24%2B09%3A00&order=ASC") + adapter = TypeAdapter(List[GetJobsResponse]) + actual = adapter.validate_python(response.json()) + expect = [ + GetJobsResponse( + job_id="testjob1id", + name="testjob1", + description="test job 1", + device_id="Kawasaki", + job_type=JobType.sampling, + job_info=JobInfo( + desc=JobInfoSampling(job_type="sampling", code="code"), + ), + transpiler_info=json.dumps({"this_is": "transpiler_info"}), + simulator_info=json.dumps({"this_is": "simulator_info"}), + mitigation_info=json.dumps( + {"field1": "value1", "field2": "value2", "field3": "value3"} + ), + status=JobStatus.submitted, + shots=1000, + created_at=datetime(2024, 3, 4, 12, 34, 56), + updated_at=None, + ), + ] + + assert response.status_code == 200 + assert actual == expect + + +def test_get_jobs_filtering_search_string( + test_db, +): + """_summary_ + filterling search string "1", expect only testjob1 will be got + """ + + test_db.flush() + test_db.add(_get_model(1)) + test_db.add(_get_model(2)) + test_db.commit() + + response = client.get("/jobs?q=1&order=ASC") + adapter = TypeAdapter(List[GetJobsResponse]) + actual = adapter.validate_python(response.json()) + expect = [ + GetJobsResponse( + job_id="testjob1id", + name="testjob1", + description="test job 1", + device_id="Kawasaki", + job_type=JobType.sampling, + job_info=JobInfo( + desc=JobInfoSampling(job_type="sampling", code="code"), + ), + transpiler_info=json.dumps({"this_is": "transpiler_info"}), + simulator_info=json.dumps({"this_is": "simulator_info"}), + mitigation_info=json.dumps( + {"field1": "value1", "field2": "value2", "field3": "value3"} + ), + status=JobStatus.submitted, + shots=1000, + created_at=datetime(2024, 3, 4, 12, 34, 56), + updated_at=None, + ), + ] + + assert response.status_code == 200 + assert actual == expect + + +def test_get_jobs_desc_order( + test_db, +): + """_summary_ + expect testjob2 and testjob1 will be got in this order + """ + + test_db.flush() + test_db.add(_get_model(1)) + test_db.add(_get_model(2)) + test_db.commit() + + response = client.get("/jobs?order=DESC") + adapter = TypeAdapter(List[GetJobsResponse]) + actual = adapter.validate_python(response.json()) + expect = [ + GetJobsResponse( + job_id="testjob2id", + name="testjob2", + description="test job 2", + device_id="Kawasaki", + job_type=JobType.sampling, + job_info=JobInfo( + desc=JobInfoSampling(job_type="sampling", code="code"), + ), + transpiler_info=json.dumps({"this_is": "transpiler_info"}), + simulator_info=json.dumps({"this_is": "simulator_info"}), + mitigation_info=json.dumps( + {"field1": "value1", "field2": "value2", "field3": "value3"} + ), + status=JobStatus.submitted, + shots=1000, + created_at=datetime(2024, 3, 5, 12, 34, 56), + updated_at=None, + ), + GetJobsResponse( + job_id="testjob1id", + name="testjob1", + description="test job 1", + device_id="Kawasaki", + job_type=JobType.sampling, + job_info=JobInfo( + desc=JobInfoSampling(job_type="sampling", code="code"), + ), + transpiler_info=json.dumps({"this_is": "transpiler_info"}), + simulator_info=json.dumps({"this_is": "simulator_info"}), + mitigation_info=json.dumps( + {"field1": "value1", "field2": "value2", "field3": "value3"} + ), + status=JobStatus.submitted, + shots=1000, + created_at=datetime(2024, 3, 4, 12, 34, 56), + updated_at=None, + ), + ] + + assert response.status_code == 200 + assert actual == expect + + +def test_get_jobs_all_parameters( + test_db, +): + """_summary_ + filtering starttime, endtime, search string, and desc order, expect only testjob3 and testjob2 will be got in this order + """ + + test_db.flush() + test_db.add(_get_model(1)) + test_db.add(_get_model(2)) + test_db.add(_get_model(3)) + test_db.add(_get_model(4)) + test_db.commit() + + response = client.get( + "/jobs?fields=job_id%2Cdescription%2Cjob_info&startTime=2024-03-04T16%3A12%3A29%2B09%3A00&endTime=2024-03-06T16%3A12%3A29%2B09%3A00&q=test&order=DESC" + ) + adapter = TypeAdapter(List[GetJobsResponse]) + actual = adapter.validate_python(response.json()) + expect = [ + GetJobsResponse( + job_id="testjob3id", + description="test job 3", + job_info=JobInfo( + desc=JobInfoSampling(job_type="sampling", code="code"), + ), + ), + GetJobsResponse( + job_id="testjob2id", + description="test job 2", + job_info=JobInfo( + desc=JobInfoSampling(job_type="sampling", code="code"), + ), + ), + ] + + assert response.status_code == 200 + assert actual == expect + + def test_job_sortedness(test_db): def mk_job(n: int) -> SubmitJobRequest: return SubmitJobRequest( @@ -106,7 +423,7 @@ def test_get_jobs_handler( """ test_db.flush() - test_db.add(_get_model()) + test_db.add(_get_model(1)) test_db.commit() response = client.get("/jobs") @@ -149,16 +466,16 @@ def test_get_get(test_db): """ test_db.flush() - test_db.add(_get_model()) + test_db.add(_get_model(1)) test_db.commit() sql = select(Job).order_by(Job.created_at) - resp1 = client.get(f"/jobs/{_get_model().id}") + resp1 = client.get(f"/jobs/{_get_model(1).id}") assert resp1.status_code == 200 before_db = test_db.execute(sql).scalars().all() - resp2 = client.get(f"/jobs/{_get_model().id}") + resp2 = client.get(f"/jobs/{_get_model(1).id}") assert resp2.status_code == 200 after_db = test_db.execute(sql).scalars().all() From 2d6495a48ce462c40376d519eb8a51cc27085362 Mon Sep 17 00:00:00 2001 From: shgokita Date: Thu, 12 Dec 2024 17:00:14 +0900 Subject: [PATCH 03/12] feat: add pagination --- backend/oqtopus_cloud/user/lambda_function.py | 3 +- backend/oqtopus_cloud/user/routers/jobs.py | 22 +++++++---- .../oqtopus_cloud/user/routers/test_jobs.py | 39 ++++++++++++++++--- poetry.lock | 36 ++++++++++++++++- pyproject.toml | 5 ++- 5 files changed, 88 insertions(+), 17 deletions(-) diff --git a/backend/oqtopus_cloud/user/lambda_function.py b/backend/oqtopus_cloud/user/lambda_function.py index 3a9862c..b13143f 100644 --- a/backend/oqtopus_cloud/user/lambda_function.py +++ b/backend/oqtopus_cloud/user/lambda_function.py @@ -7,6 +7,7 @@ import setuptools._distutils.util from fastapi import FastAPI +from fastapi_pagination import add_pagination from mangum import ( Mangum, ) @@ -21,7 +22,7 @@ jobs as job_router, ) -app: FastAPI = FastAPI() +app: FastAPI = add_pagination(FastAPI()) app.add_middleware(CustomMiddleware) diff --git a/backend/oqtopus_cloud/user/routers/jobs.py b/backend/oqtopus_cloud/user/routers/jobs.py index fb04fb3..8524e39 100644 --- a/backend/oqtopus_cloud/user/routers/jobs.py +++ b/backend/oqtopus_cloud/user/routers/jobs.py @@ -7,7 +7,8 @@ Depends, ) from fastapi import Request as Event -from fastapi_pagination import Page, add_pagination, paginate +from fastapi_pagination import Page, Params, set_page, set_params +from fastapi_pagination.ext.sqlalchemy import paginate from sqlalchemy import asc, desc, or_, select from sqlalchemy.engine.row import Row from sqlalchemy.orm import ( @@ -67,6 +68,8 @@ def get_jobs( endTime: Optional[str] = None, q: Optional[str] = None, order: Optional[str] = None, + size: Optional[str] = None, + page: Optional[str] = None, db: Session = Depends(get_db), ) -> list[GetJobsResponse] | ErrorResponse: try: @@ -105,17 +108,20 @@ def get_jobs( if q is not None: stmt = stmt.filter(or_(Job.name.contains(q), Job.description.contains(q))) - if fields is not None: - jobs = db.execute(stmt).all() - else: - jobs = db.scalars(stmt).all() + set_params( + Params( + size=int(size) if size is not None else 100, + page=int(page) if page is not None else 1, + ) + ) + set_page(Page[Job | Row]) + jobs = paginate(db, stmt) - results = [GetJobsResponse] - for job_model, job in [(job, model_to_schema(job)) for job in jobs]: + results = [] + for job_model, job in [(job, model_to_schema(job)) for job in jobs.items]: if job is None: logger.warning(f"Failed to encode job model to schema: {job_model.id}") else: - logger.info(f"job_info:{job}") results.append(job) return results except Exception as e: diff --git a/backend/tests/oqtopus_cloud/user/routers/test_jobs.py b/backend/tests/oqtopus_cloud/user/routers/test_jobs.py index 436e302..892f307 100644 --- a/backend/tests/oqtopus_cloud/user/routers/test_jobs.py +++ b/backend/tests/oqtopus_cloud/user/routers/test_jobs.py @@ -346,6 +346,37 @@ def test_get_jobs_desc_order( assert actual == expect +def test_get_jobs_pagination( + test_db, +): + """_summary_ + expect testjob2 and testjob1 will be got in this order + """ + + test_db.flush() + for i in range(1, 10): + test_db.add(_get_model(i)) + test_db.commit() + + response = client.get("/jobs?page=3&size=3&fields=job_id") + adapter = TypeAdapter(List[GetJobsResponse]) + actual = adapter.validate_python(response.json()) + expect = [ + GetJobsResponse( + job_id="testjob7id", + ), + GetJobsResponse( + job_id="testjob8id", + ), + GetJobsResponse( + job_id="testjob9id", + ), + ] + + assert response.status_code == 200 + assert actual == expect + + def test_get_jobs_all_parameters( test_db, ): @@ -354,14 +385,12 @@ def test_get_jobs_all_parameters( """ test_db.flush() - test_db.add(_get_model(1)) - test_db.add(_get_model(2)) - test_db.add(_get_model(3)) - test_db.add(_get_model(4)) + for i in range(1, 10): + test_db.add(_get_model(i)) test_db.commit() response = client.get( - "/jobs?fields=job_id%2Cdescription%2Cjob_info&startTime=2024-03-04T16%3A12%3A29%2B09%3A00&endTime=2024-03-06T16%3A12%3A29%2B09%3A00&q=test&order=DESC" + "/jobs?fields=job_id%2Cdescription%2Cjob_info&startTime=2024-03-04T16%3A12%3A29%2B09%3A00&endTime=2024-03-08T16%3A12%3A29%2B09%3A00&q=test&order=DESC&page=2&size=2" ) adapter = TypeAdapter(List[GetJobsResponse]) actual = adapter.validate_python(response.json()) diff --git a/poetry.lock b/poetry.lock index c737e75..a859898 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.4 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" @@ -1105,6 +1105,38 @@ typing-extensions = ">=4.8.0" [package.extras] all = ["email_validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +[[package]] +name = "fastapi-pagination" +version = "0.12.32" +description = "FastAPI pagination" +optional = false +python-versions = "<4.0,>=3.8" +files = [ + {file = "fastapi_pagination-0.12.32-py3-none-any.whl", hash = "sha256:38e7e72abf252cbebbc1beff9081e4929762756c04959c471b2a5866bb7f0aaf"}, + {file = "fastapi_pagination-0.12.32.tar.gz", hash = "sha256:b808b5b8af493c51d96ae0091b60532b25688cbca1350f39cb72f10d4d69a6ab"}, +] + +[package.dependencies] +pydantic = ">=1.9.1" +typing-extensions = ">=4.8.0,<5.0.0" + +[package.extras] +all = ["SQLAlchemy (>=1.3.20)", "asyncpg (>=0.24.0)", "beanie (>=1.25.0)", "bunnet (>=1.1.0,<2.0.0)", "databases (>=0.6.0)", "django (<5.0.0)", "mongoengine (>=0.23.1,<0.30.0)", "motor (>=2.5.1,<4.0.0)", "orm (>=0.3.1)", "ormar (>=0.11.2)", "piccolo (>=0.89,<0.122)", "pony (>=0.7.16,<0.8.0)", "scylla-driver (>=3.25.6,<4.0.0)", "sqlakeyset (>=2.0.1680321678,<3.0.0)", "sqlmodel (>=0.0.8,<0.0.15)", "tortoise-orm (>=0.16.18,!=0.21.0,<0.22.0)"] +asyncpg = ["SQLAlchemy (>=1.3.20)", "asyncpg (>=0.24.0)"] +beanie = ["beanie (>=1.25.0)"] +bunnet = ["bunnet (>=1.1.0,<2.0.0)"] +databases = ["databases (>=0.6.0)"] +django = ["databases (>=0.6.0)", "django (<5.0.0)"] +mongoengine = ["mongoengine (>=0.23.1,<0.30.0)"] +motor = ["motor (>=2.5.1,<4.0.0)"] +orm = ["databases (>=0.6.0)", "orm (>=0.3.1)"] +ormar = ["ormar (>=0.11.2)"] +piccolo = ["piccolo (>=0.89,<0.122)"] +scylla-driver = ["scylla-driver (>=3.25.6,<4.0.0)"] +sqlalchemy = ["SQLAlchemy (>=1.3.20)", "sqlakeyset (>=2.0.1680321678,<3.0.0)"] +sqlmodel = ["sqlakeyset (>=2.0.1680321678,<3.0.0)", "sqlmodel (>=0.0.8,<0.0.15)"] +tortoise = ["tortoise-orm (>=0.16.18,!=0.21.0,<0.22.0)"] + [[package]] name = "genson" version = "1.3.0" @@ -2755,4 +2787,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.12.3" -content-hash = "6ed405dc18e3eedd3a93c2771aeab95d6f0ee3080c71519c8b58dd26a31c1f4d" +content-hash = "9b4dec54845d7d6b7f0f3a0e88022c977140f2042cca5975d6c756b1c87d7381" diff --git a/pyproject.toml b/pyproject.toml index 397c153..25cb80f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,8 @@ setuptools = "^75.1.0" types-setuptools = "^75.1.0.20240917" uuid7 = "^0.1.0" uuid-v7 = "^1.0.0" +pytest-env = "^1.1.5" +fastapi-pagination = "^0.12.32" [tool.poetry.group.dev.dependencies] @@ -33,7 +35,6 @@ datamodel-code-generator = "^0.26.2" requests = "^2.31.0" pytest = "^8.1.1" pytest-cov = "^5.0.0" -pytest-env = "^1.1.3" mypy = "^1.9.0" case-converter = "^1.1.0" pyyaml = "^6.0.1" @@ -62,6 +63,8 @@ DB_USER="admin" DB_PASS="password" DB_HOST="localhost" ENV="local" +POWERTOOLS_METRICS_NAMESPACE="user-api" +POWERTOOLS_SERVICE_NAME="user-api" [tool.pytest.ini_options] testpaths = ["backend/tests"] From 53d46daad7d34b72a00ac2ae85506c41b5dc9802 Mon Sep 17 00:00:00 2001 From: shgokita Date: Thu, 12 Dec 2024 17:07:46 +0900 Subject: [PATCH 04/12] chore: change get_job response type for lint check --- backend/oqtopus_cloud/user/routers/jobs.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/oqtopus_cloud/user/routers/jobs.py b/backend/oqtopus_cloud/user/routers/jobs.py index 8524e39..569f71f 100644 --- a/backend/oqtopus_cloud/user/routers/jobs.py +++ b/backend/oqtopus_cloud/user/routers/jobs.py @@ -1,6 +1,6 @@ import json from datetime import datetime -from typing import Any, Optional +from typing import Any, Optional, Union from fastapi import ( APIRouter, @@ -57,7 +57,7 @@ def __init__(self, detail: str): @router.get( "/jobs", - response_model=list[GetJobsResponse], + response_model=list[Union[GetJobsResponse, JobDef]], responses={500: {"model": Detail}}, ) @tracer.capture_method @@ -71,7 +71,7 @@ def get_jobs( size: Optional[str] = None, page: Optional[str] = None, db: Session = Depends(get_db), -) -> list[GetJobsResponse] | ErrorResponse: +) -> list[Union[GetJobsResponse, JobDef]] | ErrorResponse: try: owner = event.state.owner logger.info("invoked!", extra={"owner": owner}) @@ -201,7 +201,7 @@ def get_job( event: Event, job_id: str, db: Session = Depends(get_db), -) -> JobDef | ErrorResponse: +) -> Union[JobDef, GetJobsResponse] | ErrorResponse: try: owner = event.state.owner logger.info("invoked!", extra={"owner": owner, "job_id": job_id}) @@ -336,7 +336,7 @@ def decode_job_info(j: Any) -> JobInfo | None: return None -def model_to_schema(model: Job | Row) -> JobDef | GetJobsResponse | None: +def model_to_schema(model: Union[Job, Row]) -> Union[JobDef, GetJobsResponse] | None: if hasattr(model, "job_info"): job_info = decode_job_info(json.loads(model.job_info)) else: From 4986aac8736b9565b842efbbd4558f21316f1110 Mon Sep 17 00:00:00 2001 From: shgokita Date: Thu, 12 Dec 2024 17:19:12 +0900 Subject: [PATCH 05/12] chore: add pagination query parameters to oas --- backend/oas/user/openapi.yaml | 20 ++++++++++++++++++++ backend/oas/user/paths/jobs.yaml | 21 +++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/backend/oas/user/openapi.yaml b/backend/oas/user/openapi.yaml index ddf09c6..8fbb79d 100644 --- a/backend/oas/user/openapi.yaml +++ b/backend/oas/user/openapi.yaml @@ -133,6 +133,26 @@ paths: type: string maxLength: 1024 example: Bell + - name: page + in: query + description: |- + Set jobs list page number to fetch. + If requested page number exceeds number of all pages last page is returned. + required: false + schema: + type: integer + minimum: 1 + maximum: 4294967295 + default: 1 + - name: size + in: query + description: Configure number of jobs per page + required: false + schema: + type: integer + minimum: 1 + maximum: 65535 + default: 10 - name: order in: query description: Specify jobs order according to creation time (createdAt property) diff --git a/backend/oas/user/paths/jobs.yaml b/backend/oas/user/paths/jobs.yaml index c8336d1..fe28dcd 100644 --- a/backend/oas/user/paths/jobs.yaml +++ b/backend/oas/user/paths/jobs.yaml @@ -53,6 +53,27 @@ jobs: type: string maxLength: 1024 example: "Bell" + - name: page + in: query + description: |- + Set jobs list page number to fetch. + If requested page number exceeds number of all pages last page is returned. + required: false + schema: + type: integer + minimum: 1 + maximum: 4294967295 + default: 1 + - name: size + in: query + description: |- + Configure number of jobs per page + required: false + schema: + type: integer + minimum: 1 + maximum: 65535 + default: 10 - name: order in: query description: |- From 0cf42c84cd6e04be85d29cc6a9d4f659f5cc1dc9 Mon Sep 17 00:00:00 2001 From: shgokita Date: Thu, 12 Dec 2024 20:24:23 +0900 Subject: [PATCH 06/12] feat: add fields query parameter to get jobs API --- backend/oas/provider/openapi.yaml | 116 ++++++++++++- backend/oas/provider/paths/jobs.yaml | 15 +- backend/oas/provider/schemas/jobs.yaml | 108 ++++++++++++ .../oqtopus_cloud/provider/routers/jobs.py | 154 ++++++++++++------ .../oqtopus_cloud/provider/schemas/jobs.py | 39 +++++ backend/oqtopus_cloud/user/routers/jobs.py | 3 +- 6 files changed, 381 insertions(+), 54 deletions(-) diff --git a/backend/oas/provider/openapi.yaml b/backend/oas/provider/openapi.yaml index e971363..3419e04 100644 --- a/backend/oas/provider/openapi.yaml +++ b/backend/oas/provider/openapi.yaml @@ -103,6 +103,19 @@ paths: schema: type: string example: Kawasaki + - in: query + name: fields + description: |- + Allows to specify an exact list of job properties to fetch for a single job. Each element of the list must be a valid name of job property. + + If parameter is specified and requested job field is not defined for a job null is returned. + + If parameter is omitted all available job properties are returned. Undefined job properties (null properties) are not included in the response. + required: false + schema: + type: string + maxLength: 1024 + example: job_id,status,name - in: query name: status description: Additional search parameter:
Search jobs with specified status only @@ -128,7 +141,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/jobs.JobDef' + $ref: '#/components/schemas/jobs.GetJobsResponse' '400': description: Bad Request content: @@ -445,6 +458,107 @@ components: description: The reason indicating why there is no result required: - desc + jobs.GetJobsResponse: + type: object + properties: + job_id: + $ref: '#/components/schemas/jobs.JobId' + name: + type: string + example: Bell State Sampling + description: + type: string + example: Bell State Sampling Example + device_id: + type: string + example: Kawasaki + shots: + type: integer + minimum: 1 + maximum: 10000000 + example: '1000' + job_info: + $ref: '#/components/schemas/jobs.JobInfo' + transpiler_info: + type: string + example: |- + { + "qubit_allocation": { + "0"": 12, + "1": 16 + }, + "skip_transpilation": false, + "seed_transpilation": 873 + } + simulator_info: + type: string + example: |- + { + "n_qubits": 5, + "n_nodes": 12, + "n_per_node": 2, + "seed_simulation": 39058567, + "simulation_opt": { + "optimization_method": "light", + "optimization_block_size": 1, + "optimization_swap_level": 1 + } + } + mitigation_info: + type: string + example: | + { "ro_error_mitigation": "pseudo_inverse" } + status: + $ref: '#/components/schemas/jobs.JobStatus' + created_at: + type: string + format: date-time + example: '2022-10-19T11:45:34+09:00' + updated_at: + type: string + format: date-time + example: '2022-10-19T11:45:34' + required: [] + example: + job_id: 7af020f6-2e38-4d70-8cf0-4349650ea08c + name: Bell State Sampling + description: Bell State Sampling Example + device_id: Kawasaki + job_info: + desc: + job_type: sampling + code: OPENQASM 3; qubit[2] q; bit[2] c; h q[0]; cnot q[0], q[1]; c = measure q; + transpiled_code: null + result: null + reason: null + transpiler_info: |- + { + "qubit_allocation": { + "0": 12, + "1": 16 + }, + "skip_transpilation": false, + "seed_transpilation": 873 + } + simulator_info: |- + { + "n_qubits": 5, + "n_nodes": 12, + "n_per_node": 2, + "seed_simulation": 39058567, + "simulation_opt": { + "optimization_method": "light", + "optimization_block_size": 1, + "optimization_swap_level": 1 + } + } + mitigation_info: | + { "ro_error_mitigation": "pseudo_inverse" } + job_type: sampling + shots: 1000 + status: submitted + created_at: '2022-10-19T11:45:34' + updated_at: '2022-10-19T11:45:34' jobs.JobDef: type: object properties: diff --git a/backend/oas/provider/paths/jobs.yaml b/backend/oas/provider/paths/jobs.yaml index 39afe3e..953cdf4 100644 --- a/backend/oas/provider/paths/jobs.yaml +++ b/backend/oas/provider/paths/jobs.yaml @@ -12,6 +12,19 @@ jobs: required: true description: "Device identifier" schema: { type: string, example: "Kawasaki" } + - in: query + name: fields + description: |- + Allows to specify an exact list of job properties to fetch for a single job. Each element of the list must be a valid name of job property. + + If parameter is specified and requested job field is not defined for a job null is returned. + + If parameter is omitted all available job properties are returned. Undefined job properties (null properties) are not included in the response. + required: false + schema: + type: string + maxLength: 1024 + example: "job_id,status,name" - in: query name: status description: "Additional search parameter:
Search jobs with specified status only" @@ -33,7 +46,7 @@ jobs: schema: type: array items: - $ref: "../schemas/jobs.yaml#/jobs.JobDef" + $ref: "../schemas/jobs.yaml#/jobs.GetJobsResponse" "400": description: Bad Request content: diff --git a/backend/oas/provider/schemas/jobs.yaml b/backend/oas/provider/schemas/jobs.yaml index f05b99d..0782ad3 100644 --- a/backend/oas/provider/schemas/jobs.yaml +++ b/backend/oas/provider/schemas/jobs.yaml @@ -214,6 +214,114 @@ jobs.JobDef: created_at: 2022-10-19T11:45:34 updated_at: 2022-10-19T11:45:34 +jobs.GetJobsResponse: + type: object + properties: + job_id: + $ref: "#/jobs.JobId" + name: + type: string + example: Bell State Sampling + description: + type: string + example: Bell State Sampling Example + device_id: + type: string + example: Kawasaki + shots: + type: integer + minimum: 1 + maximum: 1e7 + example: "1000" + job_info: + $ref: "#/jobs.JobInfo" + transpiler_info: + type: string + example: >- + { + "qubit_allocation": { + "0"": 12, + "1": 16 + }, + "skip_transpilation": false, + "seed_transpilation": 873 + } + simulator_info: + type: string + example: >- + { + "n_qubits": 5, + "n_nodes": 12, + "n_per_node": 2, + "seed_simulation": 39058567, + "simulation_opt": { + "optimization_method": "light", + "optimization_block_size": 1, + "optimization_swap_level": 1 + } + } + mitigation_info: + type: string + example: | + { "ro_error_mitigation": "pseudo_inverse" } + status: + $ref: "#/jobs.JobStatus" + created_at: + type: string + format: date-time + example: 2022-10-19T11:45:34+09:00 + updated_at: + type: string + format: date-time + example: 2022-10-19T11:45:34 + required: [] + example: + job_id: 7af020f6-2e38-4d70-8cf0-4349650ea08c + name: Bell State Sampling + description: Bell State Sampling Example + device_id: Kawasaki + job_info: + desc: + job_type: sampling + code: >- + OPENQASM 3; + qubit[2] q; + bit[2] c; + h q[0]; + cnot q[0], q[1]; + c = measure q; + transpiled_code: null + result: null + reason: null + transpiler_info: >- + { + "qubit_allocation": { + "0": 12, + "1": 16 + }, + "skip_transpilation": false, + "seed_transpilation": 873 + } + simulator_info: >- + { + "n_qubits": 5, + "n_nodes": 12, + "n_per_node": 2, + "seed_simulation": 39058567, + "simulation_opt": { + "optimization_method": "light", + "optimization_block_size": 1, + "optimization_swap_level": 1 + } + } + mitigation_info: | + { "ro_error_mitigation": "pseudo_inverse" } + job_type: sampling + shots: 1000 + status: submitted + created_at: 2022-10-19T11:45:34 + updated_at: 2022-10-19T11:45:34 + jobs.JobStatusUpdate: type: object properties: diff --git a/backend/oqtopus_cloud/provider/routers/jobs.py b/backend/oqtopus_cloud/provider/routers/jobs.py index f206237..1fa4647 100644 --- a/backend/oqtopus_cloud/provider/routers/jobs.py +++ b/backend/oqtopus_cloud/provider/routers/jobs.py @@ -1,6 +1,6 @@ import json from datetime import datetime -from typing import Any, Optional +from typing import Any, Optional, Union from fastapi import APIRouter, Depends from oqtopus_cloud.common.models.job import Job @@ -15,6 +15,7 @@ NotFoundErrorResponse, ) from oqtopus_cloud.provider.schemas.jobs import ( + GetJobsResponse, JobDef, JobInfo, JobStatus, @@ -23,7 +24,7 @@ UpdateJobInfoRequest, UpdateJobInfoResponse, ) -from sqlalchemy import select +from sqlalchemy import Row, select from sqlalchemy.orm import Session from zoneinfo import ZoneInfo @@ -39,42 +40,73 @@ @router.get( "/jobs", - response_model=list[JobDef], + response_model=list[Union[JobDef, GetJobsResponse]], + responses={500: {"model": Detail}}, ) @tracer.capture_method def get_jobs( device_id: str, + fields: Optional[str] = None, status: Optional[str] = None, max_results: Optional[int] = None, timestamp: Optional[str] = None, db: Session = Depends(get_db), -) -> list[JobDef]: +) -> list[Union[JobDef, GetJobsResponse]] | ErrorResponse: logger.info("invoked get_jobs") - query = db.query(Job).filter(Job.device_id == device_id) - if status is not None: - query = query.filter(Job.status == status) - if timestamp is not None: - time = datetime.fromisoformat(timestamp).astimezone(jst) - query = query.filter(Job.created_at > time) - if max_results is not None: - query = query.limit(max_results) - models = query.all() - jobs: list[JobDef] = [] - for model in models: - job = model_to_schema(model) - if isinstance(job, ValueError): - logger.warning(str(job)) + # Fields Control + try: + if fields is not None: + fields_list = fields.split(",") + MAP_SCHEMA_TO_MODEL = {v: k for k, v in MAP_MODEL_TO_SCHEMA.items()} + converted_fields_list = [ + MAP_SCHEMA_TO_MODEL[field] for field in fields_list + ] + columns = [getattr(Job, field) for field in converted_fields_list] + arg_select = columns + else: + arg_select = [Job] + + stmt = select(*arg_select).filter(Job.device_id == device_id) + full_stmt = select(Job).filter(Job.device_id == device_id) + # query = db.query(Job).filter(Job.device_id == device_id) + # Filtering Jobs + if status is not None: + stmt = stmt.filter(Job.status == status) + full_stmt = full_stmt.filter(Job.status == status) + if timestamp is not None: + time = datetime.fromisoformat(timestamp).astimezone(jst) + stmt = stmt.filter(Job.created_at > time) + full_stmt = full_stmt.filter(Job.created_at > time) + if max_results is not None: + stmt = stmt.limit(max_results) + full_stmt = full_stmt.limit(max_results) + + if fields is None: + # models is Job type + models = db.scalars(stmt).all() else: - try: - if decode_job_status(model.status) == JobStatus.submitted: - model.status = JobStatus.ready - db.commit() - job.status = JobStatus(model.status) - jobs.append(job) - except Exception as e: + # models is Row type + models = db.execute(stmt).all() + update_models = db.scalars(full_stmt).all() + results: list[Union[JobDef, GetJobsResponse]] = [] + for model, update_model in zip(models, update_models): + job = model_to_schema(model) + if isinstance(job, ValueError): logger.warning(str(job)) - logger.warning(f"Error: {str(e)}") - return jobs + else: + try: + if decode_job_status(update_model.status) == JobStatus.submitted: + update_model.status = JobStatus.ready + db.commit() + job.status = JobStatus(model.status) + results.append(job) + except Exception as e: + logger.warning(str(job)) + logger.warning(f"Error: {str(e)}") + return results + except Exception as e: + logger.info(f"error: {str(e)}") + return InternalServerErrorResponse(detail=str(e)) @router.get( @@ -86,7 +118,7 @@ def get_jobs( def get_job( job_id: str, db: Session = Depends(get_db), -) -> JobDef | ErrorResponse: +) -> Union[JobDef, GetJobsResponse] | ErrorResponse: logger.info("invoked get_job") try: model = db.get(Job, job_id) @@ -193,8 +225,9 @@ def patch_job_info(job_info: JobInfo) -> tuple[Optional[JobStatus], JobInfo]: return InternalServerErrorResponse(f"Error: {str(e)}") +# TODO: match parameter names of model and schema MAP_MODEL_TO_SCHEMA = { - "id": "id", + "id": "job_id", "owner": "owner", "status": "status", "name": "name", @@ -218,7 +251,9 @@ def decode_job_status(s: str) -> JobStatus | ValueError: return ValueError(f"Failed to decode JobStatus: {str(err)}") -def model_to_schema(model: Job) -> JobDef | ValueError: +def model_to_schema( + model: Union[Job, Row], +) -> Union[JobDef, GetJobsResponse] | ValueError: def decode_job_info(j: Any) -> JobInfo | ValueError: try: jobinfo = JobInfo.model_validate(j) @@ -226,24 +261,41 @@ def decode_job_info(j: Any) -> JobInfo | ValueError: except Exception as e: return ValueError(f"Failed to decode job_info: {str(e)}") - status = decode_job_status(model.status) - if isinstance(status, ValueError): - return status - - job_info = decode_job_info(json.loads(model.job_info)) - if isinstance(job_info, ValueError): - return job_info - return JobDef( - job_id=model.id, - name=model.name, - description=model.description, - device_id=model.device_id, - shots=model.shots, - job_info=job_info, - status=status, - transpiler_info=model.transpiler_info, - mitigation_info=model.mitigation_info, - simulator_info=model.simulator_info, - created_at=model.created_at, - updated_at=model.updated_at, - ) + if hasattr(model, "status"): + status = decode_job_status(model.status) + if hasattr(model, "job_info"): + job_info = decode_job_info(json.loads(model.job_info)) + + if type(model) is Job: + if isinstance(job_info, ValueError): + return job_info + if isinstance(status, ValueError): + return status + return JobDef( + job_id=model.id, + name=model.name, + description=model.description, + device_id=model.device_id, + shots=model.shots, + job_info=job_info, + status=status, + transpiler_info=model.transpiler_info, + mitigation_info=model.mitigation_info, + simulator_info=model.simulator_info, + created_at=model.created_at, + updated_at=model.updated_at, + ) + elif type(model) is Row: + dict_model = {} + for k, v in model._mapping.items(): + if k == "id": + dict_model["job_id"] = v + elif k == "job_info": + dict_model[k] = job_info + elif k == "status": + dict_model[k] = JobStatus(v) + else: + dict_model[k] = v + return GetJobsResponse(**dict_model) + else: + return ValueError("Failed to decode model") diff --git a/backend/oqtopus_cloud/provider/schemas/jobs.py b/backend/oqtopus_cloud/provider/schemas/jobs.py index 73bfb2b..e968afe 100644 --- a/backend/oqtopus_cloud/provider/schemas/jobs.py +++ b/backend/oqtopus_cloud/provider/schemas/jobs.py @@ -75,6 +75,45 @@ class JobInfo(BaseModel): """ +class GetJobsResponse(BaseModel): + job_id: Annotated[ + str | None, Field(examples=["7af020f6-2e38-4d70-8cf0-4349650ea08c"]) + ] = None + name: Annotated[str | None, Field(examples=["Bell State Sampling"])] = None + description: Annotated[ + str | None, Field(examples=["Bell State Sampling Example"]) + ] = None + device_id: Annotated[str | None, Field(examples=["Kawasaki"])] = None + shots: Annotated[int | None, Field(examples=["1000"], ge=1, le=10000000)] = None + job_info: JobInfo | None = None + transpiler_info: Annotated[ + str | None, + Field( + examples=[ + '{\n "qubit_allocation": {\n "0"": 12,\n "1": 16\n },\n "skip_transpilation": false,\n "seed_transpilation": 873\n}' + ] + ), + ] = None + simulator_info: Annotated[ + str | None, + Field( + examples=[ + '{\n "n_qubits": 5,\n "n_nodes": 12,\n "n_per_node": 2,\n "seed_simulation": 39058567,\n "simulation_opt": {\n "optimization_method": "light",\n "optimization_block_size": 1,\n "optimization_swap_level": 1\n }\n}' + ] + ), + ] = None + mitigation_info: Annotated[ + str | None, Field(examples=['{ "ro_error_mitigation": "pseudo_inverse" }\n']) + ] = None + status: JobStatus | None = None + created_at: Annotated[ + datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) + ] = None + updated_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34"])] = ( + None + ) + + class JobDef(BaseModel): job_id: Annotated[str, Field(examples=["7af020f6-2e38-4d70-8cf0-4349650ea08c"])] name: Annotated[str | None, Field(examples=["Bell State Sampling"])] = None diff --git a/backend/oqtopus_cloud/user/routers/jobs.py b/backend/oqtopus_cloud/user/routers/jobs.py index 569f71f..b3b074a 100644 --- a/backend/oqtopus_cloud/user/routers/jobs.py +++ b/backend/oqtopus_cloud/user/routers/jobs.py @@ -98,7 +98,7 @@ def get_jobs( stmt = select(*arg_select).filter(Job.owner == owner).order_by(arg_order) - # Filterling Jobs + # Filtering Jobs if startTime is not None: stime = datetime.fromisoformat(startTime).astimezone(jst) stmt = stmt.filter(Job.created_at >= stime) @@ -311,6 +311,7 @@ def cancel_job( return InternalServerErrorResponse(detail=str(e)) +# TODO: match parameter names of model and schema MAP_MODEL_TO_SCHEMA = { "id": "job_id", "owner": "owner", From a3ede70c4b909305a0e0834c1fb9f0bc3946acab Mon Sep 17 00:00:00 2001 From: shgokita Date: Thu, 12 Dec 2024 20:24:39 +0900 Subject: [PATCH 07/12] tests: add get jobs tests --- .../provider/routers/test_jobs.py | 114 ++++++++++++++++-- 1 file changed, 103 insertions(+), 11 deletions(-) diff --git a/backend/tests/oqtopus_cloud/provider/routers/test_jobs.py b/backend/tests/oqtopus_cloud/provider/routers/test_jobs.py index 8cb806c..0e4c53a 100644 --- a/backend/tests/oqtopus_cloud/provider/routers/test_jobs.py +++ b/backend/tests/oqtopus_cloud/provider/routers/test_jobs.py @@ -1,6 +1,6 @@ import json -import uuid from datetime import datetime +from typing import List from fastapi.testclient import TestClient from oqtopus_cloud.common.models.device import ( @@ -16,13 +16,16 @@ update_job, ) from oqtopus_cloud.provider.schemas.jobs import ( + GetJobsResponse, JobDef, JobInfo, + JobInfoSampling, JobStatus, JobStatusUpdate, JobStatusUpdateResponse, UpdateJobInfoRequest, ) +from pydantic.type_adapter import TypeAdapter from sqlalchemy.orm.session import Session from zoneinfo import ZoneInfo @@ -65,12 +68,12 @@ def _get_device_model(): return Device(**mode_dict) -def _get_job_model() -> Job: +def _get_job_model(n: int) -> Job: mode_dict = { - "id": "testjob1id", + "id": f"testjob{n}id", "owner": "admin", - "name": "testjob1", - "description": "test job 1", + "name": f"testjob{n}", + "description": f"test job {n}", "device_id": "SC2", "job_type": "sampling", "job_info": json.dumps( @@ -88,7 +91,7 @@ def _get_job_model() -> Job: ), "status": "ready", "shots": 1000, - "created_at": datetime(2024, 3, 4, 12, 34, 56), + "created_at": datetime(2024, 3, 4 + n, 12, 34, 56), } return Job(**mode_dict) @@ -123,6 +126,7 @@ def _get_job_model_2() -> Job: def test_get_jobs(test_db: Session): # Arrange + test_db.flush() test_db.add(_get_job_model_2()) test_db.add(_get_device_model()) test_db.commit() @@ -142,10 +146,98 @@ def test_get_jobs(test_db: Session): assert job.status == "ready" +def test_get_jobs_filtering(test_db: Session): + # Arrange + test_db.flush() + test_db.add(_get_job_model(1)) + test_db.add(_get_job_model(2)) + test_db.add(_get_device_model()) + test_db.commit() + + response = client.get("/jobs?device_id=SC2&fields=job_id%2Cdescription%2Cjob_info") + adapter = TypeAdapter(List[GetJobsResponse]) + actual = adapter.validate_python(response.json()) + expect = [ + GetJobsResponse( + job_id="testjob1id", + description="test job 1", + job_info=JobInfo( + desc=JobInfoSampling(job_type="sampling", code="code"), + ), + ), + GetJobsResponse( + job_id="testjob2id", + description="test job 2", + job_info=JobInfo( + desc=JobInfoSampling(job_type="sampling", code="code"), + ), + ), + ] + + assert response.status_code == 200 + assert actual == expect + + +def test_get_jobs_timestamp(test_db: Session): + # Arrange + test_db.flush() + for i in range(1, 10): + test_db.add(_get_job_model(i)) + test_db.add(_get_device_model()) + test_db.commit() + + response = client.get( + "/jobs?device_id=SC2&fields=job_id×tamp=2024-03-11T07%3A04%3A24%2B09%3A00" + ) + adapter = TypeAdapter(List[GetJobsResponse]) + actual = adapter.validate_python(response.json()) + expect = [ + GetJobsResponse( + job_id="testjob7id", + ), + GetJobsResponse( + job_id="testjob8id", + ), + GetJobsResponse( + job_id="testjob9id", + ), + ] + + assert response.status_code == 200 + assert actual == expect + + +def test_get_jobs_max_results(test_db: Session): + # Arrange + test_db.flush() + for i in range(1, 10): + test_db.add(_get_job_model(i)) + test_db.add(_get_device_model()) + test_db.commit() + + response = client.get("/jobs?device_id=SC2&fields=job_id&max_results=3") + adapter = TypeAdapter(List[GetJobsResponse]) + actual = adapter.validate_python(response.json()) + expect = [ + GetJobsResponse( + job_id="testjob1id", + ), + GetJobsResponse( + job_id="testjob2id", + ), + GetJobsResponse( + job_id="testjob3id", + ), + ] + + assert response.status_code == 200 + assert actual == expect + + def test_get_job(test_db: Session): # Arrange - test_db.add(_get_job_model()) + test_db.add(_get_job_model(1)) test_db.add(_get_device_model()) test_db.commit() job_id = "testjob1id" @@ -156,7 +248,7 @@ def test_get_job(test_db: Session): def test_update_job(test_db: Session): # Arrange - test_db.add(_get_job_model()) + test_db.add(_get_job_model(1)) test_db.add(_get_device_model()) test_db.commit() job_id = "testjob1id" @@ -170,7 +262,7 @@ def test_update_job(test_db: Session): def test_update_job_info_400(test_db: Session): - job_model = _get_job_model() + job_model = _get_job_model(1) test_db.add(_get_device_model()) test_db.add(job_model) test_db.commit() @@ -189,7 +281,7 @@ def test_update_job_info_400(test_db: Session): def test_update_job_info_result(test_db: Session): - job_model = _get_job_model() + job_model = _get_job_model(1) bef_job_info = JobInfo.model_validate(json.loads(job_model.job_info)) test_db.add(_get_device_model()) test_db.add(job_model) @@ -216,7 +308,7 @@ def test_update_job_info_result(test_db: Session): def test_update_job_info_reason(test_db: Session): - job_model = _get_job_model() + job_model = _get_job_model(1) bef_job_info = JobInfo.model_validate(json.loads(job_model.job_info)) test_db.add(_get_device_model()) test_db.add(job_model) From fb3c6e7b5ed2ce042913165dc20f44ebeefdc7ff Mon Sep 17 00:00:00 2001 From: shgokita Date: Thu, 12 Dec 2024 20:26:32 +0900 Subject: [PATCH 08/12] docs: update openapi docs --- docs/oas/provider/openapi.yaml | 116 ++++++++++++++++++++++- docs/oas/user/openapi.yaml | 163 ++++++++++++++++++++++++++++++--- 2 files changed, 263 insertions(+), 16 deletions(-) diff --git a/docs/oas/provider/openapi.yaml b/docs/oas/provider/openapi.yaml index e971363..3419e04 100644 --- a/docs/oas/provider/openapi.yaml +++ b/docs/oas/provider/openapi.yaml @@ -103,6 +103,19 @@ paths: schema: type: string example: Kawasaki + - in: query + name: fields + description: |- + Allows to specify an exact list of job properties to fetch for a single job. Each element of the list must be a valid name of job property. + + If parameter is specified and requested job field is not defined for a job null is returned. + + If parameter is omitted all available job properties are returned. Undefined job properties (null properties) are not included in the response. + required: false + schema: + type: string + maxLength: 1024 + example: job_id,status,name - in: query name: status description: Additional search parameter:
Search jobs with specified status only @@ -128,7 +141,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/jobs.JobDef' + $ref: '#/components/schemas/jobs.GetJobsResponse' '400': description: Bad Request content: @@ -445,6 +458,107 @@ components: description: The reason indicating why there is no result required: - desc + jobs.GetJobsResponse: + type: object + properties: + job_id: + $ref: '#/components/schemas/jobs.JobId' + name: + type: string + example: Bell State Sampling + description: + type: string + example: Bell State Sampling Example + device_id: + type: string + example: Kawasaki + shots: + type: integer + minimum: 1 + maximum: 10000000 + example: '1000' + job_info: + $ref: '#/components/schemas/jobs.JobInfo' + transpiler_info: + type: string + example: |- + { + "qubit_allocation": { + "0"": 12, + "1": 16 + }, + "skip_transpilation": false, + "seed_transpilation": 873 + } + simulator_info: + type: string + example: |- + { + "n_qubits": 5, + "n_nodes": 12, + "n_per_node": 2, + "seed_simulation": 39058567, + "simulation_opt": { + "optimization_method": "light", + "optimization_block_size": 1, + "optimization_swap_level": 1 + } + } + mitigation_info: + type: string + example: | + { "ro_error_mitigation": "pseudo_inverse" } + status: + $ref: '#/components/schemas/jobs.JobStatus' + created_at: + type: string + format: date-time + example: '2022-10-19T11:45:34+09:00' + updated_at: + type: string + format: date-time + example: '2022-10-19T11:45:34' + required: [] + example: + job_id: 7af020f6-2e38-4d70-8cf0-4349650ea08c + name: Bell State Sampling + description: Bell State Sampling Example + device_id: Kawasaki + job_info: + desc: + job_type: sampling + code: OPENQASM 3; qubit[2] q; bit[2] c; h q[0]; cnot q[0], q[1]; c = measure q; + transpiled_code: null + result: null + reason: null + transpiler_info: |- + { + "qubit_allocation": { + "0": 12, + "1": 16 + }, + "skip_transpilation": false, + "seed_transpilation": 873 + } + simulator_info: |- + { + "n_qubits": 5, + "n_nodes": 12, + "n_per_node": 2, + "seed_simulation": 39058567, + "simulation_opt": { + "optimization_method": "light", + "optimization_block_size": 1, + "optimization_swap_level": 1 + } + } + mitigation_info: | + { "ro_error_mitigation": "pseudo_inverse" } + job_type: sampling + shots: 1000 + status: submitted + created_at: '2022-10-19T11:45:34' + updated_at: '2022-10-19T11:45:34' jobs.JobDef: type: object properties: diff --git a/docs/oas/user/openapi.yaml b/docs/oas/user/openapi.yaml index 910d6ea..8fbb79d 100644 --- a/docs/oas/user/openapi.yaml +++ b/docs/oas/user/openapi.yaml @@ -86,10 +86,83 @@ paths: tags: - job summary: List all quantum jobs - description: List all quantum jobs + description: |- + By default, all available job's properties are returned. Use 'fields' parameter to specify exact list of properties to get for each job. + + List of jobs can be filtered by job creation time or search text with 'startTime', 'endTime' and 'q' parameters. + + Jobs are fetched with the pagination mechanism. This can be configured with 'page' and 'perPage' parameters. Check response's 'Link' header for pagination details. operationId: listJobs security: - BearerAuth: [] + parameters: + - name: fields + in: query + description: |- + Allows to specify an exact list of job properties to fetch for a single job. Each element of the list must be a valid name of job property. + + If parameter is specified and requested job field is not defined for a job null is returned. + + If parameter is omitted all available job properties are returned. Undefined job properties (null properties) are not included in the response. + required: false + schema: + type: string + maxLength: 1024 + example: job_id,status,name + - name: startTime + in: query + description: Allows to filter the list of jobs to fetch by creation time. If specified only jobs with creation time (createdAt property) >= startTime are returned. + required: false + schema: + type: string + format: date-time + example: '2022-10-19T11:45:34+09:00' + - name: endTime + in: query + description: Allows to filter the list of jobs to fetch by to creation time. If specified only jobs with creation time (createdAt property) <= endTime are returned. + required: false + schema: + type: string + format: date-time + example: '2022-10-19T11:45:34+09:00' + - name: q + in: query + description: Allows to filter the list of jobs to fetch by job's name and description. If specified only jobs which name or description contains specified search string are returned. + required: false + schema: + type: string + maxLength: 1024 + example: Bell + - name: page + in: query + description: |- + Set jobs list page number to fetch. + If requested page number exceeds number of all pages last page is returned. + required: false + schema: + type: integer + minimum: 1 + maximum: 4294967295 + default: 1 + - name: size + in: query + description: Configure number of jobs per page + required: false + schema: + type: integer + minimum: 1 + maximum: 65535 + default: 10 + - name: order + in: query + description: Specify jobs order according to creation time (createdAt property) + required: false + schema: + type: string + enum: + - DESC + - ASC + default: ASC responses: '200': description: Return a list of submitted quantum jobs @@ -98,7 +171,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/jobs.JobDef' + $ref: '#/components/schemas/jobs.GetJobsResponse' '401': description: Unauthorized content: @@ -647,7 +720,7 @@ components: { "ro_error_mitigation": "pseudo_inverse" } - jobs.JobDef: + jobs.GetJobsResponse: type: object properties: job_id: @@ -681,19 +754,12 @@ components: created_at: type: string format: date-time - example: '2022-10-19T11:45:34Z' + example: '2022-10-19T11:45:34+09:00' updated_at: type: string format: date-time - example: '2022-10-19T11:45:34Z' - required: - - job_id - - name - - job_type - - status - - device_id - - shots - - job_info + example: '2022-10-19T11:45:34+09:00' + required: [] example: job_id: 7af020f6-2e38-4d70-8cf0-4349650ea08c name: Bell State Sampling @@ -712,8 +778,8 @@ components: mitigation_info: '{ "ro_error_mitigation": "pseudo_inverse" }' shots: 1000 status: submitted - created_at: '2022-10-19T11:45:34' - updated_at: '2022-10-19T11:45:34' + created_at: '2022-10-19T11:45:34+09:00' + updated_at: '2022-10-19T11:45:34+09:00' jobs.SubmitJobRequest: type: object properties: @@ -784,6 +850,73 @@ components: type: string required: - detail + jobs.JobDef: + type: object + properties: + job_id: + $ref: '#/components/schemas/jobs.JobId' + name: + type: string + example: Bell State Sampling + description: + type: string + example: Bell State Sampling Example + job_type: + $ref: '#/components/schemas/jobs.JobType' + status: + $ref: '#/components/schemas/jobs.JobStatus' + device_id: + type: string + example: Kawasaki + shots: + type: integer + minimum: 1 + maximum: 10000000 + example: '1000' + job_info: + $ref: '#/components/schemas/jobs.JobInfo' + transpiler_info: + $ref: '#/components/schemas/jobs.TranspilerInfo' + simulator_info: + $ref: '#/components/schemas/jobs.SimulatorInfo' + mitigation_info: + $ref: '#/components/schemas/jobs.MitigationInfo' + created_at: + type: string + format: date-time + example: '2022-10-19T11:45:34Z' + updated_at: + type: string + format: date-time + example: '2022-10-19T11:45:34Z' + required: + - job_id + - name + - job_type + - status + - device_id + - shots + - job_info + example: + job_id: 7af020f6-2e38-4d70-8cf0-4349650ea08c + name: Bell State Sampling + description: Bell State Sampling Example + device_id: Kawasaki, + job_info: + desc: + job_type: estimation + code: OPENQASM 3; qubit[2] q; bit[2] c; h q[0]; cnot q[0], q[1]; c = measure q; + operator: X 0 Y 1 Z 5 I 2 + transpiled_code: '{}' + result: '{}' + reason: '' + transpiler_info: '{ "qubit_allocation": { "0": 12, "1": 16 }, "skip_transpilation": false, "seed_transpilation": 873 },' + simulator_info: '{ "n_qubits": 5, "n_nodes": 12, "n_per_node": 2, "seed_simulation": 39058567, "simulation_opt": { "optimization_method": "light", "optimization_block_size": 1, "optimization_swap_level": 1 } }' + mitigation_info: '{ "ro_error_mitigation": "pseudo_inverse" }' + shots: 1000 + status: submitted + created_at: '2022-10-19T11:45:34' + updated_at: '2022-10-19T11:45:34' success.SuccessResponse: type: object properties: From 5dcbea5ec6e19080e649be01af02135ab26c76e1 Mon Sep 17 00:00:00 2001 From: shgokita Date: Wed, 25 Dec 2024 12:09:45 +0900 Subject: [PATCH 09/12] chore: add exception handling for fields parameter --- .../oqtopus_cloud/provider/routers/jobs.py | 55 ++++++++++++------- backend/oqtopus_cloud/user/routers/jobs.py | 34 ++++++++---- .../oqtopus_cloud/user/routers/test_jobs.py | 27 +++++++++ 3 files changed, 86 insertions(+), 30 deletions(-) diff --git a/backend/oqtopus_cloud/provider/routers/jobs.py b/backend/oqtopus_cloud/provider/routers/jobs.py index 1fa4647..2d83711 100644 --- a/backend/oqtopus_cloud/provider/routers/jobs.py +++ b/backend/oqtopus_cloud/provider/routers/jobs.py @@ -1,6 +1,6 @@ import json from datetime import datetime -from typing import Any, Optional, Union +from typing import Any, Optional from fastapi import APIRouter, Depends from oqtopus_cloud.common.models.job import Job @@ -40,7 +40,7 @@ @router.get( "/jobs", - response_model=list[Union[JobDef, GetJobsResponse]], + response_model=list[JobDef | GetJobsResponse], responses={500: {"model": Detail}}, ) @tracer.capture_method @@ -51,18 +51,30 @@ def get_jobs( max_results: Optional[int] = None, timestamp: Optional[str] = None, db: Session = Depends(get_db), -) -> list[Union[JobDef, GetJobsResponse]] | ErrorResponse: +) -> list[JobDef | GetJobsResponse] | ErrorResponse: logger.info("invoked get_jobs") # Fields Control try: if fields is not None: fields_list = fields.split(",") - MAP_SCHEMA_TO_MODEL = {v: k for k, v in MAP_MODEL_TO_SCHEMA.items()} - converted_fields_list = [ - MAP_SCHEMA_TO_MODEL[field] for field in fields_list - ] - columns = [getattr(Job, field) for field in converted_fields_list] - arg_select = columns + valid_fields_list = [field in JobDef.model_fields for field in fields_list] + if all(valid_fields_list): + MAP_SCHEMA_TO_MODEL = {v: k for k, v in MAP_MODEL_TO_SCHEMA.items()} + converted_fields_list = [ + MAP_SCHEMA_TO_MODEL[field] for field in fields_list + ] + columns = [getattr(Job, field) for field in converted_fields_list] + + # remove duplicated fields + arg_select = list(dict.fromkeys(columns)) + else: + invalid_indices = [ + i for i, field in enumerate(valid_fields_list) if field is False + ] + invalid_fields_list = [fields_list[i] for i in invalid_indices] + return InternalServerErrorResponse( + detail=f"fields {invalid_fields_list} is invalid" + ) else: arg_select = [Job] @@ -88,7 +100,7 @@ def get_jobs( # models is Row type models = db.execute(stmt).all() update_models = db.scalars(full_stmt).all() - results: list[Union[JobDef, GetJobsResponse]] = [] + results: list[JobDef | GetJobsResponse] = [] for model, update_model in zip(models, update_models): job = model_to_schema(model) if isinstance(job, ValueError): @@ -97,12 +109,12 @@ def get_jobs( try: if decode_job_status(update_model.status) == JobStatus.submitted: update_model.status = JobStatus.ready - db.commit() job.status = JobStatus(model.status) results.append(job) except Exception as e: logger.warning(str(job)) logger.warning(f"Error: {str(e)}") + db.commit() return results except Exception as e: logger.info(f"error: {str(e)}") @@ -118,7 +130,7 @@ def get_jobs( def get_job( job_id: str, db: Session = Depends(get_db), -) -> Union[JobDef, GetJobsResponse] | ErrorResponse: +) -> JobDef | GetJobsResponse | ErrorResponse: logger.info("invoked get_job") try: model = db.get(Job, job_id) @@ -252,8 +264,8 @@ def decode_job_status(s: str) -> JobStatus | ValueError: def model_to_schema( - model: Union[Job, Row], -) -> Union[JobDef, GetJobsResponse] | ValueError: + model: Job | Row, +) -> JobDef | GetJobsResponse | ValueError: def decode_job_info(j: Any) -> JobInfo | ValueError: try: jobinfo = JobInfo.model_validate(j) @@ -265,12 +277,11 @@ def decode_job_info(j: Any) -> JobInfo | ValueError: status = decode_job_status(model.status) if hasattr(model, "job_info"): job_info = decode_job_info(json.loads(model.job_info)) - if type(model) is Job: - if isinstance(job_info, ValueError): - return job_info if isinstance(status, ValueError): return status + if isinstance(job_info, ValueError): + return job_info return JobDef( job_id=model.id, name=model.name, @@ -291,9 +302,15 @@ def decode_job_info(j: Any) -> JobInfo | ValueError: if k == "id": dict_model["job_id"] = v elif k == "job_info": - dict_model[k] = job_info + if isinstance(job_info, ValueError): + return job_info + else: + dict_model[k] = job_info elif k == "status": - dict_model[k] = JobStatus(v) + if isinstance(status, ValueError): + return status + else: + dict_model[k] = JobStatus(v) else: dict_model[k] = v return GetJobsResponse(**dict_model) diff --git a/backend/oqtopus_cloud/user/routers/jobs.py b/backend/oqtopus_cloud/user/routers/jobs.py index b3b074a..8b0c27b 100644 --- a/backend/oqtopus_cloud/user/routers/jobs.py +++ b/backend/oqtopus_cloud/user/routers/jobs.py @@ -1,6 +1,6 @@ import json from datetime import datetime -from typing import Any, Optional, Union +from typing import Any, Optional from fastapi import ( APIRouter, @@ -57,7 +57,7 @@ def __init__(self, detail: str): @router.get( "/jobs", - response_model=list[Union[GetJobsResponse, JobDef]], + response_model=list[GetJobsResponse | JobDef], responses={500: {"model": Detail}}, ) @tracer.capture_method @@ -71,7 +71,7 @@ def get_jobs( size: Optional[str] = None, page: Optional[str] = None, db: Session = Depends(get_db), -) -> list[Union[GetJobsResponse, JobDef]] | ErrorResponse: +) -> list[GetJobsResponse | JobDef] | ErrorResponse: try: owner = event.state.owner logger.info("invoked!", extra={"owner": owner}) @@ -87,12 +87,24 @@ def get_jobs( # Fields Control if fields is not None: fields_list = fields.split(",") - MAP_SCHEMA_TO_MODEL = {v: k for k, v in MAP_MODEL_TO_SCHEMA.items()} - converted_fields_list = [ - MAP_SCHEMA_TO_MODEL[field] for field in fields_list - ] - columns = [getattr(Job, field) for field in converted_fields_list] - arg_select = columns + valid_fields_list = [field in JobDef.model_fields for field in fields_list] + if all(valid_fields_list): + MAP_SCHEMA_TO_MODEL = {v: k for k, v in MAP_MODEL_TO_SCHEMA.items()} + converted_fields_list = [ + MAP_SCHEMA_TO_MODEL[field] for field in fields_list + ] + columns = [getattr(Job, field) for field in converted_fields_list] + + # remove duplicated fields + arg_select = list(dict.fromkeys(columns)) + else: + invalid_indices = [ + i for i, field in enumerate(valid_fields_list) if field is False + ] + invalid_fields_list = [fields_list[i] for i in invalid_indices] + return InternalServerErrorResponse( + detail=f"fields {invalid_fields_list} is invalid" + ) else: arg_select = [Job] @@ -201,7 +213,7 @@ def get_job( event: Event, job_id: str, db: Session = Depends(get_db), -) -> Union[JobDef, GetJobsResponse] | ErrorResponse: +) -> JobDef | GetJobsResponse | ErrorResponse: try: owner = event.state.owner logger.info("invoked!", extra={"owner": owner, "job_id": job_id}) @@ -337,7 +349,7 @@ def decode_job_info(j: Any) -> JobInfo | None: return None -def model_to_schema(model: Union[Job, Row]) -> Union[JobDef, GetJobsResponse] | None: +def model_to_schema(model: Job | Row) -> JobDef | GetJobsResponse | None: if hasattr(model, "job_info"): job_info = decode_job_info(json.loads(model.job_info)) else: diff --git a/backend/tests/oqtopus_cloud/user/routers/test_jobs.py b/backend/tests/oqtopus_cloud/user/routers/test_jobs.py index 892f307..9471d06 100644 --- a/backend/tests/oqtopus_cloud/user/routers/test_jobs.py +++ b/backend/tests/oqtopus_cloud/user/routers/test_jobs.py @@ -5,6 +5,9 @@ from fastapi.testclient import TestClient from oqtopus_cloud.common.models.job import Job from oqtopus_cloud.user.lambda_function import app +from oqtopus_cloud.user.schemas.errors import ( + InternalServerErrorResponse, +) # from oqtopus_cloud.user.routers.jobs import ( # get_job, @@ -163,6 +166,30 @@ def test_get_jobs_filtering_fields( assert actual == expect +def test_get_jobs_invalid_fields( + test_db, +): + """_summary_ + GET job_id, status and name by ASC order + """ + + test_db.flush() + test_db.add(_get_model(1)) + test_db.add(_get_model(2)) + test_db.commit() + + response = client.get("/jobs?fields=XXX%2Cstatus%2CYYY&order=ASC") + actual = response.json() + expect = json.loads( + InternalServerErrorResponse( + detail=f"fields {["XXX", "YYY"]} is invalid" + ).body.decode() + ) + + assert response.status_code == 500 + assert actual == expect + + def test_get_jobs_filtering_startTime( test_db, ): From ca67d025f08ceb0a28634c734951a0f225cc15d6 Mon Sep 17 00:00:00 2001 From: shgokita Date: Thu, 26 Dec 2024 13:32:57 +0900 Subject: [PATCH 10/12] refactor: use sqlalchemy load_only option --- .../oqtopus_cloud/provider/routers/jobs.py | 97 +++++++++---------- backend/oqtopus_cloud/user/routers/jobs.py | 78 ++++++++------- 2 files changed, 92 insertions(+), 83 deletions(-) diff --git a/backend/oqtopus_cloud/provider/routers/jobs.py b/backend/oqtopus_cloud/provider/routers/jobs.py index 2d83711..b6f06c7 100644 --- a/backend/oqtopus_cloud/provider/routers/jobs.py +++ b/backend/oqtopus_cloud/provider/routers/jobs.py @@ -24,8 +24,8 @@ UpdateJobInfoRequest, UpdateJobInfoResponse, ) -from sqlalchemy import Row, select -from sqlalchemy.orm import Session +from sqlalchemy import select +from sqlalchemy.orm import Session, load_only from zoneinfo import ZoneInfo from . import LoggerRouteHandler @@ -53,8 +53,9 @@ def get_jobs( db: Session = Depends(get_db), ) -> list[JobDef | GetJobsResponse] | ErrorResponse: logger.info("invoked get_jobs") - # Fields Control try: + # Fields Control + fields_list = None if fields is not None: fields_list = fields.split(",") valid_fields_list = [field in JobDef.model_fields for field in fields_list] @@ -67,6 +68,11 @@ def get_jobs( # remove duplicated fields arg_select = list(dict.fromkeys(columns)) + select_stmt = ( + select(Job) + .filter(Job.device_id == device_id) + .options(load_only(*arg_select)) + ) else: invalid_indices = [ i for i, field in enumerate(valid_fields_list) if field is False @@ -76,44 +82,34 @@ def get_jobs( detail=f"fields {invalid_fields_list} is invalid" ) else: - arg_select = [Job] + select_stmt = select(Job).filter(Job.device_id == device_id) - stmt = select(*arg_select).filter(Job.device_id == device_id) - full_stmt = select(Job).filter(Job.device_id == device_id) - # query = db.query(Job).filter(Job.device_id == device_id) # Filtering Jobs if status is not None: - stmt = stmt.filter(Job.status == status) - full_stmt = full_stmt.filter(Job.status == status) + select_stmt = select_stmt.filter(Job.status == status) if timestamp is not None: time = datetime.fromisoformat(timestamp).astimezone(jst) - stmt = stmt.filter(Job.created_at > time) - full_stmt = full_stmt.filter(Job.created_at > time) + select_stmt = select_stmt.filter(Job.created_at > time) if max_results is not None: - stmt = stmt.limit(max_results) - full_stmt = full_stmt.limit(max_results) + select_stmt = select_stmt.limit(max_results) + + models = db.scalars(select_stmt).all() - if fields is None: - # models is Job type - models = db.scalars(stmt).all() - else: - # models is Row type - models = db.execute(stmt).all() - update_models = db.scalars(full_stmt).all() results: list[JobDef | GetJobsResponse] = [] - for model, update_model in zip(models, update_models): - job = model_to_schema(model) + # for model, update_status in zip(models, update_statuses): + for model in models: + job = model_to_schema(model, fields_list) if isinstance(job, ValueError): logger.warning(str(job)) + return NotFoundErrorResponse("Job not found") else: - try: - if decode_job_status(update_model.status) == JobStatus.submitted: - update_model.status = JobStatus.ready - job.status = JobStatus(model.status) - results.append(job) - except Exception as e: - logger.warning(str(job)) - logger.warning(f"Error: {str(e)}") + # if status is "submitted", then update status to "ready" + if decode_job_status(model.status) == JobStatus.submitted: + model.status = JobStatus.ready + # checking model objects has status attribute + if (fields is None) or (fields is not None and "status" in fields): + job.status = JobStatus(model.status) + results.append(job) db.commit() return results except Exception as e: @@ -263,21 +259,20 @@ def decode_job_status(s: str) -> JobStatus | ValueError: return ValueError(f"Failed to decode JobStatus: {str(err)}") +def decode_job_info(j: Any) -> JobInfo | ValueError: + try: + jobinfo = JobInfo.model_validate(j) + return jobinfo + except Exception as e: + return ValueError(f"Failed to decode job_info: {str(e)}") + + def model_to_schema( - model: Job | Row, + model: Job, fields: Optional[list[str]] = None ) -> JobDef | GetJobsResponse | ValueError: - def decode_job_info(j: Any) -> JobInfo | ValueError: - try: - jobinfo = JobInfo.model_validate(j) - return jobinfo - except Exception as e: - return ValueError(f"Failed to decode job_info: {str(e)}") - - if hasattr(model, "status"): + if fields is None: status = decode_job_status(model.status) - if hasattr(model, "job_info"): job_info = decode_job_info(json.loads(model.job_info)) - if type(model) is Job: if isinstance(status, ValueError): return status if isinstance(job_info, ValueError): @@ -296,23 +291,25 @@ def decode_job_info(j: Any) -> JobInfo | ValueError: created_at=model.created_at, updated_at=model.updated_at, ) - elif type(model) is Row: - dict_model = {} - for k, v in model._mapping.items(): - if k == "id": - dict_model["job_id"] = v + elif fields is not None: + dict_schema: dict[str, Any] = {} + for k in fields: + if k == "job_id": + dict_schema["job_id"] = model.id elif k == "job_info": + job_info = decode_job_info(json.loads(model.job_info)) if isinstance(job_info, ValueError): return job_info else: - dict_model[k] = job_info + dict_schema[k] = job_info elif k == "status": + status = decode_job_status(model.status) if isinstance(status, ValueError): return status else: - dict_model[k] = JobStatus(v) + dict_schema[k] = JobStatus(model.status) else: - dict_model[k] = v - return GetJobsResponse(**dict_model) + dict_schema[k] = getattr(model, k) + return GetJobsResponse(**dict_schema) else: return ValueError("Failed to decode model") diff --git a/backend/oqtopus_cloud/user/routers/jobs.py b/backend/oqtopus_cloud/user/routers/jobs.py index 8b0c27b..1b7eb02 100644 --- a/backend/oqtopus_cloud/user/routers/jobs.py +++ b/backend/oqtopus_cloud/user/routers/jobs.py @@ -10,10 +10,7 @@ from fastapi_pagination import Page, Params, set_page, set_params from fastapi_pagination.ext.sqlalchemy import paginate from sqlalchemy import asc, desc, or_, select -from sqlalchemy.engine.row import Row -from sqlalchemy.orm import ( - Session, -) +from sqlalchemy.orm import Session, load_only from uuid_extensions import uuid7 from zoneinfo import ZoneInfo @@ -85,6 +82,7 @@ def get_jobs( arg_order = asc(Job.created_at) # Fields Control + fields_list = None if fields is not None: fields_list = fields.split(",") valid_fields_list = [field in JobDef.model_fields for field in fields_list] @@ -97,6 +95,12 @@ def get_jobs( # remove duplicated fields arg_select = list(dict.fromkeys(columns)) + stmt = ( + select(Job) + .filter(Job.owner == owner) + .order_by(arg_order) + .options(load_only(*arg_select)) + ) else: invalid_indices = [ i for i, field in enumerate(valid_fields_list) if field is False @@ -106,9 +110,7 @@ def get_jobs( detail=f"fields {invalid_fields_list} is invalid" ) else: - arg_select = [Job] - - stmt = select(*arg_select).filter(Job.owner == owner).order_by(arg_order) + stmt = select(Job).filter(Job.owner == owner).order_by(arg_order) # Filtering Jobs if startTime is not None: @@ -126,13 +128,16 @@ def get_jobs( page=int(page) if page is not None else 1, ) ) - set_page(Page[Job | Row]) - jobs = paginate(db, stmt) + set_page(Page[Job]) + models = paginate(db, stmt) results = [] - for job_model, job in [(job, model_to_schema(job)) for job in jobs.items]: - if job is None: - logger.warning(f"Failed to encode job model to schema: {job_model.id}") + for model, job in [ + (model, model_to_schema(model, fields_list)) for model in models.items + ]: + if isinstance(job, ValueError): + logger.warning(str(job)) + return NotFoundErrorResponse("Job not found") else: results.append(job) return results @@ -221,7 +226,7 @@ def get_job( if job_model is None: return NotFoundErrorResponse(detail="job not found with the given id") job = model_to_schema(job_model) - if job is None: + if isinstance(job, ValueError): logger.warning("warn: Failed to encode job model to schema.") return NotFoundErrorResponse(detail="job not found with the given id") return job @@ -342,20 +347,23 @@ def cancel_job( } -def decode_job_info(j: Any) -> JobInfo | None: +def decode_job_info(j: Any) -> JobInfo | ValueError: try: - return JobInfo.model_validate(j) - except Exception as _: - return None + jobinfo = JobInfo.model_validate(j) + return jobinfo + except Exception as e: + return ValueError(f"Failed to decode job_info: {str(e)}") -def model_to_schema(model: Job | Row) -> JobDef | GetJobsResponse | None: - if hasattr(model, "job_info"): - job_info = decode_job_info(json.loads(model.job_info)) - else: - job_info = None +def model_to_schema( + model: Job, fields: Optional[list[str]] = None +) -> JobDef | GetJobsResponse | ValueError: + job_info = decode_job_info(json.loads(model.job_info)) - if type(model) is Job and job_info is not None: + if fields is None: + job_info = decode_job_info(json.loads(model.job_info)) + if isinstance(job_info, ValueError): + return job_info return JobDef( job_id=model.id, name=model.name, @@ -371,19 +379,23 @@ def model_to_schema(model: Job | Row) -> JobDef | GetJobsResponse | None: created_at=model.created_at, updated_at=model.updated_at, ) - elif type(model) is Row: - dict_model = {} - for k, v in model._mapping.items(): - if k == "id": - dict_model["job_id"] = v + elif fields is not None: + dict_schema: dict[str, Any] = {} + for k in fields: + if k == "job_id": + dict_schema["job_id"] = model.id elif k == "job_type": - dict_model[k] = JobType(v) + dict_schema[k] = JobType(model.job_type) elif k == "job_info": - dict_model[k] = job_info + job_info = decode_job_info(json.loads(model.job_info)) + if isinstance(job_info, ValueError): + return job_info + else: + dict_schema[k] = job_info elif k == "status": - dict_model[k] = JobStatus(v) + dict_schema[k] = JobStatus(model.status) else: - dict_model[k] = v - return GetJobsResponse(**dict_model) + dict_schema[k] = getattr(model, k) + return GetJobsResponse(**dict_schema) else: return None From ed39a02586c4c7bb8e6d40f6772271186539e6d6 Mon Sep 17 00:00:00 2001 From: shgokita Date: Thu, 26 Dec 2024 15:37:16 +0900 Subject: [PATCH 11/12] chore: fix datetime formats --- backend/oas/provider/openapi.yaml | 12 +++++----- backend/oas/provider/schemas/jobs.yaml | 12 +++++----- backend/oas/user/openapi.yaml | 12 +++++----- backend/oas/user/schemas/jobs.yaml | 12 +++++----- .../oqtopus_cloud/provider/schemas/jobs.py | 12 +++++----- backend/oqtopus_cloud/user/schemas/jobs.py | 24 +++++++++---------- docs/oas/provider/openapi.yaml | 12 +++++----- docs/oas/user/openapi.yaml | 12 +++++----- 8 files changed, 54 insertions(+), 54 deletions(-) diff --git a/backend/oas/provider/openapi.yaml b/backend/oas/provider/openapi.yaml index 3419e04..4490648 100644 --- a/backend/oas/provider/openapi.yaml +++ b/backend/oas/provider/openapi.yaml @@ -517,7 +517,7 @@ components: updated_at: type: string format: date-time - example: '2022-10-19T11:45:34' + example: '2022-10-19T11:45:34+09:00' required: [] example: job_id: 7af020f6-2e38-4d70-8cf0-4349650ea08c @@ -557,8 +557,8 @@ components: job_type: sampling shots: 1000 status: submitted - created_at: '2022-10-19T11:45:34' - updated_at: '2022-10-19T11:45:34' + created_at: '2022-10-19T11:45:34+09:00' + updated_at: '2022-10-19T11:45:34+09:00' jobs.JobDef: type: object properties: @@ -618,7 +618,7 @@ components: updated_at: type: string format: date-time - example: '2022-10-19T11:45:34' + example: '2022-10-19T11:45:34+09:00' required: - job_id - device_id @@ -664,8 +664,8 @@ components: job_type: sampling shots: 1000 status: submitted - created_at: '2022-10-19T11:45:34' - updated_at: '2022-10-19T11:45:34' + created_at: '2022-10-19T11:45:34+09:00' + updated_at: '2022-10-19T11:45:34+09:00' jobs.JobStatusUpdate: type: object properties: diff --git a/backend/oas/provider/schemas/jobs.yaml b/backend/oas/provider/schemas/jobs.yaml index 0782ad3..a0ce7a9 100644 --- a/backend/oas/provider/schemas/jobs.yaml +++ b/backend/oas/provider/schemas/jobs.yaml @@ -159,7 +159,7 @@ jobs.JobDef: updated_at: type: string format: date-time - example: 2022-10-19T11:45:34 + example: 2022-10-19T11:45:34+09:00 required: - job_id - device_id @@ -211,8 +211,8 @@ jobs.JobDef: job_type: sampling shots: 1000 status: submitted - created_at: 2022-10-19T11:45:34 - updated_at: 2022-10-19T11:45:34 + created_at: 2022-10-19T11:45:34+09:00 + updated_at: 2022-10-19T11:45:34+09:00 jobs.GetJobsResponse: type: object @@ -273,7 +273,7 @@ jobs.GetJobsResponse: updated_at: type: string format: date-time - example: 2022-10-19T11:45:34 + example: 2022-10-19T11:45:34+09:00 required: [] example: job_id: 7af020f6-2e38-4d70-8cf0-4349650ea08c @@ -319,8 +319,8 @@ jobs.GetJobsResponse: job_type: sampling shots: 1000 status: submitted - created_at: 2022-10-19T11:45:34 - updated_at: 2022-10-19T11:45:34 + created_at: 2022-10-19T11:45:34+09:00 + updated_at: 2022-10-19T11:45:34+09:00 jobs.JobStatusUpdate: type: object diff --git a/backend/oas/user/openapi.yaml b/backend/oas/user/openapi.yaml index 8fbb79d..e0b8735 100644 --- a/backend/oas/user/openapi.yaml +++ b/backend/oas/user/openapi.yaml @@ -825,11 +825,11 @@ components: created_at: type: string format: date-time - example: '2022-10-19T11:45:34' + example: '2022-10-19T11:45:34+09:00' updated_at: type: string format: date-time - example: '2022-10-19T11:45:34' + example: '2022-10-19T11:45:34+09:00' required: - name - device_id @@ -884,11 +884,11 @@ components: created_at: type: string format: date-time - example: '2022-10-19T11:45:34Z' + example: '2022-10-19T11:45:34+09:00' updated_at: type: string format: date-time - example: '2022-10-19T11:45:34Z' + example: '2022-10-19T11:45:34+09:00' required: - job_id - name @@ -915,8 +915,8 @@ components: mitigation_info: '{ "ro_error_mitigation": "pseudo_inverse" }' shots: 1000 status: submitted - created_at: '2022-10-19T11:45:34' - updated_at: '2022-10-19T11:45:34' + created_at: '2022-10-19T11:45:34+09:00' + updated_at: '2022-10-19T11:45:34+09:00' success.SuccessResponse: type: object properties: diff --git a/backend/oas/user/schemas/jobs.yaml b/backend/oas/user/schemas/jobs.yaml index 88e8610..e49b76c 100644 --- a/backend/oas/user/schemas/jobs.yaml +++ b/backend/oas/user/schemas/jobs.yaml @@ -187,11 +187,11 @@ jobs.JobDef: created_at: type: string format: date-time - example: 2022-10-19T11:45:34Z + example: 2022-10-19T11:45:34+09:00 updated_at: type: string format: date-time - example: 2022-10-19T11:45:34Z + example: 2022-10-19T11:45:34+09:00 required: - job_id - name @@ -221,8 +221,8 @@ jobs.JobDef: { "ro_error_mitigation": "pseudo_inverse" } shots: 1000 status: submitted - created_at: 2022-10-19T11:45:34 - updated_at: 2022-10-19T11:45:34 + created_at: 2022-10-19T11:45:34+09:00 + updated_at: 2022-10-19T11:45:34+09:00 jobs.SubmitJobRequest: @@ -270,11 +270,11 @@ jobs.SubmitJobRequest: created_at: type: string format: date-time - example: 2022-10-19T11:45:34 + example: 2022-10-19T11:45:34+09:00 updated_at: type: string format: date-time - example: 2022-10-19T11:45:34 + example: 2022-10-19T11:45:34+09:00 required: - name - device_id diff --git a/backend/oqtopus_cloud/provider/schemas/jobs.py b/backend/oqtopus_cloud/provider/schemas/jobs.py index e968afe..521938b 100644 --- a/backend/oqtopus_cloud/provider/schemas/jobs.py +++ b/backend/oqtopus_cloud/provider/schemas/jobs.py @@ -109,9 +109,9 @@ class GetJobsResponse(BaseModel): created_at: Annotated[ datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) ] = None - updated_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34"])] = ( - None - ) + updated_at: Annotated[ + datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) + ] = None class JobDef(BaseModel): @@ -144,9 +144,9 @@ class JobDef(BaseModel): ] = None status: JobStatus created_at: Annotated[datetime, Field(examples=["2022-10-19T11:45:34+09:00"])] - updated_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34"])] = ( - None - ) + updated_at: Annotated[ + datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) + ] = None class JobStatusUpdate(BaseModel): diff --git a/backend/oqtopus_cloud/user/schemas/jobs.py b/backend/oqtopus_cloud/user/schemas/jobs.py index 05ca5b7..a93c417 100644 --- a/backend/oqtopus_cloud/user/schemas/jobs.py +++ b/backend/oqtopus_cloud/user/schemas/jobs.py @@ -145,12 +145,12 @@ class SubmitJobRequest(BaseModel): """ shots: Annotated[int, Field(examples=[1000])] status: Annotated[JobStatus | None, Field(examples=["submitted"])] = None - created_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34"])] = ( - None - ) - updated_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34"])] = ( - None - ) + created_at: Annotated[ + datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) + ] = None + updated_at: Annotated[ + datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) + ] = None class SubmitJobResponse(BaseModel): @@ -191,12 +191,12 @@ class JobDef(BaseModel): mitigation_info: Annotated[ str | None, Field(examples=['{\n "ro_error_mitigation": "pseudo_inverse"\n}']) ] = None - created_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34Z"])] = ( - None - ) - updated_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34Z"])] = ( - None - ) + created_at: Annotated[ + datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) + ] = None + updated_at: Annotated[ + datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) + ] = None class GetJobStatusResponse(BaseModel): diff --git a/docs/oas/provider/openapi.yaml b/docs/oas/provider/openapi.yaml index 3419e04..4490648 100644 --- a/docs/oas/provider/openapi.yaml +++ b/docs/oas/provider/openapi.yaml @@ -517,7 +517,7 @@ components: updated_at: type: string format: date-time - example: '2022-10-19T11:45:34' + example: '2022-10-19T11:45:34+09:00' required: [] example: job_id: 7af020f6-2e38-4d70-8cf0-4349650ea08c @@ -557,8 +557,8 @@ components: job_type: sampling shots: 1000 status: submitted - created_at: '2022-10-19T11:45:34' - updated_at: '2022-10-19T11:45:34' + created_at: '2022-10-19T11:45:34+09:00' + updated_at: '2022-10-19T11:45:34+09:00' jobs.JobDef: type: object properties: @@ -618,7 +618,7 @@ components: updated_at: type: string format: date-time - example: '2022-10-19T11:45:34' + example: '2022-10-19T11:45:34+09:00' required: - job_id - device_id @@ -664,8 +664,8 @@ components: job_type: sampling shots: 1000 status: submitted - created_at: '2022-10-19T11:45:34' - updated_at: '2022-10-19T11:45:34' + created_at: '2022-10-19T11:45:34+09:00' + updated_at: '2022-10-19T11:45:34+09:00' jobs.JobStatusUpdate: type: object properties: diff --git a/docs/oas/user/openapi.yaml b/docs/oas/user/openapi.yaml index 8fbb79d..e0b8735 100644 --- a/docs/oas/user/openapi.yaml +++ b/docs/oas/user/openapi.yaml @@ -825,11 +825,11 @@ components: created_at: type: string format: date-time - example: '2022-10-19T11:45:34' + example: '2022-10-19T11:45:34+09:00' updated_at: type: string format: date-time - example: '2022-10-19T11:45:34' + example: '2022-10-19T11:45:34+09:00' required: - name - device_id @@ -884,11 +884,11 @@ components: created_at: type: string format: date-time - example: '2022-10-19T11:45:34Z' + example: '2022-10-19T11:45:34+09:00' updated_at: type: string format: date-time - example: '2022-10-19T11:45:34Z' + example: '2022-10-19T11:45:34+09:00' required: - job_id - name @@ -915,8 +915,8 @@ components: mitigation_info: '{ "ro_error_mitigation": "pseudo_inverse" }' shots: 1000 status: submitted - created_at: '2022-10-19T11:45:34' - updated_at: '2022-10-19T11:45:34' + created_at: '2022-10-19T11:45:34+09:00' + updated_at: '2022-10-19T11:45:34+09:00' success.SuccessResponse: type: object properties: From 28ed01b153e00693781050c12a24005a4ec4d17a Mon Sep 17 00:00:00 2001 From: shgokita Date: Thu, 26 Dec 2024 15:37:16 +0900 Subject: [PATCH 12/12] chore: fix datetime formats --- backend/oas/provider/openapi.yaml | 12 +- backend/oas/provider/schemas/jobs.yaml | 12 +- backend/oas/user/openapi.yaml | 12 +- backend/oas/user/schemas/jobs.yaml | 12 +- .../oqtopus_cloud/provider/schemas/jobs.py | 12 +- backend/oqtopus_cloud/user/schemas/jobs.py | 24 +- docs/oas/provider/openapi.yaml | 12 +- docs/oas/user/openapi.yaml | 12 +- poetry.lock | 809 +++++++++--------- 9 files changed, 461 insertions(+), 456 deletions(-) diff --git a/backend/oas/provider/openapi.yaml b/backend/oas/provider/openapi.yaml index 3419e04..4490648 100644 --- a/backend/oas/provider/openapi.yaml +++ b/backend/oas/provider/openapi.yaml @@ -517,7 +517,7 @@ components: updated_at: type: string format: date-time - example: '2022-10-19T11:45:34' + example: '2022-10-19T11:45:34+09:00' required: [] example: job_id: 7af020f6-2e38-4d70-8cf0-4349650ea08c @@ -557,8 +557,8 @@ components: job_type: sampling shots: 1000 status: submitted - created_at: '2022-10-19T11:45:34' - updated_at: '2022-10-19T11:45:34' + created_at: '2022-10-19T11:45:34+09:00' + updated_at: '2022-10-19T11:45:34+09:00' jobs.JobDef: type: object properties: @@ -618,7 +618,7 @@ components: updated_at: type: string format: date-time - example: '2022-10-19T11:45:34' + example: '2022-10-19T11:45:34+09:00' required: - job_id - device_id @@ -664,8 +664,8 @@ components: job_type: sampling shots: 1000 status: submitted - created_at: '2022-10-19T11:45:34' - updated_at: '2022-10-19T11:45:34' + created_at: '2022-10-19T11:45:34+09:00' + updated_at: '2022-10-19T11:45:34+09:00' jobs.JobStatusUpdate: type: object properties: diff --git a/backend/oas/provider/schemas/jobs.yaml b/backend/oas/provider/schemas/jobs.yaml index 0782ad3..a0ce7a9 100644 --- a/backend/oas/provider/schemas/jobs.yaml +++ b/backend/oas/provider/schemas/jobs.yaml @@ -159,7 +159,7 @@ jobs.JobDef: updated_at: type: string format: date-time - example: 2022-10-19T11:45:34 + example: 2022-10-19T11:45:34+09:00 required: - job_id - device_id @@ -211,8 +211,8 @@ jobs.JobDef: job_type: sampling shots: 1000 status: submitted - created_at: 2022-10-19T11:45:34 - updated_at: 2022-10-19T11:45:34 + created_at: 2022-10-19T11:45:34+09:00 + updated_at: 2022-10-19T11:45:34+09:00 jobs.GetJobsResponse: type: object @@ -273,7 +273,7 @@ jobs.GetJobsResponse: updated_at: type: string format: date-time - example: 2022-10-19T11:45:34 + example: 2022-10-19T11:45:34+09:00 required: [] example: job_id: 7af020f6-2e38-4d70-8cf0-4349650ea08c @@ -319,8 +319,8 @@ jobs.GetJobsResponse: job_type: sampling shots: 1000 status: submitted - created_at: 2022-10-19T11:45:34 - updated_at: 2022-10-19T11:45:34 + created_at: 2022-10-19T11:45:34+09:00 + updated_at: 2022-10-19T11:45:34+09:00 jobs.JobStatusUpdate: type: object diff --git a/backend/oas/user/openapi.yaml b/backend/oas/user/openapi.yaml index 8fbb79d..e0b8735 100644 --- a/backend/oas/user/openapi.yaml +++ b/backend/oas/user/openapi.yaml @@ -825,11 +825,11 @@ components: created_at: type: string format: date-time - example: '2022-10-19T11:45:34' + example: '2022-10-19T11:45:34+09:00' updated_at: type: string format: date-time - example: '2022-10-19T11:45:34' + example: '2022-10-19T11:45:34+09:00' required: - name - device_id @@ -884,11 +884,11 @@ components: created_at: type: string format: date-time - example: '2022-10-19T11:45:34Z' + example: '2022-10-19T11:45:34+09:00' updated_at: type: string format: date-time - example: '2022-10-19T11:45:34Z' + example: '2022-10-19T11:45:34+09:00' required: - job_id - name @@ -915,8 +915,8 @@ components: mitigation_info: '{ "ro_error_mitigation": "pseudo_inverse" }' shots: 1000 status: submitted - created_at: '2022-10-19T11:45:34' - updated_at: '2022-10-19T11:45:34' + created_at: '2022-10-19T11:45:34+09:00' + updated_at: '2022-10-19T11:45:34+09:00' success.SuccessResponse: type: object properties: diff --git a/backend/oas/user/schemas/jobs.yaml b/backend/oas/user/schemas/jobs.yaml index 88e8610..e49b76c 100644 --- a/backend/oas/user/schemas/jobs.yaml +++ b/backend/oas/user/schemas/jobs.yaml @@ -187,11 +187,11 @@ jobs.JobDef: created_at: type: string format: date-time - example: 2022-10-19T11:45:34Z + example: 2022-10-19T11:45:34+09:00 updated_at: type: string format: date-time - example: 2022-10-19T11:45:34Z + example: 2022-10-19T11:45:34+09:00 required: - job_id - name @@ -221,8 +221,8 @@ jobs.JobDef: { "ro_error_mitigation": "pseudo_inverse" } shots: 1000 status: submitted - created_at: 2022-10-19T11:45:34 - updated_at: 2022-10-19T11:45:34 + created_at: 2022-10-19T11:45:34+09:00 + updated_at: 2022-10-19T11:45:34+09:00 jobs.SubmitJobRequest: @@ -270,11 +270,11 @@ jobs.SubmitJobRequest: created_at: type: string format: date-time - example: 2022-10-19T11:45:34 + example: 2022-10-19T11:45:34+09:00 updated_at: type: string format: date-time - example: 2022-10-19T11:45:34 + example: 2022-10-19T11:45:34+09:00 required: - name - device_id diff --git a/backend/oqtopus_cloud/provider/schemas/jobs.py b/backend/oqtopus_cloud/provider/schemas/jobs.py index e968afe..521938b 100644 --- a/backend/oqtopus_cloud/provider/schemas/jobs.py +++ b/backend/oqtopus_cloud/provider/schemas/jobs.py @@ -109,9 +109,9 @@ class GetJobsResponse(BaseModel): created_at: Annotated[ datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) ] = None - updated_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34"])] = ( - None - ) + updated_at: Annotated[ + datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) + ] = None class JobDef(BaseModel): @@ -144,9 +144,9 @@ class JobDef(BaseModel): ] = None status: JobStatus created_at: Annotated[datetime, Field(examples=["2022-10-19T11:45:34+09:00"])] - updated_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34"])] = ( - None - ) + updated_at: Annotated[ + datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) + ] = None class JobStatusUpdate(BaseModel): diff --git a/backend/oqtopus_cloud/user/schemas/jobs.py b/backend/oqtopus_cloud/user/schemas/jobs.py index 05ca5b7..a93c417 100644 --- a/backend/oqtopus_cloud/user/schemas/jobs.py +++ b/backend/oqtopus_cloud/user/schemas/jobs.py @@ -145,12 +145,12 @@ class SubmitJobRequest(BaseModel): """ shots: Annotated[int, Field(examples=[1000])] status: Annotated[JobStatus | None, Field(examples=["submitted"])] = None - created_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34"])] = ( - None - ) - updated_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34"])] = ( - None - ) + created_at: Annotated[ + datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) + ] = None + updated_at: Annotated[ + datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) + ] = None class SubmitJobResponse(BaseModel): @@ -191,12 +191,12 @@ class JobDef(BaseModel): mitigation_info: Annotated[ str | None, Field(examples=['{\n "ro_error_mitigation": "pseudo_inverse"\n}']) ] = None - created_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34Z"])] = ( - None - ) - updated_at: Annotated[datetime | None, Field(examples=["2022-10-19T11:45:34Z"])] = ( - None - ) + created_at: Annotated[ + datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) + ] = None + updated_at: Annotated[ + datetime | None, Field(examples=["2022-10-19T11:45:34+09:00"]) + ] = None class GetJobStatusResponse(BaseModel): diff --git a/docs/oas/provider/openapi.yaml b/docs/oas/provider/openapi.yaml index 3419e04..4490648 100644 --- a/docs/oas/provider/openapi.yaml +++ b/docs/oas/provider/openapi.yaml @@ -517,7 +517,7 @@ components: updated_at: type: string format: date-time - example: '2022-10-19T11:45:34' + example: '2022-10-19T11:45:34+09:00' required: [] example: job_id: 7af020f6-2e38-4d70-8cf0-4349650ea08c @@ -557,8 +557,8 @@ components: job_type: sampling shots: 1000 status: submitted - created_at: '2022-10-19T11:45:34' - updated_at: '2022-10-19T11:45:34' + created_at: '2022-10-19T11:45:34+09:00' + updated_at: '2022-10-19T11:45:34+09:00' jobs.JobDef: type: object properties: @@ -618,7 +618,7 @@ components: updated_at: type: string format: date-time - example: '2022-10-19T11:45:34' + example: '2022-10-19T11:45:34+09:00' required: - job_id - device_id @@ -664,8 +664,8 @@ components: job_type: sampling shots: 1000 status: submitted - created_at: '2022-10-19T11:45:34' - updated_at: '2022-10-19T11:45:34' + created_at: '2022-10-19T11:45:34+09:00' + updated_at: '2022-10-19T11:45:34+09:00' jobs.JobStatusUpdate: type: object properties: diff --git a/docs/oas/user/openapi.yaml b/docs/oas/user/openapi.yaml index 8fbb79d..e0b8735 100644 --- a/docs/oas/user/openapi.yaml +++ b/docs/oas/user/openapi.yaml @@ -825,11 +825,11 @@ components: created_at: type: string format: date-time - example: '2022-10-19T11:45:34' + example: '2022-10-19T11:45:34+09:00' updated_at: type: string format: date-time - example: '2022-10-19T11:45:34' + example: '2022-10-19T11:45:34+09:00' required: - name - device_id @@ -884,11 +884,11 @@ components: created_at: type: string format: date-time - example: '2022-10-19T11:45:34Z' + example: '2022-10-19T11:45:34+09:00' updated_at: type: string format: date-time - example: '2022-10-19T11:45:34Z' + example: '2022-10-19T11:45:34+09:00' required: - job_id - name @@ -915,8 +915,8 @@ components: mitigation_info: '{ "ro_error_mitigation": "pseudo_inverse" }' shots: 1000 status: submitted - created_at: '2022-10-19T11:45:34' - updated_at: '2022-10-19T11:45:34' + created_at: '2022-10-19T11:45:34+09:00' + updated_at: '2022-10-19T11:45:34+09:00' success.SuccessResponse: type: object properties: diff --git a/poetry.lock b/poetry.lock index 7c26160..0127fbf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 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" @@ -13,33 +13,34 @@ files = [ [[package]] name = "anyio" -version = "4.6.2.post1" +version = "4.7.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" files = [ - {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"}, - {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"}, + {file = "anyio-4.7.0-py3-none-any.whl", hash = "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352"}, + {file = "anyio-4.7.0.tar.gz", hash = "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48"}, ] [package.dependencies] idna = ">=2.8" sniffio = ">=1.1" +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] +doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] trio = ["trio (>=0.26.1)"] [[package]] name = "argcomplete" -version = "3.5.1" +version = "3.5.2" description = "Bash tab completion for argparse" optional = false python-versions = ">=3.8" files = [ - {file = "argcomplete-3.5.1-py3-none-any.whl", hash = "sha256:1a1d148bdaa3e3b93454900163403df41448a248af01b6e849edc5ac08e6c363"}, - {file = "argcomplete-3.5.1.tar.gz", hash = "sha256:eb1ee355aa2557bd3d0145de7b06b2a45b0ce461e1e7813f5d066039ab4177b4"}, + {file = "argcomplete-3.5.2-py3-none-any.whl", hash = "sha256:036d020d79048a5d525bc63880d7a4b8d1668566b8a76daf1144c0bbe0f63472"}, + {file = "argcomplete-3.5.2.tar.gz", hash = "sha256:23146ed7ac4403b70bd6026402468942ceba34a6732255b9edf5b7354f68a6bb"}, ] [package.extras] @@ -166,17 +167,17 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "boto3" -version = "1.35.60" +version = "1.35.87" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" files = [ - {file = "boto3-1.35.60-py3-none-any.whl", hash = "sha256:a34d28de1a1f6ca6ec3edd05c26db16e422293d8f9dcd94f308059a434596753"}, - {file = "boto3-1.35.60.tar.gz", hash = "sha256:e573504c67c3e438fd4b0222119ed1a73b644c78eb3b6dee0b36a6c70ecf7677"}, + {file = "boto3-1.35.87-py3-none-any.whl", hash = "sha256:588ab05e2771c50fca5c242be14e7a25200ffd3dd95c45950ce40993473864c7"}, + {file = "boto3-1.35.87.tar.gz", hash = "sha256:341c58602889078a4a25dc4331b832b5b600a33acd73471d2532c6f01b16fbb4"}, ] [package.dependencies] -botocore = ">=1.35.60,<1.36.0" +botocore = ">=1.35.87,<1.36.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -185,13 +186,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "boto3-stubs" -version = "1.35.60" -description = "Type annotations for boto3 1.35.60 generated with mypy-boto3-builder 8.2.1" +version = "1.35.87" +description = "Type annotations for boto3 1.35.87 generated with mypy-boto3-builder 8.7.0" optional = false python-versions = ">=3.8" files = [ - {file = "boto3_stubs-1.35.60-py3-none-any.whl", hash = "sha256:916f3fcdef27ccdab2d39b60b39671407c6c8323b8329556e6c175a80d010b09"}, - {file = "boto3_stubs-1.35.60.tar.gz", hash = "sha256:48908c8f3700b36f853514b40c8e5c64b02c62adfc632adddb85b3c28673e058"}, + {file = "boto3_stubs-1.35.87-py3-none-any.whl", hash = "sha256:76bb623169ee670ca04c07ccdde5218380b7ccc9803b2730e90e436fb42f4298"}, + {file = "boto3_stubs-1.35.87.tar.gz", hash = "sha256:85c1a54f30e33b5ab3946133275bef3fce1f7ae8fd97525532310f573bd0e38e"}, ] [package.dependencies] @@ -203,7 +204,7 @@ accessanalyzer = ["mypy-boto3-accessanalyzer (>=1.35.0,<1.36.0)"] account = ["mypy-boto3-account (>=1.35.0,<1.36.0)"] acm = ["mypy-boto3-acm (>=1.35.0,<1.36.0)"] acm-pca = ["mypy-boto3-acm-pca (>=1.35.0,<1.36.0)"] -all = ["mypy-boto3-accessanalyzer (>=1.35.0,<1.36.0)", "mypy-boto3-account (>=1.35.0,<1.36.0)", "mypy-boto3-acm (>=1.35.0,<1.36.0)", "mypy-boto3-acm-pca (>=1.35.0,<1.36.0)", "mypy-boto3-amp (>=1.35.0,<1.36.0)", "mypy-boto3-amplify (>=1.35.0,<1.36.0)", "mypy-boto3-amplifybackend (>=1.35.0,<1.36.0)", "mypy-boto3-amplifyuibuilder (>=1.35.0,<1.36.0)", "mypy-boto3-apigateway (>=1.35.0,<1.36.0)", "mypy-boto3-apigatewaymanagementapi (>=1.35.0,<1.36.0)", "mypy-boto3-apigatewayv2 (>=1.35.0,<1.36.0)", "mypy-boto3-appconfig (>=1.35.0,<1.36.0)", "mypy-boto3-appconfigdata (>=1.35.0,<1.36.0)", "mypy-boto3-appfabric (>=1.35.0,<1.36.0)", "mypy-boto3-appflow (>=1.35.0,<1.36.0)", "mypy-boto3-appintegrations (>=1.35.0,<1.36.0)", "mypy-boto3-application-autoscaling (>=1.35.0,<1.36.0)", "mypy-boto3-application-insights (>=1.35.0,<1.36.0)", "mypy-boto3-application-signals (>=1.35.0,<1.36.0)", "mypy-boto3-applicationcostprofiler (>=1.35.0,<1.36.0)", "mypy-boto3-appmesh (>=1.35.0,<1.36.0)", "mypy-boto3-apprunner (>=1.35.0,<1.36.0)", "mypy-boto3-appstream (>=1.35.0,<1.36.0)", "mypy-boto3-appsync (>=1.35.0,<1.36.0)", "mypy-boto3-apptest (>=1.35.0,<1.36.0)", "mypy-boto3-arc-zonal-shift (>=1.35.0,<1.36.0)", "mypy-boto3-artifact (>=1.35.0,<1.36.0)", "mypy-boto3-athena (>=1.35.0,<1.36.0)", "mypy-boto3-auditmanager (>=1.35.0,<1.36.0)", "mypy-boto3-autoscaling (>=1.35.0,<1.36.0)", "mypy-boto3-autoscaling-plans (>=1.35.0,<1.36.0)", "mypy-boto3-b2bi (>=1.35.0,<1.36.0)", "mypy-boto3-backup (>=1.35.0,<1.36.0)", "mypy-boto3-backup-gateway (>=1.35.0,<1.36.0)", "mypy-boto3-batch (>=1.35.0,<1.36.0)", "mypy-boto3-bcm-data-exports (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock-agent (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock-agent-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-billing (>=1.35.0,<1.36.0)", "mypy-boto3-billingconductor (>=1.35.0,<1.36.0)", "mypy-boto3-braket (>=1.35.0,<1.36.0)", "mypy-boto3-budgets (>=1.35.0,<1.36.0)", "mypy-boto3-ce (>=1.35.0,<1.36.0)", "mypy-boto3-chatbot (>=1.35.0,<1.36.0)", "mypy-boto3-chime (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-identity (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-media-pipelines (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-meetings (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-messaging (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-voice (>=1.35.0,<1.36.0)", "mypy-boto3-cleanrooms (>=1.35.0,<1.36.0)", "mypy-boto3-cleanroomsml (>=1.35.0,<1.36.0)", "mypy-boto3-cloud9 (>=1.35.0,<1.36.0)", "mypy-boto3-cloudcontrol (>=1.35.0,<1.36.0)", "mypy-boto3-clouddirectory (>=1.35.0,<1.36.0)", "mypy-boto3-cloudformation (>=1.35.0,<1.36.0)", "mypy-boto3-cloudfront (>=1.35.0,<1.36.0)", "mypy-boto3-cloudfront-keyvaluestore (>=1.35.0,<1.36.0)", "mypy-boto3-cloudhsm (>=1.35.0,<1.36.0)", "mypy-boto3-cloudhsmv2 (>=1.35.0,<1.36.0)", "mypy-boto3-cloudsearch (>=1.35.0,<1.36.0)", "mypy-boto3-cloudsearchdomain (>=1.35.0,<1.36.0)", "mypy-boto3-cloudtrail (>=1.35.0,<1.36.0)", "mypy-boto3-cloudtrail-data (>=1.35.0,<1.36.0)", "mypy-boto3-cloudwatch (>=1.35.0,<1.36.0)", "mypy-boto3-codeartifact (>=1.35.0,<1.36.0)", "mypy-boto3-codebuild (>=1.35.0,<1.36.0)", "mypy-boto3-codecatalyst (>=1.35.0,<1.36.0)", "mypy-boto3-codecommit (>=1.35.0,<1.36.0)", "mypy-boto3-codeconnections (>=1.35.0,<1.36.0)", "mypy-boto3-codedeploy (>=1.35.0,<1.36.0)", "mypy-boto3-codeguru-reviewer (>=1.35.0,<1.36.0)", "mypy-boto3-codeguru-security (>=1.35.0,<1.36.0)", "mypy-boto3-codeguruprofiler (>=1.35.0,<1.36.0)", "mypy-boto3-codepipeline (>=1.35.0,<1.36.0)", "mypy-boto3-codestar-connections (>=1.35.0,<1.36.0)", "mypy-boto3-codestar-notifications (>=1.35.0,<1.36.0)", "mypy-boto3-cognito-identity (>=1.35.0,<1.36.0)", "mypy-boto3-cognito-idp (>=1.35.0,<1.36.0)", "mypy-boto3-cognito-sync (>=1.35.0,<1.36.0)", "mypy-boto3-comprehend (>=1.35.0,<1.36.0)", "mypy-boto3-comprehendmedical (>=1.35.0,<1.36.0)", "mypy-boto3-compute-optimizer (>=1.35.0,<1.36.0)", "mypy-boto3-config (>=1.35.0,<1.36.0)", "mypy-boto3-connect (>=1.35.0,<1.36.0)", "mypy-boto3-connect-contact-lens (>=1.35.0,<1.36.0)", "mypy-boto3-connectcampaigns (>=1.35.0,<1.36.0)", "mypy-boto3-connectcases (>=1.35.0,<1.36.0)", "mypy-boto3-connectparticipant (>=1.35.0,<1.36.0)", "mypy-boto3-controlcatalog (>=1.35.0,<1.36.0)", "mypy-boto3-controltower (>=1.35.0,<1.36.0)", "mypy-boto3-cost-optimization-hub (>=1.35.0,<1.36.0)", "mypy-boto3-cur (>=1.35.0,<1.36.0)", "mypy-boto3-customer-profiles (>=1.35.0,<1.36.0)", "mypy-boto3-databrew (>=1.35.0,<1.36.0)", "mypy-boto3-dataexchange (>=1.35.0,<1.36.0)", "mypy-boto3-datapipeline (>=1.35.0,<1.36.0)", "mypy-boto3-datasync (>=1.35.0,<1.36.0)", "mypy-boto3-datazone (>=1.35.0,<1.36.0)", "mypy-boto3-dax (>=1.35.0,<1.36.0)", "mypy-boto3-deadline (>=1.35.0,<1.36.0)", "mypy-boto3-detective (>=1.35.0,<1.36.0)", "mypy-boto3-devicefarm (>=1.35.0,<1.36.0)", "mypy-boto3-devops-guru (>=1.35.0,<1.36.0)", "mypy-boto3-directconnect (>=1.35.0,<1.36.0)", "mypy-boto3-discovery (>=1.35.0,<1.36.0)", "mypy-boto3-dlm (>=1.35.0,<1.36.0)", "mypy-boto3-dms (>=1.35.0,<1.36.0)", "mypy-boto3-docdb (>=1.35.0,<1.36.0)", "mypy-boto3-docdb-elastic (>=1.35.0,<1.36.0)", "mypy-boto3-drs (>=1.35.0,<1.36.0)", "mypy-boto3-ds (>=1.35.0,<1.36.0)", "mypy-boto3-ds-data (>=1.35.0,<1.36.0)", "mypy-boto3-dynamodb (>=1.35.0,<1.36.0)", "mypy-boto3-dynamodbstreams (>=1.35.0,<1.36.0)", "mypy-boto3-ebs (>=1.35.0,<1.36.0)", "mypy-boto3-ec2 (>=1.35.0,<1.36.0)", "mypy-boto3-ec2-instance-connect (>=1.35.0,<1.36.0)", "mypy-boto3-ecr (>=1.35.0,<1.36.0)", "mypy-boto3-ecr-public (>=1.35.0,<1.36.0)", "mypy-boto3-ecs (>=1.35.0,<1.36.0)", "mypy-boto3-efs (>=1.35.0,<1.36.0)", "mypy-boto3-eks (>=1.35.0,<1.36.0)", "mypy-boto3-eks-auth (>=1.35.0,<1.36.0)", "mypy-boto3-elastic-inference (>=1.35.0,<1.36.0)", "mypy-boto3-elasticache (>=1.35.0,<1.36.0)", "mypy-boto3-elasticbeanstalk (>=1.35.0,<1.36.0)", "mypy-boto3-elastictranscoder (>=1.35.0,<1.36.0)", "mypy-boto3-elb (>=1.35.0,<1.36.0)", "mypy-boto3-elbv2 (>=1.35.0,<1.36.0)", "mypy-boto3-emr (>=1.35.0,<1.36.0)", "mypy-boto3-emr-containers (>=1.35.0,<1.36.0)", "mypy-boto3-emr-serverless (>=1.35.0,<1.36.0)", "mypy-boto3-entityresolution (>=1.35.0,<1.36.0)", "mypy-boto3-es (>=1.35.0,<1.36.0)", "mypy-boto3-events (>=1.35.0,<1.36.0)", "mypy-boto3-evidently (>=1.35.0,<1.36.0)", "mypy-boto3-finspace (>=1.35.0,<1.36.0)", "mypy-boto3-finspace-data (>=1.35.0,<1.36.0)", "mypy-boto3-firehose (>=1.35.0,<1.36.0)", "mypy-boto3-fis (>=1.35.0,<1.36.0)", "mypy-boto3-fms (>=1.35.0,<1.36.0)", "mypy-boto3-forecast (>=1.35.0,<1.36.0)", "mypy-boto3-forecastquery (>=1.35.0,<1.36.0)", "mypy-boto3-frauddetector (>=1.35.0,<1.36.0)", "mypy-boto3-freetier (>=1.35.0,<1.36.0)", "mypy-boto3-fsx (>=1.35.0,<1.36.0)", "mypy-boto3-gamelift (>=1.35.0,<1.36.0)", "mypy-boto3-geo-maps (>=1.35.0,<1.36.0)", "mypy-boto3-geo-places (>=1.35.0,<1.36.0)", "mypy-boto3-geo-routes (>=1.35.0,<1.36.0)", "mypy-boto3-glacier (>=1.35.0,<1.36.0)", "mypy-boto3-globalaccelerator (>=1.35.0,<1.36.0)", "mypy-boto3-glue (>=1.35.0,<1.36.0)", "mypy-boto3-grafana (>=1.35.0,<1.36.0)", "mypy-boto3-greengrass (>=1.35.0,<1.36.0)", "mypy-boto3-greengrassv2 (>=1.35.0,<1.36.0)", "mypy-boto3-groundstation (>=1.35.0,<1.36.0)", "mypy-boto3-guardduty (>=1.35.0,<1.36.0)", "mypy-boto3-health (>=1.35.0,<1.36.0)", "mypy-boto3-healthlake (>=1.35.0,<1.36.0)", "mypy-boto3-iam (>=1.35.0,<1.36.0)", "mypy-boto3-identitystore (>=1.35.0,<1.36.0)", "mypy-boto3-imagebuilder (>=1.35.0,<1.36.0)", "mypy-boto3-importexport (>=1.35.0,<1.36.0)", "mypy-boto3-inspector (>=1.35.0,<1.36.0)", "mypy-boto3-inspector-scan (>=1.35.0,<1.36.0)", "mypy-boto3-inspector2 (>=1.35.0,<1.36.0)", "mypy-boto3-internetmonitor (>=1.35.0,<1.36.0)", "mypy-boto3-iot (>=1.35.0,<1.36.0)", "mypy-boto3-iot-data (>=1.35.0,<1.36.0)", "mypy-boto3-iot-jobs-data (>=1.35.0,<1.36.0)", "mypy-boto3-iot1click-devices (>=1.35.0,<1.36.0)", "mypy-boto3-iot1click-projects (>=1.35.0,<1.36.0)", "mypy-boto3-iotanalytics (>=1.35.0,<1.36.0)", "mypy-boto3-iotdeviceadvisor (>=1.35.0,<1.36.0)", "mypy-boto3-iotevents (>=1.35.0,<1.36.0)", "mypy-boto3-iotevents-data (>=1.35.0,<1.36.0)", "mypy-boto3-iotfleethub (>=1.35.0,<1.36.0)", "mypy-boto3-iotfleetwise (>=1.35.0,<1.36.0)", "mypy-boto3-iotsecuretunneling (>=1.35.0,<1.36.0)", "mypy-boto3-iotsitewise (>=1.35.0,<1.36.0)", "mypy-boto3-iotthingsgraph (>=1.35.0,<1.36.0)", "mypy-boto3-iottwinmaker (>=1.35.0,<1.36.0)", "mypy-boto3-iotwireless (>=1.35.0,<1.36.0)", "mypy-boto3-ivs (>=1.35.0,<1.36.0)", "mypy-boto3-ivs-realtime (>=1.35.0,<1.36.0)", "mypy-boto3-ivschat (>=1.35.0,<1.36.0)", "mypy-boto3-kafka (>=1.35.0,<1.36.0)", "mypy-boto3-kafkaconnect (>=1.35.0,<1.36.0)", "mypy-boto3-kendra (>=1.35.0,<1.36.0)", "mypy-boto3-kendra-ranking (>=1.35.0,<1.36.0)", "mypy-boto3-keyspaces (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis-video-archived-media (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis-video-media (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis-video-signaling (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis-video-webrtc-storage (>=1.35.0,<1.36.0)", "mypy-boto3-kinesisanalytics (>=1.35.0,<1.36.0)", "mypy-boto3-kinesisanalyticsv2 (>=1.35.0,<1.36.0)", "mypy-boto3-kinesisvideo (>=1.35.0,<1.36.0)", "mypy-boto3-kms (>=1.35.0,<1.36.0)", "mypy-boto3-lakeformation (>=1.35.0,<1.36.0)", "mypy-boto3-lambda (>=1.35.0,<1.36.0)", "mypy-boto3-launch-wizard (>=1.35.0,<1.36.0)", "mypy-boto3-lex-models (>=1.35.0,<1.36.0)", "mypy-boto3-lex-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-lexv2-models (>=1.35.0,<1.36.0)", "mypy-boto3-lexv2-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-license-manager (>=1.35.0,<1.36.0)", "mypy-boto3-license-manager-linux-subscriptions (>=1.35.0,<1.36.0)", "mypy-boto3-license-manager-user-subscriptions (>=1.35.0,<1.36.0)", "mypy-boto3-lightsail (>=1.35.0,<1.36.0)", "mypy-boto3-location (>=1.35.0,<1.36.0)", "mypy-boto3-logs (>=1.35.0,<1.36.0)", "mypy-boto3-lookoutequipment (>=1.35.0,<1.36.0)", "mypy-boto3-lookoutmetrics (>=1.35.0,<1.36.0)", "mypy-boto3-lookoutvision (>=1.35.0,<1.36.0)", "mypy-boto3-m2 (>=1.35.0,<1.36.0)", "mypy-boto3-machinelearning (>=1.35.0,<1.36.0)", "mypy-boto3-macie2 (>=1.35.0,<1.36.0)", "mypy-boto3-mailmanager (>=1.35.0,<1.36.0)", "mypy-boto3-managedblockchain (>=1.35.0,<1.36.0)", "mypy-boto3-managedblockchain-query (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-agreement (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-catalog (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-deployment (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-entitlement (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-reporting (>=1.35.0,<1.36.0)", "mypy-boto3-marketplacecommerceanalytics (>=1.35.0,<1.36.0)", "mypy-boto3-mediaconnect (>=1.35.0,<1.36.0)", "mypy-boto3-mediaconvert (>=1.35.0,<1.36.0)", "mypy-boto3-medialive (>=1.35.0,<1.36.0)", "mypy-boto3-mediapackage (>=1.35.0,<1.36.0)", "mypy-boto3-mediapackage-vod (>=1.35.0,<1.36.0)", "mypy-boto3-mediapackagev2 (>=1.35.0,<1.36.0)", "mypy-boto3-mediastore (>=1.35.0,<1.36.0)", "mypy-boto3-mediastore-data (>=1.35.0,<1.36.0)", "mypy-boto3-mediatailor (>=1.35.0,<1.36.0)", "mypy-boto3-medical-imaging (>=1.35.0,<1.36.0)", "mypy-boto3-memorydb (>=1.35.0,<1.36.0)", "mypy-boto3-meteringmarketplace (>=1.35.0,<1.36.0)", "mypy-boto3-mgh (>=1.35.0,<1.36.0)", "mypy-boto3-mgn (>=1.35.0,<1.36.0)", "mypy-boto3-migration-hub-refactor-spaces (>=1.35.0,<1.36.0)", "mypy-boto3-migrationhub-config (>=1.35.0,<1.36.0)", "mypy-boto3-migrationhuborchestrator (>=1.35.0,<1.36.0)", "mypy-boto3-migrationhubstrategy (>=1.35.0,<1.36.0)", "mypy-boto3-mq (>=1.35.0,<1.36.0)", "mypy-boto3-mturk (>=1.35.0,<1.36.0)", "mypy-boto3-mwaa (>=1.35.0,<1.36.0)", "mypy-boto3-neptune (>=1.35.0,<1.36.0)", "mypy-boto3-neptune-graph (>=1.35.0,<1.36.0)", "mypy-boto3-neptunedata (>=1.35.0,<1.36.0)", "mypy-boto3-network-firewall (>=1.35.0,<1.36.0)", "mypy-boto3-networkmanager (>=1.35.0,<1.36.0)", "mypy-boto3-networkmonitor (>=1.35.0,<1.36.0)", "mypy-boto3-oam (>=1.35.0,<1.36.0)", "mypy-boto3-omics (>=1.35.0,<1.36.0)", "mypy-boto3-opensearch (>=1.35.0,<1.36.0)", "mypy-boto3-opensearchserverless (>=1.35.0,<1.36.0)", "mypy-boto3-opsworks (>=1.35.0,<1.36.0)", "mypy-boto3-opsworkscm (>=1.35.0,<1.36.0)", "mypy-boto3-organizations (>=1.35.0,<1.36.0)", "mypy-boto3-osis (>=1.35.0,<1.36.0)", "mypy-boto3-outposts (>=1.35.0,<1.36.0)", "mypy-boto3-panorama (>=1.35.0,<1.36.0)", "mypy-boto3-payment-cryptography (>=1.35.0,<1.36.0)", "mypy-boto3-payment-cryptography-data (>=1.35.0,<1.36.0)", "mypy-boto3-pca-connector-ad (>=1.35.0,<1.36.0)", "mypy-boto3-pca-connector-scep (>=1.35.0,<1.36.0)", "mypy-boto3-pcs (>=1.35.0,<1.36.0)", "mypy-boto3-personalize (>=1.35.0,<1.36.0)", "mypy-boto3-personalize-events (>=1.35.0,<1.36.0)", "mypy-boto3-personalize-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-pi (>=1.35.0,<1.36.0)", "mypy-boto3-pinpoint (>=1.35.0,<1.36.0)", "mypy-boto3-pinpoint-email (>=1.35.0,<1.36.0)", "mypy-boto3-pinpoint-sms-voice (>=1.35.0,<1.36.0)", "mypy-boto3-pinpoint-sms-voice-v2 (>=1.35.0,<1.36.0)", "mypy-boto3-pipes (>=1.35.0,<1.36.0)", "mypy-boto3-polly (>=1.35.0,<1.36.0)", "mypy-boto3-pricing (>=1.35.0,<1.36.0)", "mypy-boto3-privatenetworks (>=1.35.0,<1.36.0)", "mypy-boto3-proton (>=1.35.0,<1.36.0)", "mypy-boto3-qapps (>=1.35.0,<1.36.0)", "mypy-boto3-qbusiness (>=1.35.0,<1.36.0)", "mypy-boto3-qconnect (>=1.35.0,<1.36.0)", "mypy-boto3-qldb (>=1.35.0,<1.36.0)", "mypy-boto3-qldb-session (>=1.35.0,<1.36.0)", "mypy-boto3-quicksight (>=1.35.0,<1.36.0)", "mypy-boto3-ram (>=1.35.0,<1.36.0)", "mypy-boto3-rbin (>=1.35.0,<1.36.0)", "mypy-boto3-rds (>=1.35.0,<1.36.0)", "mypy-boto3-rds-data (>=1.35.0,<1.36.0)", "mypy-boto3-redshift (>=1.35.0,<1.36.0)", "mypy-boto3-redshift-data (>=1.35.0,<1.36.0)", "mypy-boto3-redshift-serverless (>=1.35.0,<1.36.0)", "mypy-boto3-rekognition (>=1.35.0,<1.36.0)", "mypy-boto3-repostspace (>=1.35.0,<1.36.0)", "mypy-boto3-resiliencehub (>=1.35.0,<1.36.0)", "mypy-boto3-resource-explorer-2 (>=1.35.0,<1.36.0)", "mypy-boto3-resource-groups (>=1.35.0,<1.36.0)", "mypy-boto3-resourcegroupstaggingapi (>=1.35.0,<1.36.0)", "mypy-boto3-robomaker (>=1.35.0,<1.36.0)", "mypy-boto3-rolesanywhere (>=1.35.0,<1.36.0)", "mypy-boto3-route53 (>=1.35.0,<1.36.0)", "mypy-boto3-route53-recovery-cluster (>=1.35.0,<1.36.0)", "mypy-boto3-route53-recovery-control-config (>=1.35.0,<1.36.0)", "mypy-boto3-route53-recovery-readiness (>=1.35.0,<1.36.0)", "mypy-boto3-route53domains (>=1.35.0,<1.36.0)", "mypy-boto3-route53profiles (>=1.35.0,<1.36.0)", "mypy-boto3-route53resolver (>=1.35.0,<1.36.0)", "mypy-boto3-rum (>=1.35.0,<1.36.0)", "mypy-boto3-s3 (>=1.35.0,<1.36.0)", "mypy-boto3-s3control (>=1.35.0,<1.36.0)", "mypy-boto3-s3outposts (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-a2i-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-edge (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-featurestore-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-geospatial (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-metrics (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-savingsplans (>=1.35.0,<1.36.0)", "mypy-boto3-scheduler (>=1.35.0,<1.36.0)", "mypy-boto3-schemas (>=1.35.0,<1.36.0)", "mypy-boto3-sdb (>=1.35.0,<1.36.0)", "mypy-boto3-secretsmanager (>=1.35.0,<1.36.0)", "mypy-boto3-securityhub (>=1.35.0,<1.36.0)", "mypy-boto3-securitylake (>=1.35.0,<1.36.0)", "mypy-boto3-serverlessrepo (>=1.35.0,<1.36.0)", "mypy-boto3-service-quotas (>=1.35.0,<1.36.0)", "mypy-boto3-servicecatalog (>=1.35.0,<1.36.0)", "mypy-boto3-servicecatalog-appregistry (>=1.35.0,<1.36.0)", "mypy-boto3-servicediscovery (>=1.35.0,<1.36.0)", "mypy-boto3-ses (>=1.35.0,<1.36.0)", "mypy-boto3-sesv2 (>=1.35.0,<1.36.0)", "mypy-boto3-shield (>=1.35.0,<1.36.0)", "mypy-boto3-signer (>=1.35.0,<1.36.0)", "mypy-boto3-simspaceweaver (>=1.35.0,<1.36.0)", "mypy-boto3-sms (>=1.35.0,<1.36.0)", "mypy-boto3-sms-voice (>=1.35.0,<1.36.0)", "mypy-boto3-snow-device-management (>=1.35.0,<1.36.0)", "mypy-boto3-snowball (>=1.35.0,<1.36.0)", "mypy-boto3-sns (>=1.35.0,<1.36.0)", "mypy-boto3-socialmessaging (>=1.35.0,<1.36.0)", "mypy-boto3-sqs (>=1.35.0,<1.36.0)", "mypy-boto3-ssm (>=1.35.0,<1.36.0)", "mypy-boto3-ssm-contacts (>=1.35.0,<1.36.0)", "mypy-boto3-ssm-incidents (>=1.35.0,<1.36.0)", "mypy-boto3-ssm-quicksetup (>=1.35.0,<1.36.0)", "mypy-boto3-ssm-sap (>=1.35.0,<1.36.0)", "mypy-boto3-sso (>=1.35.0,<1.36.0)", "mypy-boto3-sso-admin (>=1.35.0,<1.36.0)", "mypy-boto3-sso-oidc (>=1.35.0,<1.36.0)", "mypy-boto3-stepfunctions (>=1.35.0,<1.36.0)", "mypy-boto3-storagegateway (>=1.35.0,<1.36.0)", "mypy-boto3-sts (>=1.35.0,<1.36.0)", "mypy-boto3-supplychain (>=1.35.0,<1.36.0)", "mypy-boto3-support (>=1.35.0,<1.36.0)", "mypy-boto3-support-app (>=1.35.0,<1.36.0)", "mypy-boto3-swf (>=1.35.0,<1.36.0)", "mypy-boto3-synthetics (>=1.35.0,<1.36.0)", "mypy-boto3-taxsettings (>=1.35.0,<1.36.0)", "mypy-boto3-textract (>=1.35.0,<1.36.0)", "mypy-boto3-timestream-influxdb (>=1.35.0,<1.36.0)", "mypy-boto3-timestream-query (>=1.35.0,<1.36.0)", "mypy-boto3-timestream-write (>=1.35.0,<1.36.0)", "mypy-boto3-tnb (>=1.35.0,<1.36.0)", "mypy-boto3-transcribe (>=1.35.0,<1.36.0)", "mypy-boto3-transfer (>=1.35.0,<1.36.0)", "mypy-boto3-translate (>=1.35.0,<1.36.0)", "mypy-boto3-trustedadvisor (>=1.35.0,<1.36.0)", "mypy-boto3-verifiedpermissions (>=1.35.0,<1.36.0)", "mypy-boto3-voice-id (>=1.35.0,<1.36.0)", "mypy-boto3-vpc-lattice (>=1.35.0,<1.36.0)", "mypy-boto3-waf (>=1.35.0,<1.36.0)", "mypy-boto3-waf-regional (>=1.35.0,<1.36.0)", "mypy-boto3-wafv2 (>=1.35.0,<1.36.0)", "mypy-boto3-wellarchitected (>=1.35.0,<1.36.0)", "mypy-boto3-wisdom (>=1.35.0,<1.36.0)", "mypy-boto3-workdocs (>=1.35.0,<1.36.0)", "mypy-boto3-workmail (>=1.35.0,<1.36.0)", "mypy-boto3-workmailmessageflow (>=1.35.0,<1.36.0)", "mypy-boto3-workspaces (>=1.35.0,<1.36.0)", "mypy-boto3-workspaces-thin-client (>=1.35.0,<1.36.0)", "mypy-boto3-workspaces-web (>=1.35.0,<1.36.0)", "mypy-boto3-xray (>=1.35.0,<1.36.0)"] +all = ["mypy-boto3-accessanalyzer (>=1.35.0,<1.36.0)", "mypy-boto3-account (>=1.35.0,<1.36.0)", "mypy-boto3-acm (>=1.35.0,<1.36.0)", "mypy-boto3-acm-pca (>=1.35.0,<1.36.0)", "mypy-boto3-amp (>=1.35.0,<1.36.0)", "mypy-boto3-amplify (>=1.35.0,<1.36.0)", "mypy-boto3-amplifybackend (>=1.35.0,<1.36.0)", "mypy-boto3-amplifyuibuilder (>=1.35.0,<1.36.0)", "mypy-boto3-apigateway (>=1.35.0,<1.36.0)", "mypy-boto3-apigatewaymanagementapi (>=1.35.0,<1.36.0)", "mypy-boto3-apigatewayv2 (>=1.35.0,<1.36.0)", "mypy-boto3-appconfig (>=1.35.0,<1.36.0)", "mypy-boto3-appconfigdata (>=1.35.0,<1.36.0)", "mypy-boto3-appfabric (>=1.35.0,<1.36.0)", "mypy-boto3-appflow (>=1.35.0,<1.36.0)", "mypy-boto3-appintegrations (>=1.35.0,<1.36.0)", "mypy-boto3-application-autoscaling (>=1.35.0,<1.36.0)", "mypy-boto3-application-insights (>=1.35.0,<1.36.0)", "mypy-boto3-application-signals (>=1.35.0,<1.36.0)", "mypy-boto3-applicationcostprofiler (>=1.35.0,<1.36.0)", "mypy-boto3-appmesh (>=1.35.0,<1.36.0)", "mypy-boto3-apprunner (>=1.35.0,<1.36.0)", "mypy-boto3-appstream (>=1.35.0,<1.36.0)", "mypy-boto3-appsync (>=1.35.0,<1.36.0)", "mypy-boto3-apptest (>=1.35.0,<1.36.0)", "mypy-boto3-arc-zonal-shift (>=1.35.0,<1.36.0)", "mypy-boto3-artifact (>=1.35.0,<1.36.0)", "mypy-boto3-athena (>=1.35.0,<1.36.0)", "mypy-boto3-auditmanager (>=1.35.0,<1.36.0)", "mypy-boto3-autoscaling (>=1.35.0,<1.36.0)", "mypy-boto3-autoscaling-plans (>=1.35.0,<1.36.0)", "mypy-boto3-b2bi (>=1.35.0,<1.36.0)", "mypy-boto3-backup (>=1.35.0,<1.36.0)", "mypy-boto3-backup-gateway (>=1.35.0,<1.36.0)", "mypy-boto3-backupsearch (>=1.35.0,<1.36.0)", "mypy-boto3-batch (>=1.35.0,<1.36.0)", "mypy-boto3-bcm-data-exports (>=1.35.0,<1.36.0)", "mypy-boto3-bcm-pricing-calculator (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock-agent (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock-agent-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock-data-automation (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock-data-automation-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-billing (>=1.35.0,<1.36.0)", "mypy-boto3-billingconductor (>=1.35.0,<1.36.0)", "mypy-boto3-braket (>=1.35.0,<1.36.0)", "mypy-boto3-budgets (>=1.35.0,<1.36.0)", "mypy-boto3-ce (>=1.35.0,<1.36.0)", "mypy-boto3-chatbot (>=1.35.0,<1.36.0)", "mypy-boto3-chime (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-identity (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-media-pipelines (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-meetings (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-messaging (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-voice (>=1.35.0,<1.36.0)", "mypy-boto3-cleanrooms (>=1.35.0,<1.36.0)", "mypy-boto3-cleanroomsml (>=1.35.0,<1.36.0)", "mypy-boto3-cloud9 (>=1.35.0,<1.36.0)", "mypy-boto3-cloudcontrol (>=1.35.0,<1.36.0)", "mypy-boto3-clouddirectory (>=1.35.0,<1.36.0)", "mypy-boto3-cloudformation (>=1.35.0,<1.36.0)", "mypy-boto3-cloudfront (>=1.35.0,<1.36.0)", "mypy-boto3-cloudfront-keyvaluestore (>=1.35.0,<1.36.0)", "mypy-boto3-cloudhsm (>=1.35.0,<1.36.0)", "mypy-boto3-cloudhsmv2 (>=1.35.0,<1.36.0)", "mypy-boto3-cloudsearch (>=1.35.0,<1.36.0)", "mypy-boto3-cloudsearchdomain (>=1.35.0,<1.36.0)", "mypy-boto3-cloudtrail (>=1.35.0,<1.36.0)", "mypy-boto3-cloudtrail-data (>=1.35.0,<1.36.0)", "mypy-boto3-cloudwatch (>=1.35.0,<1.36.0)", "mypy-boto3-codeartifact (>=1.35.0,<1.36.0)", "mypy-boto3-codebuild (>=1.35.0,<1.36.0)", "mypy-boto3-codecatalyst (>=1.35.0,<1.36.0)", "mypy-boto3-codecommit (>=1.35.0,<1.36.0)", "mypy-boto3-codeconnections (>=1.35.0,<1.36.0)", "mypy-boto3-codedeploy (>=1.35.0,<1.36.0)", "mypy-boto3-codeguru-reviewer (>=1.35.0,<1.36.0)", "mypy-boto3-codeguru-security (>=1.35.0,<1.36.0)", "mypy-boto3-codeguruprofiler (>=1.35.0,<1.36.0)", "mypy-boto3-codepipeline (>=1.35.0,<1.36.0)", "mypy-boto3-codestar-connections (>=1.35.0,<1.36.0)", "mypy-boto3-codestar-notifications (>=1.35.0,<1.36.0)", "mypy-boto3-cognito-identity (>=1.35.0,<1.36.0)", "mypy-boto3-cognito-idp (>=1.35.0,<1.36.0)", "mypy-boto3-cognito-sync (>=1.35.0,<1.36.0)", "mypy-boto3-comprehend (>=1.35.0,<1.36.0)", "mypy-boto3-comprehendmedical (>=1.35.0,<1.36.0)", "mypy-boto3-compute-optimizer (>=1.35.0,<1.36.0)", "mypy-boto3-config (>=1.35.0,<1.36.0)", "mypy-boto3-connect (>=1.35.0,<1.36.0)", "mypy-boto3-connect-contact-lens (>=1.35.0,<1.36.0)", "mypy-boto3-connectcampaigns (>=1.35.0,<1.36.0)", "mypy-boto3-connectcampaignsv2 (>=1.35.0,<1.36.0)", "mypy-boto3-connectcases (>=1.35.0,<1.36.0)", "mypy-boto3-connectparticipant (>=1.35.0,<1.36.0)", "mypy-boto3-controlcatalog (>=1.35.0,<1.36.0)", "mypy-boto3-controltower (>=1.35.0,<1.36.0)", "mypy-boto3-cost-optimization-hub (>=1.35.0,<1.36.0)", "mypy-boto3-cur (>=1.35.0,<1.36.0)", "mypy-boto3-customer-profiles (>=1.35.0,<1.36.0)", "mypy-boto3-databrew (>=1.35.0,<1.36.0)", "mypy-boto3-dataexchange (>=1.35.0,<1.36.0)", "mypy-boto3-datapipeline (>=1.35.0,<1.36.0)", "mypy-boto3-datasync (>=1.35.0,<1.36.0)", "mypy-boto3-datazone (>=1.35.0,<1.36.0)", "mypy-boto3-dax (>=1.35.0,<1.36.0)", "mypy-boto3-deadline (>=1.35.0,<1.36.0)", "mypy-boto3-detective (>=1.35.0,<1.36.0)", "mypy-boto3-devicefarm (>=1.35.0,<1.36.0)", "mypy-boto3-devops-guru (>=1.35.0,<1.36.0)", "mypy-boto3-directconnect (>=1.35.0,<1.36.0)", "mypy-boto3-discovery (>=1.35.0,<1.36.0)", "mypy-boto3-dlm (>=1.35.0,<1.36.0)", "mypy-boto3-dms (>=1.35.0,<1.36.0)", "mypy-boto3-docdb (>=1.35.0,<1.36.0)", "mypy-boto3-docdb-elastic (>=1.35.0,<1.36.0)", "mypy-boto3-drs (>=1.35.0,<1.36.0)", "mypy-boto3-ds (>=1.35.0,<1.36.0)", "mypy-boto3-ds-data (>=1.35.0,<1.36.0)", "mypy-boto3-dsql (>=1.35.0,<1.36.0)", "mypy-boto3-dynamodb (>=1.35.0,<1.36.0)", "mypy-boto3-dynamodbstreams (>=1.35.0,<1.36.0)", "mypy-boto3-ebs (>=1.35.0,<1.36.0)", "mypy-boto3-ec2 (>=1.35.0,<1.36.0)", "mypy-boto3-ec2-instance-connect (>=1.35.0,<1.36.0)", "mypy-boto3-ecr (>=1.35.0,<1.36.0)", "mypy-boto3-ecr-public (>=1.35.0,<1.36.0)", "mypy-boto3-ecs (>=1.35.0,<1.36.0)", "mypy-boto3-efs (>=1.35.0,<1.36.0)", "mypy-boto3-eks (>=1.35.0,<1.36.0)", "mypy-boto3-eks-auth (>=1.35.0,<1.36.0)", "mypy-boto3-elastic-inference (>=1.35.0,<1.36.0)", "mypy-boto3-elasticache (>=1.35.0,<1.36.0)", "mypy-boto3-elasticbeanstalk (>=1.35.0,<1.36.0)", "mypy-boto3-elastictranscoder (>=1.35.0,<1.36.0)", "mypy-boto3-elb (>=1.35.0,<1.36.0)", "mypy-boto3-elbv2 (>=1.35.0,<1.36.0)", "mypy-boto3-emr (>=1.35.0,<1.36.0)", "mypy-boto3-emr-containers (>=1.35.0,<1.36.0)", "mypy-boto3-emr-serverless (>=1.35.0,<1.36.0)", "mypy-boto3-entityresolution (>=1.35.0,<1.36.0)", "mypy-boto3-es (>=1.35.0,<1.36.0)", "mypy-boto3-events (>=1.35.0,<1.36.0)", "mypy-boto3-evidently (>=1.35.0,<1.36.0)", "mypy-boto3-finspace (>=1.35.0,<1.36.0)", "mypy-boto3-finspace-data (>=1.35.0,<1.36.0)", "mypy-boto3-firehose (>=1.35.0,<1.36.0)", "mypy-boto3-fis (>=1.35.0,<1.36.0)", "mypy-boto3-fms (>=1.35.0,<1.36.0)", "mypy-boto3-forecast (>=1.35.0,<1.36.0)", "mypy-boto3-forecastquery (>=1.35.0,<1.36.0)", "mypy-boto3-frauddetector (>=1.35.0,<1.36.0)", "mypy-boto3-freetier (>=1.35.0,<1.36.0)", "mypy-boto3-fsx (>=1.35.0,<1.36.0)", "mypy-boto3-gamelift (>=1.35.0,<1.36.0)", "mypy-boto3-geo-maps (>=1.35.0,<1.36.0)", "mypy-boto3-geo-places (>=1.35.0,<1.36.0)", "mypy-boto3-geo-routes (>=1.35.0,<1.36.0)", "mypy-boto3-glacier (>=1.35.0,<1.36.0)", "mypy-boto3-globalaccelerator (>=1.35.0,<1.36.0)", "mypy-boto3-glue (>=1.35.0,<1.36.0)", "mypy-boto3-grafana (>=1.35.0,<1.36.0)", "mypy-boto3-greengrass (>=1.35.0,<1.36.0)", "mypy-boto3-greengrassv2 (>=1.35.0,<1.36.0)", "mypy-boto3-groundstation (>=1.35.0,<1.36.0)", "mypy-boto3-guardduty (>=1.35.0,<1.36.0)", "mypy-boto3-health (>=1.35.0,<1.36.0)", "mypy-boto3-healthlake (>=1.35.0,<1.36.0)", "mypy-boto3-iam (>=1.35.0,<1.36.0)", "mypy-boto3-identitystore (>=1.35.0,<1.36.0)", "mypy-boto3-imagebuilder (>=1.35.0,<1.36.0)", "mypy-boto3-importexport (>=1.35.0,<1.36.0)", "mypy-boto3-inspector (>=1.35.0,<1.36.0)", "mypy-boto3-inspector-scan (>=1.35.0,<1.36.0)", "mypy-boto3-inspector2 (>=1.35.0,<1.36.0)", "mypy-boto3-internetmonitor (>=1.35.0,<1.36.0)", "mypy-boto3-invoicing (>=1.35.0,<1.36.0)", "mypy-boto3-iot (>=1.35.0,<1.36.0)", "mypy-boto3-iot-data (>=1.35.0,<1.36.0)", "mypy-boto3-iot-jobs-data (>=1.35.0,<1.36.0)", "mypy-boto3-iot1click-devices (>=1.35.0,<1.36.0)", "mypy-boto3-iot1click-projects (>=1.35.0,<1.36.0)", "mypy-boto3-iotanalytics (>=1.35.0,<1.36.0)", "mypy-boto3-iotdeviceadvisor (>=1.35.0,<1.36.0)", "mypy-boto3-iotevents (>=1.35.0,<1.36.0)", "mypy-boto3-iotevents-data (>=1.35.0,<1.36.0)", "mypy-boto3-iotfleethub (>=1.35.0,<1.36.0)", "mypy-boto3-iotfleetwise (>=1.35.0,<1.36.0)", "mypy-boto3-iotsecuretunneling (>=1.35.0,<1.36.0)", "mypy-boto3-iotsitewise (>=1.35.0,<1.36.0)", "mypy-boto3-iotthingsgraph (>=1.35.0,<1.36.0)", "mypy-boto3-iottwinmaker (>=1.35.0,<1.36.0)", "mypy-boto3-iotwireless (>=1.35.0,<1.36.0)", "mypy-boto3-ivs (>=1.35.0,<1.36.0)", "mypy-boto3-ivs-realtime (>=1.35.0,<1.36.0)", "mypy-boto3-ivschat (>=1.35.0,<1.36.0)", "mypy-boto3-kafka (>=1.35.0,<1.36.0)", "mypy-boto3-kafkaconnect (>=1.35.0,<1.36.0)", "mypy-boto3-kendra (>=1.35.0,<1.36.0)", "mypy-boto3-kendra-ranking (>=1.35.0,<1.36.0)", "mypy-boto3-keyspaces (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis-video-archived-media (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis-video-media (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis-video-signaling (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis-video-webrtc-storage (>=1.35.0,<1.36.0)", "mypy-boto3-kinesisanalytics (>=1.35.0,<1.36.0)", "mypy-boto3-kinesisanalyticsv2 (>=1.35.0,<1.36.0)", "mypy-boto3-kinesisvideo (>=1.35.0,<1.36.0)", "mypy-boto3-kms (>=1.35.0,<1.36.0)", "mypy-boto3-lakeformation (>=1.35.0,<1.36.0)", "mypy-boto3-lambda (>=1.35.0,<1.36.0)", "mypy-boto3-launch-wizard (>=1.35.0,<1.36.0)", "mypy-boto3-lex-models (>=1.35.0,<1.36.0)", "mypy-boto3-lex-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-lexv2-models (>=1.35.0,<1.36.0)", "mypy-boto3-lexv2-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-license-manager (>=1.35.0,<1.36.0)", "mypy-boto3-license-manager-linux-subscriptions (>=1.35.0,<1.36.0)", "mypy-boto3-license-manager-user-subscriptions (>=1.35.0,<1.36.0)", "mypy-boto3-lightsail (>=1.35.0,<1.36.0)", "mypy-boto3-location (>=1.35.0,<1.36.0)", "mypy-boto3-logs (>=1.35.0,<1.36.0)", "mypy-boto3-lookoutequipment (>=1.35.0,<1.36.0)", "mypy-boto3-lookoutmetrics (>=1.35.0,<1.36.0)", "mypy-boto3-lookoutvision (>=1.35.0,<1.36.0)", "mypy-boto3-m2 (>=1.35.0,<1.36.0)", "mypy-boto3-machinelearning (>=1.35.0,<1.36.0)", "mypy-boto3-macie2 (>=1.35.0,<1.36.0)", "mypy-boto3-mailmanager (>=1.35.0,<1.36.0)", "mypy-boto3-managedblockchain (>=1.35.0,<1.36.0)", "mypy-boto3-managedblockchain-query (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-agreement (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-catalog (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-deployment (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-entitlement (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-reporting (>=1.35.0,<1.36.0)", "mypy-boto3-marketplacecommerceanalytics (>=1.35.0,<1.36.0)", "mypy-boto3-mediaconnect (>=1.35.0,<1.36.0)", "mypy-boto3-mediaconvert (>=1.35.0,<1.36.0)", "mypy-boto3-medialive (>=1.35.0,<1.36.0)", "mypy-boto3-mediapackage (>=1.35.0,<1.36.0)", "mypy-boto3-mediapackage-vod (>=1.35.0,<1.36.0)", "mypy-boto3-mediapackagev2 (>=1.35.0,<1.36.0)", "mypy-boto3-mediastore (>=1.35.0,<1.36.0)", "mypy-boto3-mediastore-data (>=1.35.0,<1.36.0)", "mypy-boto3-mediatailor (>=1.35.0,<1.36.0)", "mypy-boto3-medical-imaging (>=1.35.0,<1.36.0)", "mypy-boto3-memorydb (>=1.35.0,<1.36.0)", "mypy-boto3-meteringmarketplace (>=1.35.0,<1.36.0)", "mypy-boto3-mgh (>=1.35.0,<1.36.0)", "mypy-boto3-mgn (>=1.35.0,<1.36.0)", "mypy-boto3-migration-hub-refactor-spaces (>=1.35.0,<1.36.0)", "mypy-boto3-migrationhub-config (>=1.35.0,<1.36.0)", "mypy-boto3-migrationhuborchestrator (>=1.35.0,<1.36.0)", "mypy-boto3-migrationhubstrategy (>=1.35.0,<1.36.0)", "mypy-boto3-mq (>=1.35.0,<1.36.0)", "mypy-boto3-mturk (>=1.35.0,<1.36.0)", "mypy-boto3-mwaa (>=1.35.0,<1.36.0)", "mypy-boto3-neptune (>=1.35.0,<1.36.0)", "mypy-boto3-neptune-graph (>=1.35.0,<1.36.0)", "mypy-boto3-neptunedata (>=1.35.0,<1.36.0)", "mypy-boto3-network-firewall (>=1.35.0,<1.36.0)", "mypy-boto3-networkflowmonitor (>=1.35.0,<1.36.0)", "mypy-boto3-networkmanager (>=1.35.0,<1.36.0)", "mypy-boto3-networkmonitor (>=1.35.0,<1.36.0)", "mypy-boto3-notifications (>=1.35.0,<1.36.0)", "mypy-boto3-notificationscontacts (>=1.35.0,<1.36.0)", "mypy-boto3-oam (>=1.35.0,<1.36.0)", "mypy-boto3-observabilityadmin (>=1.35.0,<1.36.0)", "mypy-boto3-omics (>=1.35.0,<1.36.0)", "mypy-boto3-opensearch (>=1.35.0,<1.36.0)", "mypy-boto3-opensearchserverless (>=1.35.0,<1.36.0)", "mypy-boto3-opsworks (>=1.35.0,<1.36.0)", "mypy-boto3-opsworkscm (>=1.35.0,<1.36.0)", "mypy-boto3-organizations (>=1.35.0,<1.36.0)", "mypy-boto3-osis (>=1.35.0,<1.36.0)", "mypy-boto3-outposts (>=1.35.0,<1.36.0)", "mypy-boto3-panorama (>=1.35.0,<1.36.0)", "mypy-boto3-partnercentral-selling (>=1.35.0,<1.36.0)", "mypy-boto3-payment-cryptography (>=1.35.0,<1.36.0)", "mypy-boto3-payment-cryptography-data (>=1.35.0,<1.36.0)", "mypy-boto3-pca-connector-ad (>=1.35.0,<1.36.0)", "mypy-boto3-pca-connector-scep (>=1.35.0,<1.36.0)", "mypy-boto3-pcs (>=1.35.0,<1.36.0)", "mypy-boto3-personalize (>=1.35.0,<1.36.0)", "mypy-boto3-personalize-events (>=1.35.0,<1.36.0)", "mypy-boto3-personalize-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-pi (>=1.35.0,<1.36.0)", "mypy-boto3-pinpoint (>=1.35.0,<1.36.0)", "mypy-boto3-pinpoint-email (>=1.35.0,<1.36.0)", "mypy-boto3-pinpoint-sms-voice (>=1.35.0,<1.36.0)", "mypy-boto3-pinpoint-sms-voice-v2 (>=1.35.0,<1.36.0)", "mypy-boto3-pipes (>=1.35.0,<1.36.0)", "mypy-boto3-polly (>=1.35.0,<1.36.0)", "mypy-boto3-pricing (>=1.35.0,<1.36.0)", "mypy-boto3-privatenetworks (>=1.35.0,<1.36.0)", "mypy-boto3-proton (>=1.35.0,<1.36.0)", "mypy-boto3-qapps (>=1.35.0,<1.36.0)", "mypy-boto3-qbusiness (>=1.35.0,<1.36.0)", "mypy-boto3-qconnect (>=1.35.0,<1.36.0)", "mypy-boto3-qldb (>=1.35.0,<1.36.0)", "mypy-boto3-qldb-session (>=1.35.0,<1.36.0)", "mypy-boto3-quicksight (>=1.35.0,<1.36.0)", "mypy-boto3-ram (>=1.35.0,<1.36.0)", "mypy-boto3-rbin (>=1.35.0,<1.36.0)", "mypy-boto3-rds (>=1.35.0,<1.36.0)", "mypy-boto3-rds-data (>=1.35.0,<1.36.0)", "mypy-boto3-redshift (>=1.35.0,<1.36.0)", "mypy-boto3-redshift-data (>=1.35.0,<1.36.0)", "mypy-boto3-redshift-serverless (>=1.35.0,<1.36.0)", "mypy-boto3-rekognition (>=1.35.0,<1.36.0)", "mypy-boto3-repostspace (>=1.35.0,<1.36.0)", "mypy-boto3-resiliencehub (>=1.35.0,<1.36.0)", "mypy-boto3-resource-explorer-2 (>=1.35.0,<1.36.0)", "mypy-boto3-resource-groups (>=1.35.0,<1.36.0)", "mypy-boto3-resourcegroupstaggingapi (>=1.35.0,<1.36.0)", "mypy-boto3-robomaker (>=1.35.0,<1.36.0)", "mypy-boto3-rolesanywhere (>=1.35.0,<1.36.0)", "mypy-boto3-route53 (>=1.35.0,<1.36.0)", "mypy-boto3-route53-recovery-cluster (>=1.35.0,<1.36.0)", "mypy-boto3-route53-recovery-control-config (>=1.35.0,<1.36.0)", "mypy-boto3-route53-recovery-readiness (>=1.35.0,<1.36.0)", "mypy-boto3-route53domains (>=1.35.0,<1.36.0)", "mypy-boto3-route53profiles (>=1.35.0,<1.36.0)", "mypy-boto3-route53resolver (>=1.35.0,<1.36.0)", "mypy-boto3-rum (>=1.35.0,<1.36.0)", "mypy-boto3-s3 (>=1.35.0,<1.36.0)", "mypy-boto3-s3control (>=1.35.0,<1.36.0)", "mypy-boto3-s3outposts (>=1.35.0,<1.36.0)", "mypy-boto3-s3tables (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-a2i-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-edge (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-featurestore-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-geospatial (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-metrics (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-savingsplans (>=1.35.0,<1.36.0)", "mypy-boto3-scheduler (>=1.35.0,<1.36.0)", "mypy-boto3-schemas (>=1.35.0,<1.36.0)", "mypy-boto3-sdb (>=1.35.0,<1.36.0)", "mypy-boto3-secretsmanager (>=1.35.0,<1.36.0)", "mypy-boto3-security-ir (>=1.35.0,<1.36.0)", "mypy-boto3-securityhub (>=1.35.0,<1.36.0)", "mypy-boto3-securitylake (>=1.35.0,<1.36.0)", "mypy-boto3-serverlessrepo (>=1.35.0,<1.36.0)", "mypy-boto3-service-quotas (>=1.35.0,<1.36.0)", "mypy-boto3-servicecatalog (>=1.35.0,<1.36.0)", "mypy-boto3-servicecatalog-appregistry (>=1.35.0,<1.36.0)", "mypy-boto3-servicediscovery (>=1.35.0,<1.36.0)", "mypy-boto3-ses (>=1.35.0,<1.36.0)", "mypy-boto3-sesv2 (>=1.35.0,<1.36.0)", "mypy-boto3-shield (>=1.35.0,<1.36.0)", "mypy-boto3-signer (>=1.35.0,<1.36.0)", "mypy-boto3-simspaceweaver (>=1.35.0,<1.36.0)", "mypy-boto3-sms (>=1.35.0,<1.36.0)", "mypy-boto3-sms-voice (>=1.35.0,<1.36.0)", "mypy-boto3-snow-device-management (>=1.35.0,<1.36.0)", "mypy-boto3-snowball (>=1.35.0,<1.36.0)", "mypy-boto3-sns (>=1.35.0,<1.36.0)", "mypy-boto3-socialmessaging (>=1.35.0,<1.36.0)", "mypy-boto3-sqs (>=1.35.0,<1.36.0)", "mypy-boto3-ssm (>=1.35.0,<1.36.0)", "mypy-boto3-ssm-contacts (>=1.35.0,<1.36.0)", "mypy-boto3-ssm-incidents (>=1.35.0,<1.36.0)", "mypy-boto3-ssm-quicksetup (>=1.35.0,<1.36.0)", "mypy-boto3-ssm-sap (>=1.35.0,<1.36.0)", "mypy-boto3-sso (>=1.35.0,<1.36.0)", "mypy-boto3-sso-admin (>=1.35.0,<1.36.0)", "mypy-boto3-sso-oidc (>=1.35.0,<1.36.0)", "mypy-boto3-stepfunctions (>=1.35.0,<1.36.0)", "mypy-boto3-storagegateway (>=1.35.0,<1.36.0)", "mypy-boto3-sts (>=1.35.0,<1.36.0)", "mypy-boto3-supplychain (>=1.35.0,<1.36.0)", "mypy-boto3-support (>=1.35.0,<1.36.0)", "mypy-boto3-support-app (>=1.35.0,<1.36.0)", "mypy-boto3-swf (>=1.35.0,<1.36.0)", "mypy-boto3-synthetics (>=1.35.0,<1.36.0)", "mypy-boto3-taxsettings (>=1.35.0,<1.36.0)", "mypy-boto3-textract (>=1.35.0,<1.36.0)", "mypy-boto3-timestream-influxdb (>=1.35.0,<1.36.0)", "mypy-boto3-timestream-query (>=1.35.0,<1.36.0)", "mypy-boto3-timestream-write (>=1.35.0,<1.36.0)", "mypy-boto3-tnb (>=1.35.0,<1.36.0)", "mypy-boto3-transcribe (>=1.35.0,<1.36.0)", "mypy-boto3-transfer (>=1.35.0,<1.36.0)", "mypy-boto3-translate (>=1.35.0,<1.36.0)", "mypy-boto3-trustedadvisor (>=1.35.0,<1.36.0)", "mypy-boto3-verifiedpermissions (>=1.35.0,<1.36.0)", "mypy-boto3-voice-id (>=1.35.0,<1.36.0)", "mypy-boto3-vpc-lattice (>=1.35.0,<1.36.0)", "mypy-boto3-waf (>=1.35.0,<1.36.0)", "mypy-boto3-waf-regional (>=1.35.0,<1.36.0)", "mypy-boto3-wafv2 (>=1.35.0,<1.36.0)", "mypy-boto3-wellarchitected (>=1.35.0,<1.36.0)", "mypy-boto3-wisdom (>=1.35.0,<1.36.0)", "mypy-boto3-workdocs (>=1.35.0,<1.36.0)", "mypy-boto3-workmail (>=1.35.0,<1.36.0)", "mypy-boto3-workmailmessageflow (>=1.35.0,<1.36.0)", "mypy-boto3-workspaces (>=1.35.0,<1.36.0)", "mypy-boto3-workspaces-thin-client (>=1.35.0,<1.36.0)", "mypy-boto3-workspaces-web (>=1.35.0,<1.36.0)", "mypy-boto3-xray (>=1.35.0,<1.36.0)"] amp = ["mypy-boto3-amp (>=1.35.0,<1.36.0)"] amplify = ["mypy-boto3-amplify (>=1.35.0,<1.36.0)"] amplifybackend = ["mypy-boto3-amplifybackend (>=1.35.0,<1.36.0)"] @@ -234,15 +235,19 @@ autoscaling-plans = ["mypy-boto3-autoscaling-plans (>=1.35.0,<1.36.0)"] b2bi = ["mypy-boto3-b2bi (>=1.35.0,<1.36.0)"] backup = ["mypy-boto3-backup (>=1.35.0,<1.36.0)"] backup-gateway = ["mypy-boto3-backup-gateway (>=1.35.0,<1.36.0)"] +backupsearch = ["mypy-boto3-backupsearch (>=1.35.0,<1.36.0)"] batch = ["mypy-boto3-batch (>=1.35.0,<1.36.0)"] bcm-data-exports = ["mypy-boto3-bcm-data-exports (>=1.35.0,<1.36.0)"] +bcm-pricing-calculator = ["mypy-boto3-bcm-pricing-calculator (>=1.35.0,<1.36.0)"] bedrock = ["mypy-boto3-bedrock (>=1.35.0,<1.36.0)"] bedrock-agent = ["mypy-boto3-bedrock-agent (>=1.35.0,<1.36.0)"] bedrock-agent-runtime = ["mypy-boto3-bedrock-agent-runtime (>=1.35.0,<1.36.0)"] +bedrock-data-automation = ["mypy-boto3-bedrock-data-automation (>=1.35.0,<1.36.0)"] +bedrock-data-automation-runtime = ["mypy-boto3-bedrock-data-automation-runtime (>=1.35.0,<1.36.0)"] bedrock-runtime = ["mypy-boto3-bedrock-runtime (>=1.35.0,<1.36.0)"] billing = ["mypy-boto3-billing (>=1.35.0,<1.36.0)"] billingconductor = ["mypy-boto3-billingconductor (>=1.35.0,<1.36.0)"] -boto3 = ["boto3 (==1.35.60)", "botocore (==1.35.60)"] +boto3 = ["boto3 (==1.35.87)"] braket = ["mypy-boto3-braket (>=1.35.0,<1.36.0)"] budgets = ["mypy-boto3-budgets (>=1.35.0,<1.36.0)"] ce = ["mypy-boto3-ce (>=1.35.0,<1.36.0)"] @@ -290,6 +295,7 @@ config = ["mypy-boto3-config (>=1.35.0,<1.36.0)"] connect = ["mypy-boto3-connect (>=1.35.0,<1.36.0)"] connect-contact-lens = ["mypy-boto3-connect-contact-lens (>=1.35.0,<1.36.0)"] connectcampaigns = ["mypy-boto3-connectcampaigns (>=1.35.0,<1.36.0)"] +connectcampaignsv2 = ["mypy-boto3-connectcampaignsv2 (>=1.35.0,<1.36.0)"] connectcases = ["mypy-boto3-connectcases (>=1.35.0,<1.36.0)"] connectparticipant = ["mypy-boto3-connectparticipant (>=1.35.0,<1.36.0)"] controlcatalog = ["mypy-boto3-controlcatalog (>=1.35.0,<1.36.0)"] @@ -316,6 +322,7 @@ docdb-elastic = ["mypy-boto3-docdb-elastic (>=1.35.0,<1.36.0)"] drs = ["mypy-boto3-drs (>=1.35.0,<1.36.0)"] ds = ["mypy-boto3-ds (>=1.35.0,<1.36.0)"] ds-data = ["mypy-boto3-ds-data (>=1.35.0,<1.36.0)"] +dsql = ["mypy-boto3-dsql (>=1.35.0,<1.36.0)"] dynamodb = ["mypy-boto3-dynamodb (>=1.35.0,<1.36.0)"] dynamodbstreams = ["mypy-boto3-dynamodbstreams (>=1.35.0,<1.36.0)"] ebs = ["mypy-boto3-ebs (>=1.35.0,<1.36.0)"] @@ -351,7 +358,7 @@ forecastquery = ["mypy-boto3-forecastquery (>=1.35.0,<1.36.0)"] frauddetector = ["mypy-boto3-frauddetector (>=1.35.0,<1.36.0)"] freetier = ["mypy-boto3-freetier (>=1.35.0,<1.36.0)"] fsx = ["mypy-boto3-fsx (>=1.35.0,<1.36.0)"] -full = ["boto3-stubs-full"] +full = ["boto3-stubs-full (>=1.35.0,<1.36.0)"] gamelift = ["mypy-boto3-gamelift (>=1.35.0,<1.36.0)"] geo-maps = ["mypy-boto3-geo-maps (>=1.35.0,<1.36.0)"] geo-places = ["mypy-boto3-geo-places (>=1.35.0,<1.36.0)"] @@ -374,6 +381,7 @@ inspector = ["mypy-boto3-inspector (>=1.35.0,<1.36.0)"] inspector-scan = ["mypy-boto3-inspector-scan (>=1.35.0,<1.36.0)"] inspector2 = ["mypy-boto3-inspector2 (>=1.35.0,<1.36.0)"] internetmonitor = ["mypy-boto3-internetmonitor (>=1.35.0,<1.36.0)"] +invoicing = ["mypy-boto3-invoicing (>=1.35.0,<1.36.0)"] iot = ["mypy-boto3-iot (>=1.35.0,<1.36.0)"] iot-data = ["mypy-boto3-iot-data (>=1.35.0,<1.36.0)"] iot-jobs-data = ["mypy-boto3-iot-jobs-data (>=1.35.0,<1.36.0)"] @@ -460,9 +468,13 @@ neptune = ["mypy-boto3-neptune (>=1.35.0,<1.36.0)"] neptune-graph = ["mypy-boto3-neptune-graph (>=1.35.0,<1.36.0)"] neptunedata = ["mypy-boto3-neptunedata (>=1.35.0,<1.36.0)"] network-firewall = ["mypy-boto3-network-firewall (>=1.35.0,<1.36.0)"] +networkflowmonitor = ["mypy-boto3-networkflowmonitor (>=1.35.0,<1.36.0)"] networkmanager = ["mypy-boto3-networkmanager (>=1.35.0,<1.36.0)"] networkmonitor = ["mypy-boto3-networkmonitor (>=1.35.0,<1.36.0)"] +notifications = ["mypy-boto3-notifications (>=1.35.0,<1.36.0)"] +notificationscontacts = ["mypy-boto3-notificationscontacts (>=1.35.0,<1.36.0)"] oam = ["mypy-boto3-oam (>=1.35.0,<1.36.0)"] +observabilityadmin = ["mypy-boto3-observabilityadmin (>=1.35.0,<1.36.0)"] omics = ["mypy-boto3-omics (>=1.35.0,<1.36.0)"] opensearch = ["mypy-boto3-opensearch (>=1.35.0,<1.36.0)"] opensearchserverless = ["mypy-boto3-opensearchserverless (>=1.35.0,<1.36.0)"] @@ -472,6 +484,7 @@ organizations = ["mypy-boto3-organizations (>=1.35.0,<1.36.0)"] osis = ["mypy-boto3-osis (>=1.35.0,<1.36.0)"] outposts = ["mypy-boto3-outposts (>=1.35.0,<1.36.0)"] panorama = ["mypy-boto3-panorama (>=1.35.0,<1.36.0)"] +partnercentral-selling = ["mypy-boto3-partnercentral-selling (>=1.35.0,<1.36.0)"] payment-cryptography = ["mypy-boto3-payment-cryptography (>=1.35.0,<1.36.0)"] payment-cryptography-data = ["mypy-boto3-payment-cryptography-data (>=1.35.0,<1.36.0)"] pca-connector-ad = ["mypy-boto3-pca-connector-ad (>=1.35.0,<1.36.0)"] @@ -522,6 +535,7 @@ rum = ["mypy-boto3-rum (>=1.35.0,<1.36.0)"] s3 = ["mypy-boto3-s3 (>=1.35.0,<1.36.0)"] s3control = ["mypy-boto3-s3control (>=1.35.0,<1.36.0)"] s3outposts = ["mypy-boto3-s3outposts (>=1.35.0,<1.36.0)"] +s3tables = ["mypy-boto3-s3tables (>=1.35.0,<1.36.0)"] sagemaker = ["mypy-boto3-sagemaker (>=1.35.0,<1.36.0)"] sagemaker-a2i-runtime = ["mypy-boto3-sagemaker-a2i-runtime (>=1.35.0,<1.36.0)"] sagemaker-edge = ["mypy-boto3-sagemaker-edge (>=1.35.0,<1.36.0)"] @@ -534,6 +548,7 @@ scheduler = ["mypy-boto3-scheduler (>=1.35.0,<1.36.0)"] schemas = ["mypy-boto3-schemas (>=1.35.0,<1.36.0)"] sdb = ["mypy-boto3-sdb (>=1.35.0,<1.36.0)"] secretsmanager = ["mypy-boto3-secretsmanager (>=1.35.0,<1.36.0)"] +security-ir = ["mypy-boto3-security-ir (>=1.35.0,<1.36.0)"] securityhub = ["mypy-boto3-securityhub (>=1.35.0,<1.36.0)"] securitylake = ["mypy-boto3-securitylake (>=1.35.0,<1.36.0)"] serverlessrepo = ["mypy-boto3-serverlessrepo (>=1.35.0,<1.36.0)"] @@ -597,13 +612,13 @@ xray = ["mypy-boto3-xray (>=1.35.0,<1.36.0)"] [[package]] name = "botocore" -version = "1.35.60" +version = "1.35.87" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" files = [ - {file = "botocore-1.35.60-py3-none-any.whl", hash = "sha256:ddccfc39a0a55ac0321191a36d29c2ea9be2c96ceefb3928dd3c91c79c494d50"}, - {file = "botocore-1.35.60.tar.gz", hash = "sha256:378f53037d817bed2c04a006b7319745e664030182211429c924647273b29bc9"}, + {file = "botocore-1.35.87-py3-none-any.whl", hash = "sha256:81cf84f12030d9ab3829484b04765d5641697ec53c2ac2b3987a99eefe501692"}, + {file = "botocore-1.35.87.tar.gz", hash = "sha256:3062d073ce4170a994099270f469864169dc1a1b8b3d4a21c14ce0ae995e0f89"}, ] [package.dependencies] @@ -616,13 +631,13 @@ crt = ["awscrt (==0.22.0)"] [[package]] name = "botocore-stubs" -version = "1.35.60" +version = "1.35.87" description = "Type annotations and code completion for botocore" optional = false python-versions = ">=3.8" files = [ - {file = "botocore_stubs-1.35.60-py3-none-any.whl", hash = "sha256:52b414b326df21a094ccd0c7840b5e82c80fa59a4decbb4594647ba2a250b3fc"}, - {file = "botocore_stubs-1.35.60.tar.gz", hash = "sha256:ae2b94b099d43204db6d056b763fff47ebc5974fab24420e7f4a01526a590048"}, + {file = "botocore_stubs-1.35.87-py3-none-any.whl", hash = "sha256:78645741966528d2cf1b6c140645766221cca39075acaa321af60751efe40645"}, + {file = "botocore_stubs-1.35.87.tar.gz", hash = "sha256:09e2a2c0757fb95a0ca595c724eb5a151f1c4c264b51c43cbdb55853a796c4c4"}, ] [package.dependencies] @@ -644,13 +659,13 @@ files = [ [[package]] name = "certifi" -version = "2024.8.30" +version = "2024.12.14" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, - {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, + {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, + {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, ] [[package]] @@ -734,127 +749,114 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "3.4.0" +version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false -python-versions = ">=3.7.0" -files = [ - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, - {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, - {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, +python-versions = ">=3.7" +files = [ + {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, + {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, + {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, ] [[package]] name = "click" -version = "8.1.7" +version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, ] [package.dependencies] @@ -1025,13 +1027,13 @@ sqlite = ["aiosqlite"] [[package]] name = "datamodel-code-generator" -version = "0.26.3" +version = "0.26.4" description = "Datamodel Code Generator" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "datamodel_code_generator-0.26.3-py3-none-any.whl", hash = "sha256:f1f8f1cef14f138fa239f987d4640837bb68d53c5f08d8673a7bde275b929fd8"}, - {file = "datamodel_code_generator-0.26.3.tar.gz", hash = "sha256:b58e0800eb6448e1d1df02f4586207c1e3631c4a188531d154b00b3cf2f95fd8"}, + {file = "datamodel_code_generator-0.26.4-py3-none-any.whl", hash = "sha256:95bdaa91fe87a8c369b1c9147bb2ef2eead918964270451e6223235131974098"}, + {file = "datamodel_code_generator-0.26.4.tar.gz", hash = "sha256:9881124fec15655a3a635808ea5ded63afb0540c0c402998070ccf60a9dab225"}, ] [package.dependencies] @@ -1107,13 +1109,13 @@ all = ["email_validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)" [[package]] name = "fastapi-pagination" -version = "0.12.32" +version = "0.12.34" description = "FastAPI pagination" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "fastapi_pagination-0.12.32-py3-none-any.whl", hash = "sha256:38e7e72abf252cbebbc1beff9081e4929762756c04959c471b2a5866bb7f0aaf"}, - {file = "fastapi_pagination-0.12.32.tar.gz", hash = "sha256:b808b5b8af493c51d96ae0091b60532b25688cbca1350f39cb72f10d4d69a6ab"}, + {file = "fastapi_pagination-0.12.34-py3-none-any.whl", hash = "sha256:089d1078aae1784395b4dbd923d0c8246641ddcc291c5ec6d92a30edb92ecbdd"}, + {file = "fastapi_pagination-0.12.34.tar.gz", hash = "sha256:05ee8c0bc572072160f7f30900bfd87869e1880c87bc5797922fec2e49e65f11"}, ] [package.dependencies] @@ -1121,21 +1123,21 @@ pydantic = ">=1.9.1" typing-extensions = ">=4.8.0,<5.0.0" [package.extras] -all = ["SQLAlchemy (>=1.3.20)", "asyncpg (>=0.24.0)", "beanie (>=1.25.0)", "bunnet (>=1.1.0,<2.0.0)", "databases (>=0.6.0)", "django (<5.0.0)", "mongoengine (>=0.23.1,<0.30.0)", "motor (>=2.5.1,<4.0.0)", "orm (>=0.3.1)", "ormar (>=0.11.2)", "piccolo (>=0.89,<0.122)", "pony (>=0.7.16,<0.8.0)", "scylla-driver (>=3.25.6,<4.0.0)", "sqlakeyset (>=2.0.1680321678,<3.0.0)", "sqlmodel (>=0.0.8,<0.0.15)", "tortoise-orm (>=0.16.18,!=0.21.0,<0.22.0)"] +all = ["SQLAlchemy (>=1.3.20)", "asyncpg (>=0.24.0)", "beanie (>=1.25.0)", "bunnet (>=1.1.0,<2.0.0)", "databases (>=0.6.0)", "django (<5.0.0)", "mongoengine (>=0.23.1,<0.30.0)", "motor (>=3.6.0,<4.0.0)", "odmantic (>=1.0.2,<2.0.0)", "orm (>=0.3.1)", "piccolo (>=0.89,<1.22)", "pony (>=0.7.16,<0.8.0)", "scylla-driver (>=3.25.6,<4.0.0)", "sqlakeyset (>=2.0.1680321678,<3.0.0)", "sqlmodel (>=0.0.22)", "tortoise-orm (>=0.22.0)"] asyncpg = ["SQLAlchemy (>=1.3.20)", "asyncpg (>=0.24.0)"] beanie = ["beanie (>=1.25.0)"] bunnet = ["bunnet (>=1.1.0,<2.0.0)"] databases = ["databases (>=0.6.0)"] django = ["databases (>=0.6.0)", "django (<5.0.0)"] mongoengine = ["mongoengine (>=0.23.1,<0.30.0)"] -motor = ["motor (>=2.5.1,<4.0.0)"] +motor = ["motor (>=3.6.0,<4.0.0)"] +odmantic = ["odmantic (>=1.0.2,<2.0.0)"] orm = ["databases (>=0.6.0)", "orm (>=0.3.1)"] -ormar = ["ormar (>=0.11.2)"] -piccolo = ["piccolo (>=0.89,<0.122)"] +piccolo = ["piccolo (>=0.89,<1.22)"] scylla-driver = ["scylla-driver (>=3.25.6,<4.0.0)"] sqlalchemy = ["SQLAlchemy (>=1.3.20)", "sqlakeyset (>=2.0.1680321678,<3.0.0)"] -sqlmodel = ["sqlakeyset (>=2.0.1680321678,<3.0.0)", "sqlmodel (>=0.0.8,<0.0.15)"] -tortoise = ["tortoise-orm (>=0.16.18,!=0.21.0,<0.22.0)"] +sqlmodel = ["sqlakeyset (>=2.0.1680321678,<3.0.0)", "sqlmodel (>=0.0.22)"] +tortoise = ["tortoise-orm (>=0.22.0)"] [[package]] name = "genson" @@ -1275,13 +1277,13 @@ files = [ [[package]] name = "httpcore" -version = "1.0.6" +version = "1.0.7" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f"}, - {file = "httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f"}, + {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, + {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, ] [package.dependencies] @@ -1375,13 +1377,13 @@ colors = ["colorama (>=0.4.6)"] [[package]] name = "jinja2" -version = "3.1.4" +version = "3.1.5" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, - {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, + {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, + {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, ] [package.dependencies] @@ -1608,13 +1610,13 @@ test = ["mkdocs-d2-plugin", "mkdocs-include-markdown-plugin", "mkdocs-macros-tes [[package]] name = "mkdocs-material" -version = "9.5.44" +version = "9.5.49" description = "Documentation that simply works" optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_material-9.5.44-py3-none-any.whl", hash = "sha256:47015f9c167d58a5ff5e682da37441fc4d66a1c79334bfc08d774763cacf69ca"}, - {file = "mkdocs_material-9.5.44.tar.gz", hash = "sha256:f3a6c968e524166b3f3ed1fb97d3ed3e0091183b0545cedf7156a2a6804c56c0"}, + {file = "mkdocs_material-9.5.49-py3-none-any.whl", hash = "sha256:c3c2d8176b18198435d3a3e119011922f3e11424074645c24019c2dcf08a360e"}, + {file = "mkdocs_material-9.5.49.tar.gz", hash = "sha256:3671bb282b4f53a1c72e08adbe04d2481a98f85fed392530051f80ff94a9621d"}, ] [package.dependencies] @@ -1679,48 +1681,48 @@ beautifulsoup4 = ">=4.11.1" [[package]] name = "mypy" -version = "1.13.0" +version = "1.14.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, - {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, - {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, - {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, - {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, - {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, - {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, - {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, - {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, - {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, - {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, - {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, - {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, - {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, - {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, - {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, - {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, - {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, - {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, - {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, - {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, - {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, - {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, - {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, - {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, - {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, - {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, - {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, - {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, - {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, - {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, - {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, + {file = "mypy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e971c1c667007f9f2b397ffa80fa8e1e0adccff336e5e77e74cb5f22868bee87"}, + {file = "mypy-1.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e86aaeaa3221a278c66d3d673b297232947d873773d61ca3ee0e28b2ff027179"}, + {file = "mypy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1628c5c3ce823d296e41e2984ff88c5861499041cb416a8809615d0c1f41740e"}, + {file = "mypy-1.14.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7fadb29b77fc14a0dd81304ed73c828c3e5cde0016c7e668a86a3e0dfc9f3af3"}, + {file = "mypy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:3fa76988dc760da377c1e5069200a50d9eaaccf34f4ea18428a3337034ab5a44"}, + {file = "mypy-1.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6e73c8a154eed31db3445fe28f63ad2d97b674b911c00191416cf7f6459fd49a"}, + {file = "mypy-1.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:273e70fcb2e38c5405a188425aa60b984ffdcef65d6c746ea5813024b68c73dc"}, + {file = "mypy-1.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1daca283d732943731a6a9f20fdbcaa927f160bc51602b1d4ef880a6fb252015"}, + {file = "mypy-1.14.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7e68047bedb04c1c25bba9901ea46ff60d5eaac2d71b1f2161f33107e2b368eb"}, + {file = "mypy-1.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:7a52f26b9c9b1664a60d87675f3bae00b5c7f2806e0c2800545a32c325920bcc"}, + {file = "mypy-1.14.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d5326ab70a6db8e856d59ad4cb72741124950cbbf32e7b70e30166ba7bbf61dd"}, + {file = "mypy-1.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bf4ec4980bec1e0e24e5075f449d014011527ae0055884c7e3abc6a99cd2c7f1"}, + {file = "mypy-1.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:390dfb898239c25289495500f12fa73aa7f24a4c6d90ccdc165762462b998d63"}, + {file = "mypy-1.14.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7e026d55ddcd76e29e87865c08cbe2d0104e2b3153a523c529de584759379d3d"}, + {file = "mypy-1.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:585ed36031d0b3ee362e5107ef449a8b5dfd4e9c90ccbe36414ee405ee6b32ba"}, + {file = "mypy-1.14.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9f6f4c0b27401d14c483c622bc5105eff3911634d576bbdf6695b9a7c1ba741"}, + {file = "mypy-1.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b2280cedcb312c7a79f5001ae5325582d0d339bce684e4a529069d0e7ca1e7"}, + {file = "mypy-1.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:342de51c48bab326bfc77ce056ba08c076d82ce4f5a86621f972ed39970f94d8"}, + {file = "mypy-1.14.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:00df23b42e533e02a6f0055e54de9a6ed491cd8b7ea738647364fd3a39ea7efc"}, + {file = "mypy-1.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:e8c8387e5d9dff80e7daf961df357c80e694e942d9755f3ad77d69b0957b8e3f"}, + {file = "mypy-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b16738b1d80ec4334654e89e798eb705ac0c36c8a5c4798496cd3623aa02286"}, + {file = "mypy-1.14.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:10065fcebb7c66df04b05fc799a854b1ae24d9963c8bb27e9064a9bdb43aa8ad"}, + {file = "mypy-1.14.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fbb7d683fa6bdecaa106e8368aa973ecc0ddb79a9eaeb4b821591ecd07e9e03c"}, + {file = "mypy-1.14.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3498cb55448dc5533e438cd13d6ddd28654559c8c4d1fd4b5ca57a31b81bac01"}, + {file = "mypy-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:c7b243408ea43755f3a21a0a08e5c5ae30eddb4c58a80f415ca6b118816e60aa"}, + {file = "mypy-1.14.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:14117b9da3305b39860d0aa34b8f1ff74d209a368829a584eb77524389a9c13e"}, + {file = "mypy-1.14.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af98c5a958f9c37404bd4eef2f920b94874507e146ed6ee559f185b8809c44cc"}, + {file = "mypy-1.14.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0b343a1d3989547024377c2ba0dca9c74a2428ad6ed24283c213af8dbb0710b"}, + {file = "mypy-1.14.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cdb5563c1726c85fb201be383168f8c866032db95e1095600806625b3a648cb7"}, + {file = "mypy-1.14.0-cp39-cp39-win_amd64.whl", hash = "sha256:74e925649c1ee0a79aa7448baf2668d81cc287dc5782cff6a04ee93f40fb8d3f"}, + {file = "mypy-1.14.0-py3-none-any.whl", hash = "sha256:2238d7f93fc4027ed1efc944507683df3ba406445a2b6c96e79666a045aadfab"}, + {file = "mypy-1.14.0.tar.gz", hash = "sha256:822dbd184d4a9804df5a7d5335a68cf7662930e70b8c1bc976645d1509f9a9d6"}, ] [package.dependencies] -mypy-extensions = ">=1.0.0" -typing-extensions = ">=4.6.0" +mypy_extensions = ">=1.0.0" +typing_extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] @@ -1821,23 +1823,20 @@ files = [ [[package]] name = "pydantic" -version = "2.9.2" +version = "2.10.4" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"}, - {file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"}, + {file = "pydantic-2.10.4-py3-none-any.whl", hash = "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d"}, + {file = "pydantic-2.10.4.tar.gz", hash = "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06"}, ] [package.dependencies] annotated-types = ">=0.6.0" email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"email\""} -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\""}, -] +pydantic-core = "2.27.2" +typing-extensions = ">=4.12.2" [package.extras] email = ["email-validator (>=2.0.0)"] @@ -1845,100 +1844,111 @@ timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.23.4" +version = "2.27.2" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {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"}, + {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, + {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af"}, + {file = "pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4"}, + {file = "pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"}, + {file = "pydantic_core-2.27.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506"}, + {file = "pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da"}, + {file = "pydantic_core-2.27.2-cp38-cp38-win32.whl", hash = "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b"}, + {file = "pydantic_core-2.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad"}, + {file = "pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993"}, + {file = "pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96"}, + {file = "pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e"}, + {file = "pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35"}, + {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"}, ] [package.dependencies] @@ -1960,13 +1970,13 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pymdown-extensions" -version = "10.12" +version = "10.13" description = "Extension pack for Python Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "pymdown_extensions-10.12-py3-none-any.whl", hash = "sha256:49f81412242d3527b8b4967b990df395c89563043bc51a3d2d7d500e52123b77"}, - {file = "pymdown_extensions-10.12.tar.gz", hash = "sha256:b0ee1e0b2bef1071a47891ab17003bfe5bf824a398e13f49f8ed653b699369a7"}, + {file = "pymdown_extensions-10.13-py3-none-any.whl", hash = "sha256:80bc33d715eec68e683e04298946d47d78c7739e79d808203df278ee8ef89428"}, + {file = "pymdown_extensions-10.13.tar.gz", hash = "sha256:e0b351494dc0d8d14a1f52b39b1499a00ef1566b4ba23dc74f1eba75c736f5dd"}, ] [package.dependencies] @@ -1993,13 +2003,13 @@ rsa = ["cryptography"] [[package]] name = "pytest" -version = "8.3.3" +version = "8.3.4" 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"}, + {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, + {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, ] [package.dependencies] @@ -2306,13 +2316,13 @@ files = [ [[package]] name = "s3transfer" -version = "0.10.3" +version = "0.10.4" description = "An Amazon S3 Transfer Manager" optional = false python-versions = ">=3.8" files = [ - {file = "s3transfer-0.10.3-py3-none-any.whl", hash = "sha256:263ed587a5803c6c708d3ce44dc4dfedaab4c1a32e8329bab818933d79ddcf5d"}, - {file = "s3transfer-0.10.3.tar.gz", hash = "sha256:4f50ed74ab84d474ce614475e0b8d5047ff080810aac5d01ea25231cfc944b0c"}, + {file = "s3transfer-0.10.4-py3-none-any.whl", hash = "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e"}, + {file = "s3transfer-0.10.4.tar.gz", hash = "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7"}, ] [package.dependencies] @@ -2323,23 +2333,23 @@ crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] [[package]] name = "setuptools" -version = "75.5.0" +version = "75.6.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.9" files = [ - {file = "setuptools-75.5.0-py3-none-any.whl", hash = "sha256:87cb777c3b96d638ca02031192d40390e0ad97737e27b6b4fa831bea86f2f829"}, - {file = "setuptools-75.5.0.tar.gz", hash = "sha256:5c4ccb41111392671f02bb5f8436dfc5a9a7185e80500531b133f5775c4163ef"}, + {file = "setuptools-75.6.0-py3-none-any.whl", hash = "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d"}, + {file = "setuptools-75.6.0.tar.gz", hash = "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6"}, ] [package.extras] check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.7.0)"] -core = ["importlib-metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +core = ["importlib_metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (>=1.12,<1.14)", "pytest-mypy"] +type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (>=1.12,<1.14)", "pytest-mypy"] [[package]] name = "shandy-sqlfmt" @@ -2364,13 +2374,13 @@ sqlfmt-primer = ["gitpython (>=3.1.24,<4.0.0)"] [[package]] name = "six" -version = "1.16.0" +version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] @@ -2540,20 +2550,20 @@ tests = ["pytest", "pytest-cov"] [[package]] name = "tqdm" -version = "4.67.0" +version = "4.67.1" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ - {file = "tqdm-4.67.0-py3-none-any.whl", hash = "sha256:0cd8af9d56911acab92182e88d763100d4788bdf421d251616040cc4d44863be"}, - {file = "tqdm-4.67.0.tar.gz", hash = "sha256:fe5a6f95e6fe0b9755e9469b77b9c3cf850048224ecaa8293d7d2d31f97d869a"}, + {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, + {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, ] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [package.extras] -dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] +dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"] discord = ["requests"] notebook = ["ipywidgets (>=6)"] slack = ["slack-sdk"] @@ -2561,35 +2571,35 @@ telegram = ["requests"] [[package]] name = "types-awscrt" -version = "0.23.0" +version = "0.23.6" description = "Type annotations and code completion for awscrt" optional = false python-versions = ">=3.8" files = [ - {file = "types_awscrt-0.23.0-py3-none-any.whl", hash = "sha256:517d9d06f19cf58d778ca90ad01e52e0489466bf70dcf78c7f47f74fdf151a60"}, - {file = "types_awscrt-0.23.0.tar.gz", hash = "sha256:3fd1edeac923d1956c0e907c973fb83bda465beae7f054716b371b293f9b5fdc"}, + {file = "types_awscrt-0.23.6-py3-none-any.whl", hash = "sha256:fbf9c221af5607b24bf17f8431217ce8b9a27917139edbc984891eb63fd5a593"}, + {file = "types_awscrt-0.23.6.tar.gz", hash = "sha256:405bce8c281f9e7c6c92a229225cc0bf10d30729a6a601123213389bd524b8b1"}, ] [[package]] name = "types-s3transfer" -version = "0.10.3" +version = "0.10.4" description = "Type annotations and code completion for s3transfer" optional = false python-versions = ">=3.8" files = [ - {file = "types_s3transfer-0.10.3-py3-none-any.whl", hash = "sha256:d34c5a82f531af95bb550927136ff5b737a1ed3087f90a59d545591dfde5b4cc"}, - {file = "types_s3transfer-0.10.3.tar.gz", hash = "sha256:f761b2876ac4c208e6c6b75cdf5f6939009768be9950c545b11b0225e7703ee7"}, + {file = "types_s3transfer-0.10.4-py3-none-any.whl", hash = "sha256:22ac1aabc98f9d7f2928eb3fb4d5c02bf7435687f0913345a97dd3b84d0c217d"}, + {file = "types_s3transfer-0.10.4.tar.gz", hash = "sha256:03123477e3064c81efe712bf9d372c7c72f2790711431f9baa59cf96ea607267"}, ] [[package]] name = "types-setuptools" -version = "75.3.0.20241112" +version = "75.6.0.20241223" description = "Typing stubs for setuptools" optional = false python-versions = ">=3.8" files = [ - {file = "types-setuptools-75.3.0.20241112.tar.gz", hash = "sha256:f9e1ebd17a56f606e16395c4ee4efa1cdc394b9a2a0ee898a624058b4b62ef8f"}, - {file = "types_setuptools-75.3.0.20241112-py3-none-any.whl", hash = "sha256:78cb5fef4a6056d2f37114d27da90f4655a306e4e38042d7034a8a880bc3f5dd"}, + {file = "types_setuptools-75.6.0.20241223-py3-none-any.whl", hash = "sha256:7cbfd3bf2944f88bbcdd321b86ddd878232a277be95d44c78a53585d78ebc2f6"}, + {file = "types_setuptools-75.6.0.20241223.tar.gz", hash = "sha256:d9478a985057ed48a994c707f548e55aababa85fe1c9b212f43ab5a1fffd3211"}, ] [[package]] @@ -2605,13 +2615,13 @@ files = [ [[package]] name = "urllib3" -version = "2.2.3" +version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, - {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, + {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, + {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, ] [package.extras] @@ -2707,84 +2717,79 @@ watchmedo = ["PyYAML (>=3.10)"] [[package]] name = "wrapt" -version = "1.16.0" +version = "1.17.0" description = "Module for decorators, wrappers and monkey patching." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, - {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, - {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, - {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, - {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, - {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, - {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, - {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, - {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, - {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, - {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, - {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, - {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, - {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, - {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, - {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, - {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, - {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, + {file = "wrapt-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301"}, + {file = "wrapt-1.17.0-cp310-cp310-win32.whl", hash = "sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22"}, + {file = "wrapt-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575"}, + {file = "wrapt-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b"}, + {file = "wrapt-1.17.0-cp311-cp311-win32.whl", hash = "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346"}, + {file = "wrapt-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a"}, + {file = "wrapt-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4"}, + {file = "wrapt-1.17.0-cp312-cp312-win32.whl", hash = "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635"}, + {file = "wrapt-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7"}, + {file = "wrapt-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a"}, + {file = "wrapt-1.17.0-cp313-cp313-win32.whl", hash = "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045"}, + {file = "wrapt-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838"}, + {file = "wrapt-1.17.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab"}, + {file = "wrapt-1.17.0-cp313-cp313t-win32.whl", hash = "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf"}, + {file = "wrapt-1.17.0-cp313-cp313t-win_amd64.whl", hash = "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a"}, + {file = "wrapt-1.17.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f"}, + {file = "wrapt-1.17.0-cp38-cp38-win32.whl", hash = "sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea"}, + {file = "wrapt-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed"}, + {file = "wrapt-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0"}, + {file = "wrapt-1.17.0-cp39-cp39-win32.whl", hash = "sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88"}, + {file = "wrapt-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977"}, + {file = "wrapt-1.17.0-py3-none-any.whl", hash = "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371"}, + {file = "wrapt-1.17.0.tar.gz", hash = "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801"}, ] [metadata] lock-version = "2.0" python-versions = "^3.12.3" -content-hash = "fb85dc06cf57986d089974cb26d9c955508fed9bb7b3fb3e6a3c9664f4cb0f48" +content-hash = "eb709c9f7743d2ece87e418f9acc338636a5c944f250243e220c7488e7df9227"