From a0084bc57e64c2b4e3991230286a70bbc352f78d Mon Sep 17 00:00:00 2001 From: Marc Vilanova Date: Thu, 8 May 2025 09:46:52 -0700 Subject: [PATCH 1/5] chore(typing): modernizes codebase to use Python 3.9+ built-in types --- src/dispatch/auth/service.py | 5 +- src/dispatch/case/flows.py | 9 ++- src/dispatch/case/messaging.py | 3 +- src/dispatch/case/models.py | 1 - src/dispatch/case/priority/service.py | 9 ++- src/dispatch/case/service.py | 15 ++--- src/dispatch/case/severity/service.py | 9 ++- src/dispatch/case/type/service.py | 11 ++- src/dispatch/case/views.py | 5 +- src/dispatch/case_cost/models.py | 7 +- src/dispatch/case_cost/service.py | 15 ++--- src/dispatch/case_cost_type/models.py | 15 ++--- src/dispatch/case_cost_type/service.py | 11 ++- src/dispatch/conference/flows.py | 3 +- src/dispatch/conference/service.py | 7 +- src/dispatch/config.py | 3 +- src/dispatch/conversation/service.py | 6 +- src/dispatch/cost_model/service.py | 3 +- src/dispatch/data/alert/models.py | 15 ++--- src/dispatch/data/alert/service.py | 5 +- src/dispatch/data/query/models.py | 15 ++--- src/dispatch/data/query/service.py | 5 +- .../data/source/data_format/models.py | 7 +- .../data/source/data_format/service.py | 7 +- .../data/source/environment/models.py | 7 +- .../data/source/environment/service.py | 7 +- src/dispatch/data/source/models.py | 59 ++++++++-------- src/dispatch/data/source/service.py | 7 +- src/dispatch/data/source/status/models.py | 7 +- src/dispatch/data/source/status/service.py | 7 +- src/dispatch/data/source/transport/models.py | 7 +- src/dispatch/data/source/transport/service.py | 7 +- src/dispatch/data/source/type/models.py | 7 +- src/dispatch/data/source/type/service.py | 7 +- src/dispatch/database/core.py | 1 - src/dispatch/database/logging.py | 1 - .../versions/2022-10-19_3b0f5b81376f.py | 1 - .../versions/2022-10-26_4b65941d065a.py | 1 - .../versions/2023-01-30_e4b4991dddcd.py | 3 +- src/dispatch/database/service.py | 1 - src/dispatch/decorators.py | 11 ++- src/dispatch/definition/models.py | 15 ++--- src/dispatch/definition/service.py | 9 ++- src/dispatch/document/flows.py | 1 - src/dispatch/document/service.py | 11 ++- src/dispatch/email_templates/models.py | 21 +++--- src/dispatch/email_templates/service.py | 7 +- src/dispatch/entity/models.py | 29 ++++---- src/dispatch/entity/service.py | 25 +++---- src/dispatch/entity_type/models.py | 31 +++++---- src/dispatch/entity_type/service.py | 5 +- src/dispatch/entity_type/views.py | 3 +- src/dispatch/event/models.py | 15 ++--- src/dispatch/event/service.py | 5 +- src/dispatch/evergreen/scheduled.py | 1 - src/dispatch/feedback/incident/messaging.py | 5 +- src/dispatch/feedback/incident/models.py | 15 ++--- src/dispatch/feedback/incident/service.py | 7 +- src/dispatch/feedback/service/messaging.py | 5 +- src/dispatch/feedback/service/models.py | 23 +++---- .../feedback/service/reminder/models.py | 17 +++-- .../feedback/service/reminder/service.py | 3 +- src/dispatch/feedback/service/service.py | 3 +- src/dispatch/forms/models.py | 31 +++++---- src/dispatch/forms/service.py | 5 +- src/dispatch/forms/type/models.py | 23 +++---- src/dispatch/forms/type/service.py | 3 +- src/dispatch/forms/views.py | 3 +- src/dispatch/group/flows.py | 3 +- src/dispatch/group/service.py | 5 +- src/dispatch/incident/flows.py | 3 +- src/dispatch/incident/messaging.py | 5 +- src/dispatch/incident/metrics.py | 5 +- src/dispatch/incident/priority/service.py | 9 ++- src/dispatch/incident/service.py | 15 ++--- src/dispatch/incident/severity/service.py | 9 ++- src/dispatch/incident/type/service.py | 11 ++- src/dispatch/incident/views.py | 3 +- src/dispatch/incident_cost/models.py | 7 +- src/dispatch/incident_cost/service.py | 15 ++--- src/dispatch/incident_cost_type/service.py | 9 ++- src/dispatch/incident_role/models.py | 25 ++++--- src/dispatch/incident_role/service.py | 21 +++--- src/dispatch/individual/service.py | 7 +- src/dispatch/main.py | 5 +- src/dispatch/messaging/strings.py | 5 +- src/dispatch/models.py | 2 - src/dispatch/monitor/models.py | 5 +- src/dispatch/monitor/scheduled.py | 3 +- src/dispatch/monitor/service.py | 9 ++- src/dispatch/nlp.py | 7 +- src/dispatch/notification/models.py | 17 +++-- src/dispatch/notification/service.py | 9 ++- src/dispatch/organization/service.py | 11 ++- src/dispatch/participant/flows.py | 3 +- src/dispatch/participant/service.py | 33 +++++---- src/dispatch/participant_role/flows.py | 1 - src/dispatch/participant_role/models.py | 9 ++- src/dispatch/participant_role/service.py | 7 +- src/dispatch/plugin/models.py | 37 +++++----- src/dispatch/plugin/service.py | 23 +++---- src/dispatch/plugins/base/v1.py | 33 +++++---- .../docs/plugin.py | 3 +- .../dispatch_atlassian_confluence/plugin.py | 3 +- src/dispatch/plugins/dispatch_aws/plugin.py | 1 - src/dispatch/plugins/dispatch_core/plugin.py | 1 - src/dispatch/plugins/dispatch_duo/plugin.py | 1 - .../dispatch_google/calendar/plugin.py | 5 +- .../plugins/dispatch_google/docs/plugin.py | 1 - .../plugins/dispatch_google/drive/drive.py | 3 +- .../plugins/dispatch_google/drive/plugin.py | 7 +- .../plugins/dispatch_google/drive/task.py | 5 +- .../plugins/dispatch_google/gmail/plugin.py | 3 +- .../plugins/dispatch_google/groups/plugin.py | 7 +- src/dispatch/plugins/dispatch_jira/plugin.py | 1 - .../conference/client.py | 1 - .../conference/plugin.py | 3 +- .../plugins/dispatch_pagerduty/plugin.py | 9 ++- .../plugins/dispatch_pagerduty/service.py | 7 +- src/dispatch/plugins/dispatch_slack/bolt.py | 1 - .../plugins/dispatch_slack/case/messages.py | 5 +- src/dispatch/plugins/dispatch_slack/config.py | 9 ++- src/dispatch/plugins/dispatch_slack/events.py | 1 - src/dispatch/plugins/dispatch_slack/fields.py | 7 +- .../plugins/dispatch_slack/handler.py | 5 +- .../dispatch_slack/incident/interactive.py | 1 - .../plugins/dispatch_slack/messaging.py | 7 +- .../plugins/dispatch_slack/middleware.py | 3 +- src/dispatch/plugins/dispatch_slack/models.py | 1 - src/dispatch/plugins/dispatch_slack/plugin.py | 23 +++---- .../plugins/dispatch_slack/service.py | 17 +++-- .../plugins/dispatch_test/conversation.py | 1 - src/dispatch/plugins/dispatch_zoom/plugin.py | 3 +- src/dispatch/project/models.py | 67 +++++++++---------- src/dispatch/project/service.py | 7 +- src/dispatch/report/models.py | 7 +- src/dispatch/report/scheduled.py | 3 +- src/dispatch/report/service.py | 9 ++- src/dispatch/route/models.py | 3 +- src/dispatch/route/service.py | 5 +- src/dispatch/search/fulltext/__init__.py | 1 - src/dispatch/search/models.py | 1 - src/dispatch/search/views.py | 3 +- src/dispatch/search_filter/models.py | 33 +++++---- src/dispatch/search_filter/service.py | 7 +- src/dispatch/service/models.py | 27 ++++---- src/dispatch/service/service.py | 21 +++--- src/dispatch/service/views.py | 5 +- src/dispatch/signal/models.py | 1 - src/dispatch/signal/service.py | 6 +- src/dispatch/signal/views.py | 9 ++- src/dispatch/storage/flows.py | 7 +- src/dispatch/storage/service.py | 5 +- src/dispatch/tag/models.py | 23 +++---- src/dispatch/tag/recommender.py | 9 ++- src/dispatch/tag/scheduled.py | 1 - src/dispatch/tag/service.py | 8 +-- src/dispatch/tag_type/models.py | 29 ++++---- src/dispatch/tag_type/service.py | 10 ++- src/dispatch/task/flows.py | 5 +- src/dispatch/task/models.py | 43 ++++++------ src/dispatch/task/service.py | 13 ++-- src/dispatch/task/views.py | 3 +- src/dispatch/team/models.py | 11 ++- src/dispatch/team/service.py | 11 ++- src/dispatch/term/models.py | 15 ++--- src/dispatch/term/service.py | 5 +- src/dispatch/ticket/service.py | 7 +- src/dispatch/workflow/service.py | 11 ++- 169 files changed, 713 insertions(+), 887 deletions(-) diff --git a/src/dispatch/auth/service.py b/src/dispatch/auth/service.py index eb5691ed0319..c395695f6928 100644 --- a/src/dispatch/auth/service.py +++ b/src/dispatch/auth/service.py @@ -6,7 +6,6 @@ """ import logging -from typing import Annotated, Optional from fastapi import HTTPException, Depends from starlette.requests import Request @@ -44,12 +43,12 @@ ) -def get(*, db_session, user_id: int) -> Optional[DispatchUser]: +def get(*, db_session, user_id: int) -> DispatchUser | None: """Returns a user based on the given user id.""" return db_session.query(DispatchUser).filter(DispatchUser.id == user_id).one_or_none() -def get_by_email(*, db_session, email: str) -> Optional[DispatchUser]: +def get_by_email(*, db_session, email: str) -> DispatchUser | None: """Returns a user object based on user email.""" return db_session.query(DispatchUser).filter(DispatchUser.email == email).one_or_none() diff --git a/src/dispatch/case/flows.py b/src/dispatch/case/flows.py index 0a8c5612249e..e33b838cc9ca 100644 --- a/src/dispatch/case/flows.py +++ b/src/dispatch/case/flows.py @@ -1,6 +1,5 @@ import logging from datetime import datetime -from typing import List, Optional from sqlalchemy.orm import Session @@ -742,8 +741,8 @@ def send_escalation_messages_for_channel_case( def map_case_roles_to_incident_roles( - participant_roles: List[ParticipantRole], incident: Incident, db_session: Session -) -> Optional[List[ParticipantRoleType]]: + participant_roles: list[ParticipantRole], incident: Incident, db_session: Session +) -> list[ParticipantRoleType | None]: # Map the case role to an incident role incident_roles = set() for role in participant_roles: @@ -1001,8 +1000,8 @@ def case_create_conversation_flow( def case_create_resources_flow( db_session: Session, case_id: int, - individual_participants: List[str], - team_participants: List[str], + individual_participants: list[str], + team_participants: list[str], conversation_target: str = None, create_all_resources: bool = True, ) -> None: diff --git a/src/dispatch/case/messaging.py b/src/dispatch/case/messaging.py index 364cd94b04c5..1bfd8b610add 100644 --- a/src/dispatch/case/messaging.py +++ b/src/dispatch/case/messaging.py @@ -7,7 +7,6 @@ import logging -from typing import Optional from sqlalchemy.orm import Session @@ -314,7 +313,7 @@ def send_case_welcome_participant_message( participant_email: str, case: Case, db_session: Session, - welcome_template: Optional[EmailTemplates] = None, + welcome_template: EmailTemplates | None = None, ): if not case.dedicated_channel: return diff --git a/src/dispatch/case/models.py b/src/dispatch/case/models.py index 035a55af0c34..8eab493e3d33 100644 --- a/src/dispatch/case/models.py +++ b/src/dispatch/case/models.py @@ -1,7 +1,6 @@ """Models and schemas for the Dispatch case management system.""" from collections import Counter, defaultdict from datetime import datetime -from typing import Any from pydantic import field_validator, Field from sqlalchemy import ( diff --git a/src/dispatch/case/priority/service.py b/src/dispatch/case/priority/service.py index 976dbda0276c..8333009b2244 100644 --- a/src/dispatch/case/priority/service.py +++ b/src/dispatch/case/priority/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from pydantic import ValidationError from sqlalchemy.sql.expression import true @@ -13,7 +12,7 @@ ) -def get(*, db_session, case_priority_id: int) -> Optional[CasePriority]: +def get(*, db_session, case_priority_id: int) -> CasePriority | None: """Returns a case priority based on the given priority id.""" return db_session.query(CasePriority).filter(CasePriority.id == case_priority_id).one_or_none() @@ -47,7 +46,7 @@ def get_default_or_raise(*, db_session, project_id: int) -> CasePriority: return case_priority -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[CasePriority]: +def get_by_name(*, db_session, project_id: int, name: str) -> CasePriority | None: """Returns a case priority based on the given priority name.""" return ( db_session.query(CasePriority) @@ -96,14 +95,14 @@ def get_by_name_or_default( return get_default_or_raise(db_session=db_session, project_id=project_id) -def get_all(*, db_session, project_id: int = None) -> List[Optional[CasePriority]]: +def get_all(*, db_session, project_id: int = None) -> list[CasePriority | None]: """Returns all case priorities.""" if project_id is not None: return db_session.query(CasePriority).filter(CasePriority.project_id == project_id) return db_session.query(CasePriority) -def get_all_enabled(*, db_session, project_id: int = None) -> List[Optional[CasePriority]]: +def get_all_enabled(*, db_session, project_id: int = None) -> list[CasePriority | None]: """Returns all enabled case priorities.""" if project_id is not None: return ( diff --git a/src/dispatch/case/service.py b/src/dispatch/case/service.py index 72e8668742d1..e2ce5ca40ed9 100644 --- a/src/dispatch/case/service.py +++ b/src/dispatch/case/service.py @@ -4,7 +4,6 @@ from pydantic import ValidationError from sqlalchemy.orm import Session, joinedload, load_only -from typing import List, Optional from dispatch.auth.models import DispatchUser from dispatch.case.priority import service as case_priority_service @@ -32,12 +31,12 @@ log = logging.getLogger(__name__) -def get(*, db_session, case_id: int) -> Optional[Case]: +def get(*, db_session, case_id: int) -> Case | None: """Returns a case based on the given id.""" return db_session.query(Case).filter(Case.id == case_id).first() -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[Case]: +def get_by_name(*, db_session, project_id: int, name: str) -> Case | None: """Returns a case based on the given name.""" return ( db_session.query(Case) @@ -64,12 +63,12 @@ def get_by_name_or_raise(*, db_session, project_id: int, case_in: CaseRead) -> C return case -def get_all(*, db_session, project_id: int) -> List[Optional[Case]]: +def get_all(*, db_session, project_id: int) -> list[Case | None]: """Returns all cases.""" return db_session.query(Case).filter(Case.project_id == project_id) -def get_all_open_by_case_type(*, db_session, case_type_id: int) -> List[Optional[Case]]: +def get_all_open_by_case_type(*, db_session, case_type_id: int) -> list[Case | None]: """Returns all non-closed cases based on the given case type.""" return ( db_session.query(Case) @@ -82,7 +81,7 @@ def get_all_open_by_case_type(*, db_session, case_type_id: int) -> List[Optional def get_all_by_status( *, db_session: Session, project_id: int, statuses: list[str] -) -> List[Optional[Case]]: +) -> list[Case | None]: """Returns all cases based on a given list of statuses.""" return ( db_session.query(Case) @@ -103,7 +102,7 @@ def get_all_by_status( ) -def get_all_last_x_hours(*, db_session, hours: int) -> List[Optional[Case]]: +def get_all_last_x_hours(*, db_session, hours: int) -> list[Case | None]: """Returns all cases in the last x hours.""" now = datetime.utcnow() return db_session.query(Case).filter(Case.created_at >= now - timedelta(hours=hours)).all() @@ -111,7 +110,7 @@ def get_all_last_x_hours(*, db_session, hours: int) -> List[Optional[Case]]: def get_all_last_x_hours_by_status( *, db_session, project_id: int, status: str, hours: int -) -> List[Optional[Case]]: +) -> list[Case | None]: """Returns all cases of a given status in the last x hours.""" now = datetime.utcnow() diff --git a/src/dispatch/case/severity/service.py b/src/dispatch/case/severity/service.py index 5a6f01931817..caf932b6b3e4 100644 --- a/src/dispatch/case/severity/service.py +++ b/src/dispatch/case/severity/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from pydantic import ValidationError from sqlalchemy.sql.expression import true @@ -13,7 +12,7 @@ ) -def get(*, db_session, case_severity_id: int) -> Optional[CaseSeverity]: +def get(*, db_session, case_severity_id: int) -> CaseSeverity | None: """Returns a case severity based on the given severity id.""" return db_session.query(CaseSeverity).filter(CaseSeverity.id == case_severity_id).one_or_none() @@ -43,7 +42,7 @@ def get_default_or_raise(*, db_session, project_id: int) -> CaseSeverity: return case_severity -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[CaseSeverity]: +def get_by_name(*, db_session, project_id: int, name: str) -> CaseSeverity | None: """Returns a case severity based on the given severity name.""" return ( db_session.query(CaseSeverity) @@ -88,14 +87,14 @@ def get_by_name_or_default( return get_default_or_raise(db_session=db_session, project_id=project_id) -def get_all(*, db_session, project_id: int = None) -> List[Optional[CaseSeverity]]: +def get_all(*, db_session, project_id: int = None) -> list[CaseSeverity | None]: """Returns all case severities.""" if project_id: return db_session.query(CaseSeverity).filter(CaseSeverity.project_id == project_id) return db_session.query(CaseSeverity) -def get_all_enabled(*, db_session, project_id: int = None) -> List[Optional[CaseSeverity]]: +def get_all_enabled(*, db_session, project_id: int = None) -> list[CaseSeverity | None]: """Returns all enabled case severities.""" if project_id: return ( diff --git a/src/dispatch/case/type/service.py b/src/dispatch/case/type/service.py index 2ccca12eacbf..5f7decedd17b 100644 --- a/src/dispatch/case/type/service.py +++ b/src/dispatch/case/type/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from sqlalchemy.sql.expression import true @@ -13,7 +12,7 @@ from .models import CaseType, CaseTypeCreate, CaseTypeRead, CaseTypeUpdate -def get(*, db_session, case_type_id: int) -> Optional[CaseType]: +def get(*, db_session, case_type_id: int) -> CaseType | None: """Returns a case type based on the given type id.""" return db_session.query(CaseType).filter(CaseType.id == case_type_id).one_or_none() @@ -37,7 +36,7 @@ def get_default_or_raise(*, db_session, project_id: int) -> CaseType: return case_type -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[CaseType]: +def get_by_name(*, db_session, project_id: int, name: str) -> CaseType | None: """Returns a case type based on the given type name.""" return ( db_session.query(CaseType) @@ -67,7 +66,7 @@ def get_by_name_or_default(*, db_session, project_id: int, case_type_in=CaseType return get_default_or_raise(db_session=db_session, project_id=project_id) -def get_by_slug(*, db_session, project_id: int, slug: str) -> Optional[CaseType]: +def get_by_slug(*, db_session, project_id: int, slug: str) -> CaseType | None: """Returns a case type based on the given type slug.""" return ( db_session.query(CaseType) @@ -77,14 +76,14 @@ def get_by_slug(*, db_session, project_id: int, slug: str) -> Optional[CaseType] ) -def get_all(*, db_session, project_id: int = None) -> List[Optional[CaseType]]: +def get_all(*, db_session, project_id: int = None) -> list[CaseType | None]: """Returns all case types.""" if project_id: return db_session.query(CaseType).filter(CaseType.project_id == project_id) return db_session.query(CaseType) -def get_all_enabled(*, db_session, project_id: int = None) -> List[Optional[CaseType]]: +def get_all_enabled(*, db_session, project_id: int = None) -> list[CaseType | None]: """Returns all enabled case types.""" if project_id: return ( diff --git a/src/dispatch/case/views.py b/src/dispatch/case/views.py index 03ff5b606c19..211124b63833 100644 --- a/src/dispatch/case/views.py +++ b/src/dispatch/case/views.py @@ -1,5 +1,4 @@ import logging -from typing import Annotated, List import json @@ -80,7 +79,7 @@ def get_case( @router.get( "/{case_id}/participants/minimal", - response_model=List[ParticipantReadMinimal], + response_model=list[ParticipantReadMinimal], summary="Retrieves a minimal list of case participants.", dependencies=[Depends(PermissionsDependency([CaseViewPermission]))], ) @@ -114,7 +113,7 @@ def get_case_participants( @router.get("", summary="Retrieves a list of cases.") def get_cases( common: CommonParameters, - include: List[str] = Query([], alias="include[]"), + include: list[str] = Query([], alias="include[]"), expand: bool = Query(default=False), ): """Retrieves all cases.""" diff --git a/src/dispatch/case_cost/models.py b/src/dispatch/case_cost/models.py index 760b431636d2..7e29efe365c2 100644 --- a/src/dispatch/case_cost/models.py +++ b/src/dispatch/case_cost/models.py @@ -3,7 +3,6 @@ from sqlalchemy import Column, ForeignKey, Integer, Numeric from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.orm import relationship -from typing import List, Optional from dispatch.database.core import Base from dispatch.case_cost_type.models import CaseCostTypeRead @@ -35,7 +34,7 @@ class CaseCostCreate(CaseCostBase): class CaseCostUpdate(CaseCostBase): - id: Optional[PrimaryKey] = None + id: PrimaryKey | None = None case_cost_type: CaseCostTypeRead @@ -46,8 +45,8 @@ class CaseCostReadMinimal(DispatchBase): class CaseCostRead(CaseCostBase): id: PrimaryKey case_cost_type: CaseCostTypeRead - updated_at: Optional[datetime] = None + updated_at: datetime | None = None class CaseCostPagination(Pagination): - items: List[CaseCostRead] = [] + items: list[CaseCostRead] = [] diff --git a/src/dispatch/case_cost/service.py b/src/dispatch/case_cost/service.py index 45771cc117da..552f2545ea97 100644 --- a/src/dispatch/case_cost/service.py +++ b/src/dispatch/case_cost/service.py @@ -1,7 +1,6 @@ from datetime import datetime, timedelta, timezone import logging import math -from typing import Optional from sqlalchemy.orm import Session @@ -27,19 +26,19 @@ log = logging.getLogger(__name__) -def get(*, db_session: Session, case_cost_id: int) -> Optional[CaseCost]: +def get(*, db_session: Session, case_cost_id: int) -> CaseCost | None: """Gets a case cost by its id.""" return db_session.query(CaseCost).filter(CaseCost.id == case_cost_id).one_or_none() -def get_by_case_id(*, db_session, case_id: int) -> list[Optional[CaseCost]]: +def get_by_case_id(*, db_session, case_id: int) -> list[CaseCost | None]: """Gets case costs by their case id.""" return db_session.query(CaseCost).filter(CaseCost.case_id == case_id).all() def get_by_case_id_and_case_cost_type_id( *, db_session: Session, case_id: int, case_cost_type_id: int -) -> Optional[CaseCost]: +) -> CaseCost | None: """Gets case costs by their case id and case cost type id.""" return ( db_session.query(CaseCost) @@ -50,7 +49,7 @@ def get_by_case_id_and_case_cost_type_id( ) -def get_all(*, db_session: Session) -> list[Optional[CaseCost]]: +def get_all(*, db_session: Session) -> list[CaseCost | None]: """Gets all case costs.""" return db_session.query(CaseCost) @@ -133,7 +132,7 @@ def calculate_response_cost(hourly_rate, total_response_time_seconds) -> int: def get_or_create_case_response_cost_by_model_type( case: Case, model_type: str, db_session: Session -) -> Optional[CaseCost]: +) -> CaseCost | None: """Gets a case response cost for a specific model type.""" # Find the cost type matching the requested model type for the project response_cost_type = case_cost_type_service.get_or_create_response_cost_type( @@ -165,7 +164,7 @@ def get_or_create_case_response_cost_by_model_type( def fetch_case_events( case: Case, activity: CostModelActivity, oldest: str, db_session: Session -) -> list[Optional[tuple[datetime.timestamp, str]]]: +) -> list[tuple[datetime.timestamp, str | None]]: """Fetches case events for a given case and cost model activity. Args: @@ -175,7 +174,7 @@ def fetch_case_events( db_session: The database session. Returns: - list[Optional[tuple[datetime.timestamp, str]]]: A list of tuples containing the timestamp and user_id of each event. + list[tuple[datetime.timestamp, str | None]]: A list of tuples containing the timestamp and user_id of each event. """ plugin_instance = plugin_service.get_active_instance_by_slug( diff --git a/src/dispatch/case_cost_type/models.py b/src/dispatch/case_cost_type/models.py index ae8323a01a02..eafe4326354c 100644 --- a/src/dispatch/case_cost_type/models.py +++ b/src/dispatch/case_cost_type/models.py @@ -1,5 +1,4 @@ from datetime import datetime -from typing import List, Optional from pydantic import Field from sqlalchemy import Column, Integer, String, Boolean @@ -38,12 +37,12 @@ class CaseCostType(Base, TimeStampMixin, ProjectMixin): # Pydantic Models class CaseCostTypeBase(DispatchBase): name: NameStr - description: Optional[str] = Field(None, nullable=True) - category: Optional[str] = Field(None, nullable=True) - details: Optional[dict] = {} - created_at: Optional[datetime] - editable: Optional[bool] - model_type: Optional[str] = Field(None, nullable=False) + description: str | None = Field(None, nullable=True) + category: str | None = Field(None, nullable=True) + details: dict | None = {} + created_at: datetime | None + editable: bool | None + model_type: str | None = Field(None, nullable=False) class CaseCostTypeCreate(CaseCostTypeBase): @@ -59,4 +58,4 @@ class CaseCostTypeRead(CaseCostTypeBase): class CaseCostTypePagination(Pagination): - items: List[CaseCostTypeRead] = [] + items: list[CaseCostTypeRead] = [] diff --git a/src/dispatch/case_cost_type/service.py b/src/dispatch/case_cost_type/service.py index 078416e28f01..96fd2f278925 100644 --- a/src/dispatch/case_cost_type/service.py +++ b/src/dispatch/case_cost_type/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from datetime import datetime, timezone from dispatch.case.enums import CostModelType @@ -12,14 +11,14 @@ ) -def get(*, db_session, case_cost_type_id: int) -> Optional[CaseCostType]: +def get(*, db_session, case_cost_type_id: int) -> CaseCostType | None: """Gets a case cost type by its id.""" return db_session.query(CaseCostType).filter(CaseCostType.id == case_cost_type_id).one_or_none() def get_response_cost_type( *, db_session, project_id: int, model_type: str -) -> Optional[CaseCostType]: +) -> CaseCostType | None: """Gets the default response cost type.""" return ( db_session.query(CaseCostType) @@ -55,7 +54,7 @@ def get_or_create_response_cost_type( def get_all_response_case_cost_types( *, db_session, project_id: int -) -> List[Optional[CaseCostType]]: +) -> list[CaseCostType | None]: """Returns all response case cost types. This function queries the database for all case cost types that are marked as the response cost type. @@ -77,7 +76,7 @@ def get_all_response_case_cost_types( ) -def get_by_name(*, db_session, project_id: int, case_cost_type_name: str) -> Optional[CaseCostType]: +def get_by_name(*, db_session, project_id: int, case_cost_type_name: str) -> CaseCostType | None: """Gets a case cost type by its name.""" return ( db_session.query(CaseCostType) @@ -87,7 +86,7 @@ def get_by_name(*, db_session, project_id: int, case_cost_type_name: str) -> Opt ) -def get_all(*, db_session) -> List[Optional[CaseCostType]]: +def get_all(*, db_session) -> list[CaseCostType | None]: """Gets all case cost types.""" return db_session.query(CaseCostType).all() diff --git a/src/dispatch/conference/flows.py b/src/dispatch/conference/flows.py index a9a1b206be3e..dcb039ac93a1 100644 --- a/src/dispatch/conference/flows.py +++ b/src/dispatch/conference/flows.py @@ -1,5 +1,4 @@ import logging -from typing import List from dispatch.database.core import SessionLocal from dispatch.event import service as event_service @@ -12,7 +11,7 @@ log = logging.getLogger(__name__) -def create_conference(incident: Incident, participants: List[str], db_session: SessionLocal): +def create_conference(incident: Incident, participants: list[str], db_session: SessionLocal): """Creates a conference room.""" plugin = plugin_service.get_active_instance( db_session=db_session, project_id=incident.project.id, plugin_type="conference" diff --git a/src/dispatch/conference/service.py b/src/dispatch/conference/service.py index 48c9ac02e41a..a65b8eb2591c 100644 --- a/src/dispatch/conference/service.py +++ b/src/dispatch/conference/service.py @@ -1,19 +1,18 @@ -from typing import Optional from .models import Conference, ConferenceCreate -def get(*, db_session, conference_id: int) -> Optional[Conference]: +def get(*, db_session, conference_id: int) -> Conference | None: """Get a conference by its id.""" return db_session.query(Conference).filter(Conference.id == conference_id).one() -def get_by_resource_id(*, db_session, resource_id: str) -> Optional[Conference]: +def get_by_resource_id(*, db_session, resource_id: str) -> Conference | None: """Get a conference by its id.""" return db_session.query(Conference).filter(Conference.resource_id == resource_id).one_or_none() -def get_by_incident_id(*, db_session, incident_id: str) -> Optional[Conference]: +def get_by_incident_id(*, db_session, incident_id: str) -> Conference | None: """Get a conference by its associated incident id.""" return db_session.query(Conference).filter(Conference.incident_id == incident_id).one() diff --git a/src/dispatch/config.py b/src/dispatch/config.py index 5ebf79bdc21d..754ae727be4b 100644 --- a/src/dispatch/config.py +++ b/src/dispatch/config.py @@ -1,7 +1,6 @@ import base64 import logging import os -from typing import List from urllib import parse from pydantic import BaseModel @@ -15,7 +14,7 @@ class BaseConfigurationModel(BaseModel): pass -def get_env_tags(tag_list: List[str]) -> dict: +def get_env_tags(tag_list: list[str]) -> dict: """Create dictionary of available env tags.""" tags = {} for t in tag_list: diff --git a/src/dispatch/conversation/service.py b/src/dispatch/conversation/service.py index 39c065c9bf29..02dfbfd0ab4d 100644 --- a/src/dispatch/conversation/service.py +++ b/src/dispatch/conversation/service.py @@ -1,16 +1,14 @@ -from typing import Optional - from .models import Conversation, ConversationCreate, ConversationUpdate -def get(*, db_session, conversation_id: int) -> Optional[Conversation]: +def get(*, db_session, conversation_id: int) -> Conversation | None: """Gets a conversation by its id.""" return db_session.query(Conversation).filter(Conversation.id == conversation_id).one_or_none() def get_by_channel_id_ignoring_channel_type( db_session, channel_id: str, thread_id: str = None -) -> Optional[Conversation]: +) -> Conversation | None: """ Gets a conversation by its id ignoring the channel type, and updates the channel id in the database if the channel type has changed. diff --git a/src/dispatch/cost_model/service.py b/src/dispatch/cost_model/service.py index dbc058923bc6..50568f68b79e 100644 --- a/src/dispatch/cost_model/service.py +++ b/src/dispatch/cost_model/service.py @@ -1,6 +1,5 @@ from datetime import datetime import logging -from typing import List from .models import ( CostModel, @@ -40,7 +39,7 @@ def get_default(*, db_session, project_id: int) -> CostModel: ) -def get_all(*, db_session, project_id: int) -> List[CostModel]: +def get_all(*, db_session, project_id: int) -> list[CostModel]: """Returns all cost models.""" if project_id: return db_session.query(CostModel).filter(CostModel.project_id == project_id) diff --git a/src/dispatch/data/alert/models.py b/src/dispatch/data/alert/models.py index 8fd6a5cc0176..7ecb74d25e18 100644 --- a/src/dispatch/data/alert/models.py +++ b/src/dispatch/data/alert/models.py @@ -1,4 +1,3 @@ -from typing import Optional, List from pydantic import Field from sqlalchemy import Column, ForeignKey, Integer, String @@ -20,18 +19,18 @@ class Alert(Base, TimeStampMixin): # Pydantic models class AlertBase(DispatchBase): - name: Optional[str] = Field(None, nullable=False) - description: Optional[str] = Field(None, nullable=True) - originator: Optional[str] = Field(None, nullable=True) - external_link: Optional[str] = Field(None, nullable=True) + name: str | None = Field(None, nullable=False) + description: str | None = Field(None, nullable=True) + originator: str | None = Field(None, nullable=True) + external_link: str | None = Field(None, nullable=True) class AlertCreate(AlertBase): - id: Optional[PrimaryKey] + id: PrimaryKey | None class AlertUpdate(AlertBase): - id: Optional[PrimaryKey] + id: PrimaryKey | None class AlertRead(AlertBase): @@ -39,4 +38,4 @@ class AlertRead(AlertBase): class AlertPagination(Pagination): - items: List[AlertRead] + items: list[AlertRead] diff --git a/src/dispatch/data/alert/service.py b/src/dispatch/data/alert/service.py index 28a14f80da02..f144f187223a 100644 --- a/src/dispatch/data/alert/service.py +++ b/src/dispatch/data/alert/service.py @@ -1,4 +1,3 @@ -from typing import Optional from pydantic import ValidationError @@ -6,12 +5,12 @@ from .models import Alert, AlertCreate, AlertRead, AlertUpdate -def get(*, db_session, alert_id: int) -> Optional[Alert]: +def get(*, db_session, alert_id: int) -> Alert | None: """Gets an alert by its id.""" return db_session.query(Alert).filter(Alert.id == alert_id).one_or_none() -def get_by_name(*, db_session, name: str) -> Optional[Alert]: +def get_by_name(*, db_session, name: str) -> Alert | None: """Gets a alert by its name.""" return db_session.query(Alert).filter(Alert.name == name).one_or_none() diff --git a/src/dispatch/data/query/models.py b/src/dispatch/data/query/models.py index 2fd669bb3458..5733fdf52665 100644 --- a/src/dispatch/data/query/models.py +++ b/src/dispatch/data/query/models.py @@ -1,4 +1,3 @@ -from typing import Optional, List from pydantic import Field from sqlalchemy import Column, Integer, String, Table, ForeignKey, PrimaryKeyConstraint @@ -50,11 +49,11 @@ class Query(Base, TimeStampMixin, ProjectMixin): # Pydantic models class QueryBase(DispatchBase): - name: Optional[str] = Field(None, nullable=False) - description: Optional[str] = Field(None, nullable=True) - language: Optional[str] = Field(None, nullable=True) - text: Optional[str] = Field(None, nullable=True) - tags: Optional[List[TagRead]] = [] + name: str | None = Field(None, nullable=False) + description: str | None = Field(None, nullable=True) + language: str | None = Field(None, nullable=True) + text: str | None = Field(None, nullable=True) + tags: list[TagRead | None] = [] source: SourceRead project: ProjectRead @@ -64,7 +63,7 @@ class QueryCreate(QueryBase): class QueryUpdate(QueryBase): - id: Optional[PrimaryKey] + id: PrimaryKey | None class QueryRead(QueryBase): @@ -72,4 +71,4 @@ class QueryRead(QueryBase): class QueryPagination(Pagination): - items: List[QueryRead] + items: list[QueryRead] diff --git a/src/dispatch/data/query/service.py b/src/dispatch/data/query/service.py index c1bbc7e197f0..8fe6c9f554a6 100644 --- a/src/dispatch/data/query/service.py +++ b/src/dispatch/data/query/service.py @@ -1,4 +1,3 @@ -from typing import Optional from pydantic import ValidationError from dispatch.project import service as project_service @@ -8,12 +7,12 @@ from .models import Query, QueryCreate, QueryUpdate, QueryRead -def get(*, db_session, query_id: int) -> Optional[Query]: +def get(*, db_session, query_id: int) -> Query | None: """Gets a query by its id.""" return db_session.query(Query).filter(Query.id == query_id).one_or_none() -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[Query]: +def get_by_name(*, db_session, project_id: int, name: str) -> Query | None: """Gets a query by its name.""" return ( db_session.query(Query) diff --git a/src/dispatch/data/source/data_format/models.py b/src/dispatch/data/source/data_format/models.py index aec18086eb6b..d16b07cab94b 100644 --- a/src/dispatch/data/source/data_format/models.py +++ b/src/dispatch/data/source/data_format/models.py @@ -1,4 +1,3 @@ -from typing import Optional, List from pydantic import Field from sqlalchemy import ( @@ -24,8 +23,8 @@ class SourceDataFormat(Base, ProjectMixin): class SourceDataFormatBase(DispatchBase): - name: Optional[str] = Field(None, nullable=False) - description: Optional[str] = Field(None, nullable=True) + name: str | None = Field(None, nullable=False) + description: str | None = Field(None, nullable=True) class SourceDataFormatRead(SourceDataFormatBase): @@ -42,4 +41,4 @@ class SourceDataFormatUpdate(SourceDataFormatBase): class SourceDataFormatPagination(Pagination): - items: List[SourceDataFormatRead] + items: list[SourceDataFormatRead] diff --git a/src/dispatch/data/source/data_format/service.py b/src/dispatch/data/source/data_format/service.py index d77a7bd6ae8a..77a278c4fc3c 100644 --- a/src/dispatch/data/source/data_format/service.py +++ b/src/dispatch/data/source/data_format/service.py @@ -1,4 +1,3 @@ -from typing import Optional, List from pydantic import ValidationError from dispatch.project import service as project_service @@ -11,7 +10,7 @@ ) -def get(*, db_session, source_data_format_id: int) -> Optional[SourceDataFormat]: +def get(*, db_session, source_data_format_id: int) -> SourceDataFormat | None: """Gets a data source by its id.""" return ( db_session.query(SourceDataFormat) @@ -20,7 +19,7 @@ def get(*, db_session, source_data_format_id: int) -> Optional[SourceDataFormat] ) -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[SourceDataFormat]: +def get_by_name(*, db_session, project_id: int, name: str) -> SourceDataFormat | None: """Gets a source by its name.""" return ( db_session.query(SourceDataFormat) @@ -51,7 +50,7 @@ def get_by_name_or_raise( return data_format -def get_all(*, db_session, project_id: int) -> List[Optional[SourceDataFormat]]: +def get_all(*, db_session, project_id: int) -> list[SourceDataFormat | None]: """Gets all sources.""" return db_session.query(SourceDataFormat).filter(SourceDataFormat.project_id == project_id) diff --git a/src/dispatch/data/source/environment/models.py b/src/dispatch/data/source/environment/models.py index 1fa2507df3fc..81aeafe19e97 100644 --- a/src/dispatch/data/source/environment/models.py +++ b/src/dispatch/data/source/environment/models.py @@ -1,4 +1,3 @@ -from typing import Optional, List from pydantic import Field from sqlalchemy import ( @@ -24,8 +23,8 @@ class SourceEnvironment(Base, ProjectMixin): class SourceEnvironmentBase(DispatchBase): - name: Optional[str] = Field(None, nullable=False) - description: Optional[str] = Field(None, nullable=True) + name: str | None = Field(None, nullable=False) + description: str | None = Field(None, nullable=True) class SourceEnvironmentRead(SourceEnvironmentBase): @@ -42,4 +41,4 @@ class SourceEnvironmentUpdate(SourceEnvironmentBase): class SourceEnvironmentPagination(Pagination): - items: List[SourceEnvironmentRead] + items: list[SourceEnvironmentRead] diff --git a/src/dispatch/data/source/environment/service.py b/src/dispatch/data/source/environment/service.py index 56f7d77c69e6..8c131c5e58bb 100644 --- a/src/dispatch/data/source/environment/service.py +++ b/src/dispatch/data/source/environment/service.py @@ -1,4 +1,3 @@ -from typing import Optional, List from pydantic import ValidationError from dispatch.project import service as project_service @@ -11,7 +10,7 @@ ) -def get(*, db_session, source_environment_id: int) -> Optional[SourceEnvironment]: +def get(*, db_session, source_environment_id: int) -> SourceEnvironment | None: """Gets a source by its id.""" return ( db_session.query(SourceEnvironment) @@ -20,7 +19,7 @@ def get(*, db_session, source_environment_id: int) -> Optional[SourceEnvironment ) -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[SourceEnvironment]: +def get_by_name(*, db_session, project_id: int, name: str) -> SourceEnvironment | None: """Gets a source by its name.""" return ( db_session.query(SourceEnvironment) @@ -53,7 +52,7 @@ def get_by_name_or_raise( return source -def get_all(*, db_session, project_id: int) -> List[Optional[SourceEnvironment]]: +def get_all(*, db_session, project_id: int) -> list[SourceEnvironment | None]: """Gets all sources.""" return db_session.query(SourceEnvironment).filter(SourceEnvironment.project_id == project_id) diff --git a/src/dispatch/data/source/models.py b/src/dispatch/data/source/models.py index 74a226a4ca39..96ab6d7a3183 100644 --- a/src/dispatch/data/source/models.py +++ b/src/dispatch/data/source/models.py @@ -1,4 +1,3 @@ -from typing import Optional, List from datetime import datetime from pydantic import Field, AnyHttpUrl @@ -103,18 +102,18 @@ class QueryReadMinimal(DispatchBase): class Link(DispatchBase): - id: Optional[int] - name: Optional[str] - description: Optional[str] - href: Optional[AnyHttpUrl] + id: int | None + name: str | None + description: str | None + href: AnyHttpUrl | None # Pydantic models class SourceBase(DispatchBase): - name: Optional[str] = Field(None, nullable=False) - description: Optional[str] = Field(None, nullable=True) - data_last_loaded_at: Optional[datetime] = Field(None, nullable=True, title="Last Loaded") - sampling_rate: Optional[int] = Field( + name: str | None = Field(None, nullable=False) + description: str | None = Field(None, nullable=True) + data_last_loaded_at: datetime | None = Field(None, nullable=True, title="Last Loaded") + sampling_rate: int | None = Field( None, nullable=True, title="Sampling Rate", @@ -122,25 +121,25 @@ class SourceBase(DispatchBase): gt=1, description="Rate at which data is sampled (as a percentage) 100% meaning all data is captured.", ) - source_schema: Optional[str] = Field(None, nullable=True) - documentation: Optional[str] = Field(None, nullable=True) - retention: Optional[int] = Field(None, nullable=True) - delay: Optional[int] = Field(None, nullable=True) - size: Optional[int] = Field(None, nullable=True) - external_id: Optional[str] = Field(None, nullable=True) - aggregated: Optional[bool] = Field(False, nullable=True) - links: Optional[List[Link]] = Field(default_factory=list) - tags: Optional[List[TagRead]] = [] - incidents: Optional[List[IncidentRead]] = [] - queries: Optional[List[QueryReadMinimal]] = [] - alerts: Optional[List[AlertRead]] = [] - cost: Optional[float] - owner: Optional[ServiceRead] = Field(None, nullable=True) - source_type: Optional[SourceTypeRead] - source_environment: Optional[SourceEnvironmentRead] - source_data_format: Optional[SourceDataFormatRead] - source_status: Optional[SourceStatusRead] - source_transport: Optional[SourceTransportRead] + source_schema: str | None = Field(None, nullable=True) + documentation: str | None = Field(None, nullable=True) + retention: int | None = Field(None, nullable=True) + delay: int | None = Field(None, nullable=True) + size: int | None = Field(None, nullable=True) + external_id: str | None = Field(None, nullable=True) + aggregated: bool | None = Field(False, nullable=True) + links: list[Link | None] = Field(default_factory=list) + tags: list[TagRead | None] = [] + incidents: list[IncidentRead | None] = [] + queries: list[QueryReadMinimal | None] = [] + alerts: list[AlertRead | None] = [] + cost: float | None + owner: ServiceRead | None = Field(None, nullable=True) + source_type: SourceTypeRead | None + source_environment: SourceEnvironmentRead | None + source_data_format: SourceDataFormatRead | None + source_status: SourceStatusRead | None + source_transport: SourceTransportRead | None project: ProjectRead @@ -149,7 +148,7 @@ class SourceCreate(SourceBase): class SourceUpdate(SourceBase): - id: Optional[PrimaryKey] + id: PrimaryKey | None class SourceRead(SourceBase): @@ -157,4 +156,4 @@ class SourceRead(SourceBase): class SourcePagination(Pagination): - items: List[SourceRead] + items: list[SourceRead] diff --git a/src/dispatch/data/source/service.py b/src/dispatch/data/source/service.py index c90fbd645600..eaf76f7c2ffe 100644 --- a/src/dispatch/data/source/service.py +++ b/src/dispatch/data/source/service.py @@ -1,4 +1,3 @@ -from typing import Optional, List from pydantic import ValidationError from dispatch.project import service as project_service @@ -16,12 +15,12 @@ from .models import Source, SourceCreate, SourceUpdate, SourceRead -def get(*, db_session, source_id: int) -> Optional[Source]: +def get(*, db_session, source_id: int) -> Source | None: """Gets a source by its id.""" return db_session.query(Source).filter(Source.id == source_id).one_or_none() -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[Source]: +def get_by_name(*, db_session, project_id: int, name: str) -> Source | None: """Gets a source by its name.""" return ( db_session.query(Source) @@ -48,7 +47,7 @@ def get_by_name_or_raise(*, db_session, project_id, source_in: SourceRead) -> So return source -def get_all(*, db_session, project_id: int) -> List[Optional[Source]]: +def get_all(*, db_session, project_id: int) -> list[Source | None]: """Gets all sources.""" return db_session.query(Source).filter(Source.project_id == project_id) diff --git a/src/dispatch/data/source/status/models.py b/src/dispatch/data/source/status/models.py index 700ae865ecc2..fc7a8314dbeb 100644 --- a/src/dispatch/data/source/status/models.py +++ b/src/dispatch/data/source/status/models.py @@ -1,4 +1,3 @@ -from typing import Optional, List from pydantic import Field from sqlalchemy import ( @@ -24,8 +23,8 @@ class SourceStatus(Base, ProjectMixin): class SourceStatusBase(DispatchBase): - name: Optional[str] = Field(None, nullable=False) - description: Optional[str] = Field(None, nullable=True) + name: str | None = Field(None, nullable=False) + description: str | None = Field(None, nullable=True) class SourceStatusRead(SourceStatusBase): @@ -42,4 +41,4 @@ class SourceStatusUpdate(SourceStatusBase): class SourceStatusPagination(Pagination): - items: List[SourceStatusRead] + items: list[SourceStatusRead] diff --git a/src/dispatch/data/source/status/service.py b/src/dispatch/data/source/status/service.py index 5c3c370ff2a0..114271ea352f 100644 --- a/src/dispatch/data/source/status/service.py +++ b/src/dispatch/data/source/status/service.py @@ -1,4 +1,3 @@ -from typing import Optional, List from pydantic import ValidationError from dispatch.project import service as project_service @@ -11,12 +10,12 @@ ) -def get(*, db_session, source_status_id: int) -> Optional[SourceStatus]: +def get(*, db_session, source_status_id: int) -> SourceStatus | None: """Gets a status by its id.""" return db_session.query(SourceStatus).filter(SourceStatus.id == source_status_id).one_or_none() -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[SourceStatus]: +def get_by_name(*, db_session, project_id: int, name: str) -> SourceStatus | None: """Gets a status by its name.""" return ( db_session.query(SourceStatus) @@ -45,7 +44,7 @@ def get_by_name_or_raise( return status -def get_all(*, db_session, project_id: int) -> List[Optional[SourceStatus]]: +def get_all(*, db_session, project_id: int) -> list[SourceStatus | None]: """Gets all sources.""" return db_session.query(SourceStatus).filter(SourceStatus.project_id == project_id) diff --git a/src/dispatch/data/source/transport/models.py b/src/dispatch/data/source/transport/models.py index 12be6e5ff423..ed7b0024a2fd 100644 --- a/src/dispatch/data/source/transport/models.py +++ b/src/dispatch/data/source/transport/models.py @@ -1,4 +1,3 @@ -from typing import Optional, List from pydantic import Field from sqlalchemy import ( @@ -24,8 +23,8 @@ class SourceTransport(Base, ProjectMixin): class SourceTransportBase(DispatchBase): - name: Optional[str] = Field(None, nullable=False) - description: Optional[str] = Field(None, nullable=True) + name: str | None = Field(None, nullable=False) + description: str | None = Field(None, nullable=True) class SourceTransportRead(SourceTransportBase): @@ -42,4 +41,4 @@ class SourceTransportUpdate(SourceTransportBase): class SourceTransportPagination(Pagination): - items: List[SourceTransportRead] + items: list[SourceTransportRead] diff --git a/src/dispatch/data/source/transport/service.py b/src/dispatch/data/source/transport/service.py index d0af013f524b..ba5106ccb9fb 100644 --- a/src/dispatch/data/source/transport/service.py +++ b/src/dispatch/data/source/transport/service.py @@ -1,4 +1,3 @@ -from typing import Optional, List from pydantic import ValidationError from dispatch.project import service as project_service @@ -11,7 +10,7 @@ ) -def get(*, db_session, source_transport_id: int) -> Optional[SourceTransport]: +def get(*, db_session, source_transport_id: int) -> SourceTransport | None: """Gets a source transport by its id.""" return ( db_session.query(SourceTransport) @@ -20,7 +19,7 @@ def get(*, db_session, source_transport_id: int) -> Optional[SourceTransport]: ) -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[SourceTransport]: +def get_by_name(*, db_session, project_id: int, name: str) -> SourceTransport | None: """Gets a source transport by its name.""" return ( db_session.query(SourceTransport) @@ -51,7 +50,7 @@ def get_by_name_or_raise( return source -def get_all(*, db_session, project_id: int) -> List[Optional[SourceTransport]]: +def get_all(*, db_session, project_id: int) -> list[SourceTransport | None]: """Gets all source transports.""" return db_session.query(SourceTransport).filter(SourceTransport.project_id == project_id) diff --git a/src/dispatch/data/source/type/models.py b/src/dispatch/data/source/type/models.py index 166fe4b35c4e..b7271097abbe 100644 --- a/src/dispatch/data/source/type/models.py +++ b/src/dispatch/data/source/type/models.py @@ -1,4 +1,3 @@ -from typing import Optional, List from pydantic import Field from sqlalchemy import ( @@ -24,8 +23,8 @@ class SourceType(Base, ProjectMixin): class SourceTypeBase(DispatchBase): - name: Optional[str] = Field(None, nullable=False) - description: Optional[str] = Field(None, nullable=True) + name: str | None = Field(None, nullable=False) + description: str | None = Field(None, nullable=True) class SourceTypeRead(SourceTypeBase): @@ -42,4 +41,4 @@ class SourceTypeUpdate(SourceTypeBase): class SourceTypePagination(Pagination): - items: List[SourceTypeRead] + items: list[SourceTypeRead] diff --git a/src/dispatch/data/source/type/service.py b/src/dispatch/data/source/type/service.py index 5a9a9739bfbe..34e9bfda7054 100644 --- a/src/dispatch/data/source/type/service.py +++ b/src/dispatch/data/source/type/service.py @@ -1,4 +1,3 @@ -from typing import Optional, List from pydantic import ValidationError from dispatch.project import service as project_service @@ -11,12 +10,12 @@ ) -def get(*, db_session, source_type_id: int) -> Optional[SourceType]: +def get(*, db_session, source_type_id: int) -> SourceType | None: """Gets a source by its id.""" return db_session.query(SourceType).filter(SourceType.id == source_type_id).one_or_none() -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[SourceType]: +def get_by_name(*, db_session, project_id: int, name: str) -> SourceType | None: """Gets a source by its name.""" return ( db_session.query(SourceType) @@ -45,7 +44,7 @@ def get_by_name_or_raise( return source -def get_all(*, db_session, project_id: int) -> List[Optional[SourceType]]: +def get_all(*, db_session, project_id: int) -> list[SourceType | None]: """Gets all source types.""" return db_session.query(SourceType).filter(SourceType.project_id == project_id) diff --git a/src/dispatch/database/core.py b/src/dispatch/database/core.py index 440d16d645f9..296d06ff21b3 100644 --- a/src/dispatch/database/core.py +++ b/src/dispatch/database/core.py @@ -8,7 +8,6 @@ import functools import re from contextlib import contextmanager -from typing import Annotated, Any from fastapi import Depends from pydantic import BaseModel, ValidationError diff --git a/src/dispatch/database/logging.py b/src/dispatch/database/logging.py index f297696e3f93..ff8c65ab2931 100644 --- a/src/dispatch/database/logging.py +++ b/src/dispatch/database/logging.py @@ -1,7 +1,6 @@ import logging import uuid from datetime import datetime -from typing import Any from sqlalchemy.orm import Session diff --git a/src/dispatch/database/revisions/tenant/versions/2022-10-19_3b0f5b81376f.py b/src/dispatch/database/revisions/tenant/versions/2022-10-19_3b0f5b81376f.py index c336b45dc1a4..b50429555329 100644 --- a/src/dispatch/database/revisions/tenant/versions/2022-10-19_3b0f5b81376f.py +++ b/src/dispatch/database/revisions/tenant/versions/2022-10-19_3b0f5b81376f.py @@ -16,7 +16,6 @@ from sqlalchemy.sql.schema import UniqueConstraint from dispatch.incident.severity import service as incident_severity_service -from typing_extensions import Annotated PrimaryKey = Annotated[int, Field(gt=0, lt=2147483647)] NameStr = Annotated[str, StringConstraints(pattern=r"^.*\S.*$", strip_whitespace=True, min_length=3)] diff --git a/src/dispatch/database/revisions/tenant/versions/2022-10-26_4b65941d065a.py b/src/dispatch/database/revisions/tenant/versions/2022-10-26_4b65941d065a.py index a33ff3df62c1..41e1c74dfe9a 100644 --- a/src/dispatch/database/revisions/tenant/versions/2022-10-26_4b65941d065a.py +++ b/src/dispatch/database/revisions/tenant/versions/2022-10-26_4b65941d065a.py @@ -13,7 +13,6 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship, Session from pydantic import Field, StringConstraints -from typing_extensions import Annotated PrimaryKey = Annotated[int, Field(gt=0, lt=2147483647)] diff --git a/src/dispatch/database/revisions/tenant/versions/2023-01-30_e4b4991dddcd.py b/src/dispatch/database/revisions/tenant/versions/2023-01-30_e4b4991dddcd.py index 4cb85cc67e46..c271c4cdaa98 100644 --- a/src/dispatch/database/revisions/tenant/versions/2023-01-30_e4b4991dddcd.py +++ b/src/dispatch/database/revisions/tenant/versions/2023-01-30_e4b4991dddcd.py @@ -14,7 +14,6 @@ from sqlalchemy.sql.expression import true from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.ext.declarative import declarative_base -from typing import Optional # revision identifiers, used by Alembic. revision = "e4b4991dddcd" @@ -74,7 +73,7 @@ class ParticipantRoleType(DispatchEnum): class ParticipantRoleCreate(ParticipantRoleBase): - role: Optional[ParticipantRoleType] = None + role: ParticipantRoleType | None = None class ProjectMixin(object): diff --git a/src/dispatch/database/service.py b/src/dispatch/database/service.py index 349faf03720f..f1a663dfcdcc 100644 --- a/src/dispatch/database/service.py +++ b/src/dispatch/database/service.py @@ -4,7 +4,6 @@ from collections.abc import Iterable from inspect import signature from itertools import chain -from typing import Annotated from fastapi import Depends, Query from pydantic import StringConstraints diff --git a/src/dispatch/decorators.py b/src/dispatch/decorators.py index 13b5524db0f9..8b88e6b45bec 100644 --- a/src/dispatch/decorators.py +++ b/src/dispatch/decorators.py @@ -2,7 +2,6 @@ import logging import time from functools import wraps -from typing import Any, Callable, List from sqlalchemy.orm import scoped_session @@ -21,7 +20,7 @@ def fullname(o): def _execute_task_in_project_context( - func: Callable, + func, *args, **kwargs, ) -> None: @@ -68,7 +67,7 @@ def _execute_task_in_project_context( CoreSession.remove() -def scheduled_project_task(func: Callable): +def scheduled_project_task(func): """Decorator that sets up a background task function with a database session and exception tracking. @@ -134,7 +133,7 @@ def wrapper(*args, **kwargs): return wrapper -def timer(func: Any): +def timer(func): """Timing decorator that sends a timing metric.""" @wraps(func) @@ -151,7 +150,7 @@ def wrapper(*args, **kwargs): return wrapper -def counter(func: Any): +def counter(func): """Counting decorator that sends a counting metric.""" @wraps(func) @@ -162,7 +161,7 @@ def wrapper(*args, **kwargs): return wrapper -def apply(decorator: Any, exclude: List[str] = None): +def apply(decorator, exclude: list[str] = None): """Class decorator that applies specified decorator to all class methods.""" if not exclude: exclude = [] diff --git a/src/dispatch/definition/models.py b/src/dispatch/definition/models.py index af3d6a3902c5..c4043ce71ae2 100644 --- a/src/dispatch/definition/models.py +++ b/src/dispatch/definition/models.py @@ -1,4 +1,3 @@ -from typing import List, Optional from pydantic import Field from sqlalchemy import Table, Column, Integer, String, ForeignKey, PrimaryKeyConstraint @@ -45,29 +44,29 @@ class Definition(Base, ProjectMixin): class DefinitionTerm(DispatchBase): - id: Optional[PrimaryKey] - text: Optional[str] + id: PrimaryKey | None + text: str | None # Pydantic models... class DefinitionBase(DispatchBase): text: str - source: Optional[str] = Field(None, nullable=True) + source: str | None = Field(None, nullable=True) class DefinitionCreate(DefinitionBase): - terms: Optional[List[DefinitionTerm]] = [] + terms: list[DefinitionTerm | None] = [] project: ProjectRead class DefinitionUpdate(DefinitionBase): - terms: Optional[List[DefinitionTerm]] = [] + terms: list[DefinitionTerm | None] = [] class DefinitionRead(DefinitionBase): id: PrimaryKey - terms: Optional[List[DefinitionTerm]] + terms: list[DefinitionTerm | None] class DefinitionPagination(Pagination): - items: List[DefinitionRead] = [] + items: list[DefinitionRead] = [] diff --git a/src/dispatch/definition/service.py b/src/dispatch/definition/service.py index 3588b69fc59c..958d10ac3dbb 100644 --- a/src/dispatch/definition/service.py +++ b/src/dispatch/definition/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from dispatch.project import service as project_service from dispatch.term import service as term_service @@ -6,17 +5,17 @@ from .models import Definition, DefinitionCreate, DefinitionUpdate -def get(*, db_session, definition_id: int) -> Optional[Definition]: +def get(*, db_session, definition_id: int) -> Definition | None: """Gets a definition by its id.""" return db_session.query(Definition).filter(Definition.id == definition_id).first() -def get_by_text(*, db_session, text: str) -> Optional[Definition]: +def get_by_text(*, db_session, text: str) -> Definition | None: """Gets a definition by its text.""" return db_session.query(Definition).filter(Definition.text == text).first() -def get_all(*, db_session) -> List[Optional[Definition]]: +def get_all(*, db_session) -> list[Definition | None]: """Gets all definitions.""" return db_session.query(Definition) @@ -38,7 +37,7 @@ def create(*, db_session, definition_in: DefinitionCreate) -> Definition: return definition -def create_all(*, db_session, definitions_in: List[DefinitionCreate]) -> List[Definition]: +def create_all(*, db_session, definitions_in: list[DefinitionCreate]) -> list[Definition]: """Creates a definitions in bulk.""" definitions = [Definition(text=d.text) for d in definitions_in] db_session.bulk_save_insert(definitions) diff --git a/src/dispatch/document/flows.py b/src/dispatch/document/flows.py index 4a6b3dd823f6..abf05c1ab185 100644 --- a/src/dispatch/document/flows.py +++ b/src/dispatch/document/flows.py @@ -1,4 +1,3 @@ -from typing import Any import logging from sqlalchemy.orm import Session diff --git a/src/dispatch/document/service.py b/src/dispatch/document/service.py index 41b499336269..acf48aa55a89 100644 --- a/src/dispatch/document/service.py +++ b/src/dispatch/document/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from pydantic.error_wrappers import ValidationError from datetime import datetime @@ -10,14 +9,14 @@ from .models import Document, DocumentCreate, DocumentUpdate -def get(*, db_session, document_id: int) -> Optional[Document]: +def get(*, db_session, document_id: int) -> Document | None: """Returns a document based on the given document id.""" return db_session.query(Document).filter(Document.id == document_id).one_or_none() def get_by_incident_id_and_resource_type( *, db_session, incident_id: int, project_id: int, resource_type: str -) -> Optional[Document]: +) -> Document | None: """Returns a document based on the given incident and id and document resource type.""" return ( db_session.query(Document) @@ -28,7 +27,7 @@ def get_by_incident_id_and_resource_type( ) -def get_project_forms_export_template(*, db_session, project_id: int) -> Optional[Document]: +def get_project_forms_export_template(*, db_session, project_id: int) -> Document | None: """Fetches the project forms export template.""" resource_type = DocumentResourceTemplateTypes.forms return ( @@ -59,7 +58,7 @@ def get_conversation_reference_document(*, db_session, project_id: int): ).one_or_none() -def get_overdue_evergreen_documents(*, db_session, project_id: int) -> List[Optional[Document]]: +def get_overdue_evergreen_documents(*, db_session, project_id: int) -> list[Document | None]: """Returns all documents that have not had a recent evergreen notification.""" query = ( db_session.query(Document) @@ -70,7 +69,7 @@ def get_overdue_evergreen_documents(*, db_session, project_id: int) -> List[Opti return query.all() -def get_all(*, db_session) -> List[Optional[Document]]: +def get_all(*, db_session) -> list[Document | None]: """Returns all documents.""" return db_session.query(Document) diff --git a/src/dispatch/email_templates/models.py b/src/dispatch/email_templates/models.py index 5982676979b9..f8dcaef13814 100644 --- a/src/dispatch/email_templates/models.py +++ b/src/dispatch/email_templates/models.py @@ -1,6 +1,5 @@ from datetime import datetime from pydantic import Field -from typing import Optional, List from sqlalchemy import Column, Integer, String, Boolean, UniqueConstraint @@ -22,15 +21,15 @@ class EmailTemplates(TimeStampMixin, ProjectMixin, Base): # Pydantic models class EmailTemplatesBase(DispatchBase): - email_template_type: Optional[str] = Field(None, nullable=True) - welcome_text: Optional[str] = Field(None, nullable=True) - welcome_body: Optional[str] = Field(None, nullable=True) - components: Optional[str] = Field(None, nullable=True) - enabled: Optional[bool] + email_template_type: str | None = Field(None, nullable=True) + welcome_text: str | None = Field(None, nullable=True) + welcome_body: str | None = Field(None, nullable=True) + components: str | None = Field(None, nullable=True) + enabled: bool | None class EmailTemplatesCreate(EmailTemplatesBase): - project: Optional[ProjectRead] + project: ProjectRead | None class EmailTemplatesUpdate(EmailTemplatesBase): @@ -39,11 +38,11 @@ class EmailTemplatesUpdate(EmailTemplatesBase): class EmailTemplatesRead(EmailTemplatesBase): id: PrimaryKey - project: Optional[ProjectRead] - created_at: Optional[datetime] = None - updated_at: Optional[datetime] = None + project: ProjectRead | None + created_at: datetime | None = None + updated_at: datetime | None = None class EmailTemplatesPagination(Pagination): - items: List[EmailTemplatesRead] + items: list[EmailTemplatesRead] total: int diff --git a/src/dispatch/email_templates/service.py b/src/dispatch/email_templates/service.py index 22a1f2208cf4..be97cd2d499b 100644 --- a/src/dispatch/email_templates/service.py +++ b/src/dispatch/email_templates/service.py @@ -1,5 +1,4 @@ import logging -from typing import List, Optional from sqlalchemy.orm import Session @@ -9,7 +8,7 @@ log = logging.getLogger(__name__) -def get(*, email_template_id: int, db_session: Session) -> Optional[EmailTemplates]: +def get(*, email_template_id: int, db_session: Session) -> EmailTemplates | None: """Gets an email template by its id.""" return ( db_session.query(EmailTemplates) @@ -20,7 +19,7 @@ def get(*, email_template_id: int, db_session: Session) -> Optional[EmailTemplat def get_by_type( *, email_template_type: str, project_id: int, db_session: Session -) -> Optional[EmailTemplates]: +) -> EmailTemplates | None: """Gets an email template by its type.""" return ( db_session.query(EmailTemplates) @@ -31,7 +30,7 @@ def get_by_type( ) -def get_all(*, db_session: Session) -> List[Optional[EmailTemplates]]: +def get_all(*, db_session: Session) -> list[EmailTemplates | None]: """Gets all email templates.""" return db_session.query(EmailTemplates) diff --git a/src/dispatch/entity/models.py b/src/dispatch/entity/models.py index 8e6deef99f44..4d0aeb50e5cf 100644 --- a/src/dispatch/entity/models.py +++ b/src/dispatch/entity/models.py @@ -1,4 +1,3 @@ -from typing import Optional, List from pydantic import Field from sqlalchemy import Column, Integer, String, ForeignKey @@ -50,40 +49,40 @@ class Entity(Base, TimeStampMixin, ProjectMixin): # Pydantic models class EntityBase(DispatchBase): - name: Optional[str] = Field(None, nullable=True) - source: Optional[str] = Field(None, nullable=True) - value: Optional[str] = Field(None, nullable=True) - description: Optional[str] = Field(None, nullable=True) + name: str | None = Field(None, nullable=True) + source: str | None = Field(None, nullable=True) + value: str | None = Field(None, nullable=True) + description: str | None = Field(None, nullable=True) class EntityCreate(EntityBase): def __hash__(self): return hash((self.id, self.value)) - id: Optional[PrimaryKey] + id: PrimaryKey | None entity_type: EntityTypeCreate project: ProjectRead class EntityUpdate(EntityBase): - id: Optional[PrimaryKey] - entity_type: Optional[EntityTypeUpdate] + id: PrimaryKey | None + entity_type: EntityTypeUpdate | None class EntityRead(EntityBase): id: PrimaryKey - entity_type: Optional[EntityTypeRead] + entity_type: EntityTypeRead | None project: ProjectRead class EntityReadMinimal(DispatchBase): id: PrimaryKey - name: Optional[str] = Field(None, nullable=True) - source: Optional[str] = Field(None, nullable=True) - value: Optional[str] = Field(None, nullable=True) - description: Optional[str] = Field(None, nullable=True) - entity_type: Optional[EntityTypeReadMinimal] + name: str | None = Field(None, nullable=True) + source: str | None = Field(None, nullable=True) + value: str | None = Field(None, nullable=True) + description: str | None = Field(None, nullable=True) + entity_type: EntityTypeReadMinimal | None class EntityPagination(Pagination): - items: List[EntityRead] + items: list[EntityRead] diff --git a/src/dispatch/entity/service.py b/src/dispatch/entity/service.py index c15ba3e70c48..6178d1d39d4e 100644 --- a/src/dispatch/entity/service.py +++ b/src/dispatch/entity/service.py @@ -1,7 +1,7 @@ from datetime import datetime, timedelta import logging -from typing import Generator, Optional, Sequence, Union, NewType, NamedTuple import re +from collections.abc import Generator, Sequence import jsonpath_ng from pydantic import ValidationError @@ -19,12 +19,12 @@ log = logging.getLogger(__name__) -def get(*, db_session: Session, entity_id: int) -> Optional[Entity]: +def get(*, db_session: Session, entity_id: int) -> Entity | None: """Gets a entity by its id.""" return db_session.query(Entity).filter(Entity.id == entity_id).one_or_none() -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[Entity]: +def get_by_name(*, db_session, project_id: int, name: str) -> Entity | None: """Gets a entity by its project and name.""" return ( db_session.query(Entity) @@ -56,7 +56,7 @@ def get_by_name_or_raise( return entity -def get_by_value(*, db_session: Session, project_id: int, value: str) -> Optional[Entity]: +def get_by_value(*, db_session: Session, project_id: int, value: str) -> Entity | None: """Gets a entity by its value.""" return ( db_session.query(Entity) @@ -244,16 +244,13 @@ def get_signal_instances_with_entities( return signal_instances -EntityTypePair = NewType( - "EntityTypePair", - NamedTuple( - "EntityTypePairTuple", - [ - ("entity_type", EntityType), - ("regex", Union[re.Pattern[str], None]), - ("json_path", Union[jsonpath_ng.JSONPath, None]), - ], - ), +EntityTypePair = NamedTuple( + "EntityTypePairTuple", + [ + ("entity_type", EntityType), + ("regex", re.Pattern[str] | None), + ("json_path", jsonpath_ng.JSONPath | None), + ], ) diff --git a/src/dispatch/entity_type/models.py b/src/dispatch/entity_type/models.py index d57012e79492..8a338239206f 100644 --- a/src/dispatch/entity_type/models.py +++ b/src/dispatch/entity_type/models.py @@ -1,4 +1,3 @@ -from typing import List, Optional from pydantic import Field from sqlalchemy import Column, Integer, String @@ -49,23 +48,23 @@ class SignalRead(DispatchBase): id: PrimaryKey name: str owner: str - conversation_target: Optional[str] - description: Optional[str] - variant: Optional[str] + conversation_target: str | None + description: str | None + variant: str | None class EntityTypeBase(DispatchBase): - name: Optional[NameStr] - description: Optional[str] = Field(None, nullable=True) - jpath: Optional[str] = Field(None, nullable=True) - scope: Optional[EntityScopeEnum] = Field(EntityScopeEnum.single, nullable=False) - enabled: Optional[bool] - signals: Optional[List[SignalRead]] = Field([], nullable=True) - regular_expression: Optional[str] = Field(None, nullable=True) + name: NameStr | None + description: str | None = Field(None, nullable=True) + jpath: str | None = Field(None, nullable=True) + scope: EntityScopeEnum | None = Field(EntityScopeEnum.single, nullable=False) + enabled: bool | None + signals: list[SignalRead | None] = Field([], nullable=True) + regular_expression: str | None = Field(None, nullable=True) class EntityTypeCreate(EntityTypeBase): - id: Optional[PrimaryKey] + id: PrimaryKey | None project: ProjectRead @@ -81,11 +80,11 @@ class EntityTypeRead(EntityTypeBase): class EntityTypeReadMinimal(DispatchBase): id: PrimaryKey name: NameStr - description: Optional[str] = Field(None, nullable=True) + description: str | None = Field(None, nullable=True) scope: EntityScopeEnum - enabled: Optional[bool] - regular_expression: Optional[str] = Field(None, nullable=True) + enabled: bool | None + regular_expression: str | None = Field(None, nullable=True) class EntityTypePagination(Pagination): - items: List[EntityTypeRead] + items: list[EntityTypeRead] diff --git a/src/dispatch/entity_type/service.py b/src/dispatch/entity_type/service.py index 6ae6e678c081..219c48861337 100644 --- a/src/dispatch/entity_type/service.py +++ b/src/dispatch/entity_type/service.py @@ -1,5 +1,4 @@ import logging -from typing import Optional from pydantic import ValidationError from sqlalchemy.orm import Query, Session @@ -11,12 +10,12 @@ logger = logging.getLogger(__name__) -def get(*, db_session, entity_type_id: int) -> Optional[EntityType]: +def get(*, db_session, entity_type_id: int) -> EntityType | None: """Gets a entity type by its id.""" return db_session.query(EntityType).filter(EntityType.id == entity_type_id).one_or_none() -def get_by_name(*, db_session: Session, project_id: int, name: str) -> Optional[EntityType]: +def get_by_name(*, db_session: Session, project_id: int, name: str) -> EntityType | None: """Gets a entity type by its name.""" return ( db_session.query(EntityType) diff --git a/src/dispatch/entity_type/views.py b/src/dispatch/entity_type/views.py index eb231832862c..162600fbf88c 100644 --- a/src/dispatch/entity_type/views.py +++ b/src/dispatch/entity_type/views.py @@ -1,4 +1,3 @@ -from typing import List from fastapi import APIRouter, HTTPException, status from pydantic import ValidationError @@ -76,7 +75,7 @@ def create_entity_type_with_case( return entity_type -@router.put("/recalculate/{entity_type_id}/{case_id}", response_model=List[SignalInstanceRead]) +@router.put("/recalculate/{entity_type_id}/{case_id}", response_model=list[SignalInstanceRead]) def recalculate(db_session: DbSession, entity_type_id: PrimaryKey, case_id: PrimaryKey): """Recalculates the associated entities for all signal instances in a case.""" entity_type = get( diff --git a/src/dispatch/event/models.py b/src/dispatch/event/models.py index 6c8551062ffb..33c5bf6f44fa 100644 --- a/src/dispatch/event/models.py +++ b/src/dispatch/event/models.py @@ -1,7 +1,6 @@ from datetime import datetime from uuid import UUID -from typing import Optional from sqlalchemy import Column, DateTime, ForeignKey, Integer, String, Boolean from sqlalchemy.dialects.postgresql import UUID as SQLAlchemyUUID @@ -49,10 +48,10 @@ class EventBase(DispatchBase): ended_at: datetime source: str description: str - details: Optional[dict] = None - type: Optional[str] = None - owner: Optional[str] = None - pinned: Optional[bool] = False + details: dict | None = None + type: str | None = None + owner: str | None = None + pinned: bool | None = False class EventCreate(EventBase): @@ -72,6 +71,6 @@ class EventCreateMinimal(DispatchBase): source: str description: str details: dict - type: Optional[str] = None - owner: Optional[str] = None - pinned: Optional[bool] = False + type: str | None = None + owner: str | None = None + pinned: bool | None = False diff --git a/src/dispatch/event/service.py b/src/dispatch/event/service.py index 89cd91a76548..aa1d7852843a 100644 --- a/src/dispatch/event/service.py +++ b/src/dispatch/event/service.py @@ -1,4 +1,3 @@ -from typing import Optional from uuid import uuid4 from datetime import datetime import logging @@ -21,7 +20,7 @@ log = logging.getLogger(__name__) -def get(*, db_session, event_id: int) -> Optional[Event]: +def get(*, db_session, event_id: int) -> Event | None: """Get an event by id.""" return ( db_session.query(Event) @@ -44,7 +43,7 @@ def get_by_incident_id(*, db_session, incident_id: int) -> list[Event | None]: ) -def get_by_uuid(*, db_session, uuid: str) -> list[Event | None]: +def get_by_uuid(*, db_session, uuid: str) -> Event | None: """Get events by uuid.""" return db_session.query(Event).filter(Event.uuid == uuid).one_or_none() diff --git a/src/dispatch/evergreen/scheduled.py b/src/dispatch/evergreen/scheduled.py index fadb7ecb1baa..3b1ae4255309 100644 --- a/src/dispatch/evergreen/scheduled.py +++ b/src/dispatch/evergreen/scheduled.py @@ -10,7 +10,6 @@ from collections import defaultdict from datetime import datetime from schedule import every -from typing import Any from sqlalchemy.orm import Session diff --git a/src/dispatch/feedback/incident/messaging.py b/src/dispatch/feedback/incident/messaging.py index 470189ea62cc..d663236044ee 100644 --- a/src/dispatch/feedback/incident/messaging.py +++ b/src/dispatch/feedback/incident/messaging.py @@ -1,5 +1,4 @@ import logging -from typing import List from sqlalchemy.orm import Session @@ -17,7 +16,7 @@ def send_incident_feedback_daily_report( - commander_email: str, feedback: List[Feedback], project_id: int, db_session: Session + commander_email: str, feedback: list[Feedback], project_id: int, db_session: Session ): """Sends an incident feedback daily report to all incident commanders who received feedback.""" plugin = plugin_service.get_active_instance( @@ -67,7 +66,7 @@ def send_incident_feedback_daily_report( def send_case_feedback_daily_report( - assignee_email: str, feedback: List[Feedback], project_id: int, db_session: Session + assignee_email: str, feedback: list[Feedback], project_id: int, db_session: Session ): """Sends an case feedback daily report to all case assignees who received feedback.""" plugin = plugin_service.get_active_instance( diff --git a/src/dispatch/feedback/incident/models.py b/src/dispatch/feedback/incident/models.py index 0066c5809390..9f56f415415b 100644 --- a/src/dispatch/feedback/incident/models.py +++ b/src/dispatch/feedback/incident/models.py @@ -1,6 +1,5 @@ from datetime import datetime from pydantic import Field -from typing import Optional, List from sqlalchemy import Column, Integer, ForeignKey from sqlalchemy_utils import TSVectorType @@ -42,12 +41,12 @@ class Feedback(TimeStampMixin, FeedbackMixin, ProjectMixin, Base): # Pydantic models class FeedbackBase(DispatchBase): - created_at: Optional[datetime] = None + created_at: datetime | None = None rating: FeedbackRating = FeedbackRating.very_satisfied - feedback: Optional[str] = Field(None, nullable=True) - incident: Optional[IncidentReadBasic] = None - case: Optional[CaseReadMinimal] = None - participant: Optional[ParticipantRead] = None + feedback: str | None = Field(None, nullable=True) + incident: IncidentReadBasic | None = None + case: CaseReadMinimal | None = None + participant: ParticipantRead | None = None class FeedbackCreate(FeedbackBase): @@ -60,8 +59,8 @@ class FeedbackUpdate(FeedbackBase): class FeedbackRead(FeedbackBase): id: PrimaryKey - project: Optional[ProjectRead] + project: ProjectRead | None class FeedbackPagination(Pagination): - items: List[FeedbackRead] + items: list[FeedbackRead] diff --git a/src/dispatch/feedback/incident/service.py b/src/dispatch/feedback/incident/service.py index af7128dd072a..8d8d45d8c8c9 100644 --- a/src/dispatch/feedback/incident/service.py +++ b/src/dispatch/feedback/incident/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from datetime import datetime, timedelta from dispatch.incident import service as incident_service @@ -10,7 +9,7 @@ from .models import Feedback, FeedbackCreate, FeedbackUpdate -def get(*, db_session, feedback_id: int) -> Optional[Feedback]: +def get(*, db_session, feedback_id: int) -> Feedback | None: """Gets a piece of feedback by its id.""" return db_session.query(Feedback).filter(Feedback.id == feedback_id).one_or_none() @@ -22,7 +21,7 @@ def get_all(*, db_session): def get_all_incident_last_x_hours_by_project_id( *, db_session, hours: int = 24, project_id: int -) -> List[Optional[Feedback]]: +) -> list[Feedback | None]: """Returns all feedback provided in the last x hours by project id. Defaults to 24 hours.""" return ( db_session.query(Feedback) @@ -36,7 +35,7 @@ def get_all_incident_last_x_hours_by_project_id( def get_all_case_last_x_hours_by_project_id( *, db_session, hours: int = 24, project_id: int -) -> List[Optional[Feedback]]: +) -> list[Feedback | None]: """Returns all feedback provided in the last x hours by project id. Defaults to 24 hours.""" return ( db_session.query(Feedback) diff --git a/src/dispatch/feedback/service/messaging.py b/src/dispatch/feedback/service/messaging.py index 57e69012642d..20e1d1481e8e 100644 --- a/src/dispatch/feedback/service/messaging.py +++ b/src/dispatch/feedback/service/messaging.py @@ -1,6 +1,5 @@ import logging from datetime import datetime, timedelta -from typing import Optional, List from sqlalchemy.orm import Session @@ -25,8 +24,8 @@ def send_oncall_shift_feedback_message( service_id: str, shift_end_at: str, schedule_name: str, - reminder: Optional[ServiceFeedbackReminder] = None, - details: Optional[List[dict]] = None, + reminder: ServiceFeedbackReminder | None = None, + details: list[dict | None] = None, db_session: Session, ): """ diff --git a/src/dispatch/feedback/service/models.py b/src/dispatch/feedback/service/models.py index a6fd32b145ce..c18b8e9b822f 100644 --- a/src/dispatch/feedback/service/models.py +++ b/src/dispatch/feedback/service/models.py @@ -1,6 +1,5 @@ from datetime import datetime from pydantic import Field -from typing import Optional, List from sqlalchemy import Column, Integer, ForeignKey, DateTime, String, Numeric, JSON from sqlalchemy_utils import TSVectorType @@ -40,16 +39,16 @@ class ServiceFeedback(TimeStampMixin, FeedbackMixin, Base): # Pydantic models class ServiceFeedbackBase(DispatchBase): - feedback: Optional[str] = Field(None, nullable=True) - hours: Optional[float] - individual: Optional[IndividualContactReadMinimal] + feedback: str | None = Field(None, nullable=True) + hours: float | None + individual: IndividualContactReadMinimal | None rating: ServiceFeedbackRating = ServiceFeedbackRating.little_effort - schedule: Optional[str] - shift_end_at: Optional[datetime] - shift_start_at: Optional[datetime] - project: Optional[ProjectRead] - created_at: Optional[datetime] - details: Optional[List[dict]] = Field([], nullable=True) + schedule: str | None + shift_end_at: datetime | None + shift_start_at: datetime | None + project: ProjectRead | None + created_at: datetime | None + details: list[dict | None] = Field([], nullable=True) class ServiceFeedbackCreate(ServiceFeedbackBase): @@ -62,9 +61,9 @@ class ServiceFeedbackUpdate(ServiceFeedbackBase): class ServiceFeedbackRead(ServiceFeedbackBase): id: PrimaryKey - project: Optional[ProjectRead] + project: ProjectRead | None class ServiceFeedbackPagination(Pagination): - items: List[ServiceFeedbackRead] + items: list[ServiceFeedbackRead] total: int diff --git a/src/dispatch/feedback/service/reminder/models.py b/src/dispatch/feedback/service/reminder/models.py index a1c81b6070e5..9f14ed7ad8b3 100644 --- a/src/dispatch/feedback/service/reminder/models.py +++ b/src/dispatch/feedback/service/reminder/models.py @@ -1,6 +1,5 @@ from datetime import datetime from pydantic import Field -from typing import Optional, List from sqlalchemy import Column, Integer, ForeignKey, DateTime, String, JSON @@ -26,13 +25,13 @@ class ServiceFeedbackReminder(TimeStampMixin, Base): # Pydantic models class ServiceFeedbackReminderBase(DispatchBase): - reminder_at: Optional[datetime] - individual: Optional[IndividualContactRead] - project: Optional[ProjectRead] - schedule_id: Optional[str] - schedule_name: Optional[str] - shift_end_at: Optional[datetime] - details: Optional[List[dict]] = Field([], nullable=True) + reminder_at: datetime | None + individual: IndividualContactRead | None + project: ProjectRead | None + schedule_id: str | None + schedule_name: str | None + shift_end_at: datetime | None + details: list[dict | None] = Field([], nullable=True) class ServiceFeedbackReminderCreate(ServiceFeedbackReminderBase): @@ -41,7 +40,7 @@ class ServiceFeedbackReminderCreate(ServiceFeedbackReminderBase): class ServiceFeedbackReminderUpdate(ServiceFeedbackReminderBase): id: PrimaryKey = None - reminder_at: Optional[datetime] + reminder_at: datetime | None class ServiceFeedbackReminderRead(ServiceFeedbackReminderBase): diff --git a/src/dispatch/feedback/service/reminder/service.py b/src/dispatch/feedback/service/reminder/service.py index 1944d1a00e87..058278b3ac7f 100644 --- a/src/dispatch/feedback/service/reminder/service.py +++ b/src/dispatch/feedback/service/reminder/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from datetime import datetime, timedelta from .models import ( @@ -11,7 +10,7 @@ def get_all_expired_reminders_by_project_id( *, db_session, project_id: int -) -> List[Optional[ServiceFeedbackReminder]]: +) -> list[ServiceFeedbackReminder | None]: """Returns all expired reminders by project id.""" return ( db_session.query(ServiceFeedbackReminder) diff --git a/src/dispatch/feedback/service/service.py b/src/dispatch/feedback/service/service.py index 46a7845d082f..75b0c7f2794d 100644 --- a/src/dispatch/feedback/service/service.py +++ b/src/dispatch/feedback/service/service.py @@ -1,11 +1,10 @@ -from typing import Optional from sqlalchemy.orm import Session from .models import ServiceFeedback, ServiceFeedbackCreate, ServiceFeedbackUpdate -def get(*, service_feedback_id: int, db_session: Session) -> Optional[ServiceFeedback]: +def get(*, service_feedback_id: int, db_session: Session) -> ServiceFeedback | None: """Gets a piece of service feedback by its id.""" return ( db_session.query(ServiceFeedback) diff --git a/src/dispatch/forms/models.py b/src/dispatch/forms/models.py index 435c76a7d4e2..8fb35069d7e4 100644 --- a/src/dispatch/forms/models.py +++ b/src/dispatch/forms/models.py @@ -1,6 +1,5 @@ from datetime import datetime from pydantic import Field -from typing import Optional, List from sqlalchemy import Column, Integer, ForeignKey, String from sqlalchemy.orm import relationship @@ -39,17 +38,17 @@ class Forms(TimeStampMixin, ProjectMixin, Base): # Pydantic models class FormsBase(DispatchBase): - form_type: Optional[FormsTypeRead] - creator: Optional[IndividualContactReadMinimal] - form_data: Optional[str] = Field(None, nullable=True) - attorney_form_data: Optional[str] = Field(None, nullable=True) - status: Optional[str] = Field(None, nullable=True) - attorney_status: Optional[str] = Field(None, nullable=True) - project: Optional[ProjectRead] - incident: Optional[IncidentReadBasic] - attorney_questions: Optional[str] = Field(None, nullable=True) - attorney_analysis: Optional[str] = Field(None, nullable=True) - score: Optional[int] + form_type: FormsTypeRead | None + creator: IndividualContactReadMinimal | None + form_data: str | None = Field(None, nullable=True) + attorney_form_data: str | None = Field(None, nullable=True) + status: str | None = Field(None, nullable=True) + attorney_status: str | None = Field(None, nullable=True) + project: ProjectRead | None + incident: IncidentReadBasic | None + attorney_questions: str | None = Field(None, nullable=True) + attorney_analysis: str | None = Field(None, nullable=True) + score: int | None class FormsCreate(FormsBase): @@ -62,11 +61,11 @@ class FormsUpdate(FormsBase): class FormsRead(FormsBase): id: PrimaryKey - project: Optional[ProjectRead] - created_at: Optional[datetime] = None - updated_at: Optional[datetime] = None + project: ProjectRead | None + created_at: datetime | None = None + updated_at: datetime | None = None class FormsPagination(Pagination): - items: List[FormsRead] + items: list[FormsRead] total: int diff --git a/src/dispatch/forms/service.py b/src/dispatch/forms/service.py index cb5f8e3d2887..a71f68cd6266 100644 --- a/src/dispatch/forms/service.py +++ b/src/dispatch/forms/service.py @@ -1,6 +1,5 @@ import logging import json -from typing import List, Optional from datetime import datetime from sqlalchemy.orm import Session @@ -17,7 +16,7 @@ log = logging.getLogger(__name__) -def get(*, forms_id: int, db_session: Session) -> Optional[Forms]: +def get(*, forms_id: int, db_session: Session) -> Forms | None: """Gets a from by its id.""" return db_session.query(Forms).filter(Forms.id == forms_id).one_or_none() @@ -97,7 +96,7 @@ def build_form_doc(form_schema: str, form_data: str) -> str: return "\n".join(output_qa) -def export(*, db_session: Session, ids: List[int]) -> List[str]: +def export(*, db_session: Session, ids: list[int]) -> list[str]: """Exports forms.""" folders = [] # get all the forms given the ids diff --git a/src/dispatch/forms/type/models.py b/src/dispatch/forms/type/models.py index 9712633e894c..1e6ab699bb9e 100644 --- a/src/dispatch/forms/type/models.py +++ b/src/dispatch/forms/type/models.py @@ -1,6 +1,5 @@ from datetime import datetime from pydantic import Field -from typing import List, Optional from sqlalchemy import Boolean, Column, Integer, ForeignKey, String from sqlalchemy.sql.schema import UniqueConstraint @@ -41,14 +40,14 @@ class FormsType(ProjectMixin, TimeStampMixin, Base): # Pydantic models class FormsTypeBase(DispatchBase): name: NameStr - description: Optional[str] = Field(None, nullable=True) - enabled: Optional[bool] - form_schema: Optional[str] = Field(None, nullable=True) - attorney_form_schema: Optional[str] = Field(None, nullable=True) - scoring_schema: Optional[str] = Field(None, nullable=True) - creator: Optional[IndividualContactReadMinimal] - project: Optional[ProjectRead] - service: Optional[ServiceRead] + description: str | None = Field(None, nullable=True) + enabled: bool | None + form_schema: str | None = Field(None, nullable=True) + attorney_form_schema: str | None = Field(None, nullable=True) + scoring_schema: str | None = Field(None, nullable=True) + creator: IndividualContactReadMinimal | None + project: ProjectRead | None + service: ServiceRead | None class FormsTypeCreate(FormsTypeBase): @@ -61,9 +60,9 @@ class FormsTypeUpdate(FormsTypeBase): class FormsTypeRead(FormsTypeBase): id: PrimaryKey - created_at: Optional[datetime] = None - updated_at: Optional[datetime] = None + created_at: datetime | None = None + updated_at: datetime | None = None class FormsTypePagination(Pagination): - items: List[FormsTypeRead] = [] + items: list[FormsTypeRead] = [] diff --git a/src/dispatch/forms/type/service.py b/src/dispatch/forms/type/service.py index cc5fe7432a36..c84bb15ebd3e 100644 --- a/src/dispatch/forms/type/service.py +++ b/src/dispatch/forms/type/service.py @@ -1,5 +1,4 @@ import logging -from typing import Optional from sqlalchemy.orm import Session @@ -15,7 +14,7 @@ log = logging.getLogger(__name__) -def get(*, forms_type_id: int, db_session: Session) -> Optional[FormsType]: +def get(*, forms_type_id: int, db_session: Session) -> FormsType | None: """Gets a from type by its id.""" return db_session.query(FormsType).filter(FormsType.id == forms_type_id).one_or_none() diff --git a/src/dispatch/forms/views.py b/src/dispatch/forms/views.py index d8c51dc579d0..f1dbd528b5a7 100644 --- a/src/dispatch/forms/views.py +++ b/src/dispatch/forms/views.py @@ -1,7 +1,6 @@ import logging from fastapi import APIRouter, HTTPException, status, Depends, Response from pydantic import ValidationError -from typing import List from sqlalchemy.exc import IntegrityError @@ -84,7 +83,7 @@ def create_forms( ) def export_forms( db_session: DbSession, - ids: List[int], + ids: list[int], ): """Exports forms.""" return export(db_session=db_session, ids=ids) diff --git a/src/dispatch/group/flows.py b/src/dispatch/group/flows.py index 3f8cd7dbe316..eaedb2fe2b58 100644 --- a/src/dispatch/group/flows.py +++ b/src/dispatch/group/flows.py @@ -1,4 +1,3 @@ -from typing import List, TypeVar import logging from sqlalchemy.orm import Session @@ -19,7 +18,7 @@ def create_group( - subject: Subject, group_type: str, group_participants: List[str], db_session: Session + subject: Subject, group_type: str, group_participants: list[str], db_session: Session ): """Creates a group.""" plugin = plugin_service.get_active_instance( diff --git a/src/dispatch/group/service.py b/src/dispatch/group/service.py index f5707c2ae097..be889044bc3f 100644 --- a/src/dispatch/group/service.py +++ b/src/dispatch/group/service.py @@ -1,16 +1,15 @@ -from typing import Optional from .models import Group, GroupCreate, GroupUpdate -def get(*, db_session, group_id: int) -> Optional[Group]: +def get(*, db_session, group_id: int) -> Group | None: """Returns a group given a group id.""" return db_session.query(Group).filter(Group.id == group_id).one_or_none() def get_by_incident_id_and_resource_type( *, db_session, incident_id: str, resource_type: str -) -> Optional[Group]: +) -> Group | None: """Returns a group given an incident id and group resource type.""" return ( db_session.query(Group) diff --git a/src/dispatch/incident/flows.py b/src/dispatch/incident/flows.py index 5ce81b47563a..b34323d90fe1 100644 --- a/src/dispatch/incident/flows.py +++ b/src/dispatch/incident/flows.py @@ -1,6 +1,5 @@ import logging from datetime import datetime -from typing import Optional from sqlalchemy.orm import Session @@ -446,7 +445,7 @@ def incident_active_status_flow(incident: Incident, db_session=None): conversation_flows.unarchive_conversation(subject=incident, db_session=db_session) -def create_incident_review_document(incident: Incident, db_session=None) -> Optional[Document]: +def create_incident_review_document(incident: Incident, db_session=None) -> Document | None: # we create the post-incident review document document_flows.create_document( subject=incident, diff --git a/src/dispatch/incident/messaging.py b/src/dispatch/incident/messaging.py index a66d19f85bde..c6f4c2b541de 100644 --- a/src/dispatch/incident/messaging.py +++ b/src/dispatch/incident/messaging.py @@ -6,7 +6,6 @@ """ import logging -from typing import Optional from slack_sdk.errors import SlackApiError from sqlalchemy.orm import Session @@ -83,7 +82,7 @@ def send_welcome_ephemeral_message_to_participant( participant_email: str, incident: Incident, db_session: Session, - welcome_template: Optional[EmailTemplates] = None, + welcome_template: EmailTemplates | None = None, ): """Sends an ephemeral welcome message to the participant.""" if not incident.conversation: @@ -164,7 +163,7 @@ def send_welcome_email_to_participant( participant_email: str, incident: Incident, db_session: Session, - welcome_template: Optional[EmailTemplates] = None, + welcome_template: EmailTemplates | None = None, ): """Sends a welcome email to the participant.""" # we load the incident instance diff --git a/src/dispatch/incident/metrics.py b/src/dispatch/incident/metrics.py index 36bf4a9716ab..afdec49f2380 100644 --- a/src/dispatch/incident/metrics.py +++ b/src/dispatch/incident/metrics.py @@ -4,7 +4,6 @@ from calendar import monthrange from datetime import date from itertools import groupby -from typing import List import pandas as pd from sqlalchemy import and_ @@ -32,7 +31,7 @@ def create_incident_metric_query( db_session, end_date: date, start_date: date = None, - filter_spec: List[dict] | str | None = None, + filter_spec: list[dict] | str | None = None, ): """Fetches eligible incidents.""" query = db_session.query(Incident) @@ -55,7 +54,7 @@ def create_incident_metric_query( return query.all() -def make_forecast(incidents: List[Incident]): +def make_forecast(incidents: list[Incident]): """Makes an incident forecast.""" incidents_sorted = sorted(incidents, key=month_grouper) diff --git a/src/dispatch/incident/priority/service.py b/src/dispatch/incident/priority/service.py index 4c03c0635dc7..b012fe582e97 100644 --- a/src/dispatch/incident/priority/service.py +++ b/src/dispatch/incident/priority/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from pydantic import ValidationError from sqlalchemy.sql.expression import true @@ -13,7 +12,7 @@ ) -def get(*, db_session, incident_priority_id: int) -> Optional[IncidentPriority]: +def get(*, db_session, incident_priority_id: int) -> IncidentPriority | None: """Returns an incident priority based on the given priority id.""" return ( db_session.query(IncidentPriority) @@ -46,7 +45,7 @@ def get_default_or_raise(*, db_session, project_id: int) -> IncidentPriority: return incident_priority -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[IncidentPriority]: +def get_by_name(*, db_session, project_id: int, name: str) -> IncidentPriority | None: """Returns an incident priority based on the given priority name.""" return ( db_session.query(IncidentPriority) @@ -90,14 +89,14 @@ def get_by_name_or_default( return get_default_or_raise(db_session=db_session, project_id=project_id) -def get_all(*, db_session, project_id: int = None) -> List[Optional[IncidentPriority]]: +def get_all(*, db_session, project_id: int = None) -> list[IncidentPriority | None]: """Returns all incident priorities.""" if project_id: return db_session.query(IncidentPriority).filter(IncidentPriority.project_id == project_id) return db_session.query(IncidentPriority) -def get_all_enabled(*, db_session, project_id: int = None) -> List[Optional[IncidentPriority]]: +def get_all_enabled(*, db_session, project_id: int = None) -> list[IncidentPriority | None]: """Returns all enabled incident priorities.""" if project_id: return ( diff --git a/src/dispatch/incident/service.py b/src/dispatch/incident/service.py index e59c0a590d10..34c3c20189c3 100644 --- a/src/dispatch/incident/service.py +++ b/src/dispatch/incident/service.py @@ -7,7 +7,6 @@ import logging from datetime import datetime, timedelta -from typing import List, Optional from pydantic import ValidationError from sqlalchemy.orm import Session @@ -62,12 +61,12 @@ def resolve_and_associate_role(db_session: Session, incident: Incident, role: Pa @timer -def get(*, db_session: Session, incident_id: int) -> Optional[Incident]: +def get(*, db_session: Session, incident_id: int) -> Incident | None: """Returns an incident based on the given id.""" return db_session.query(Incident).filter(Incident.id == incident_id).first() -def get_by_name(*, db_session: Session, project_id: int, name: str) -> Optional[Incident]: +def get_by_name(*, db_session: Session, project_id: int, name: str) -> Incident | None: """Returns an incident based on the given name.""" return ( db_session.query(Incident) @@ -79,7 +78,7 @@ def get_by_name(*, db_session: Session, project_id: int, name: str) -> Optional[ def get_all_open_by_incident_type( *, db_session: Session, incident_type_id: int -) -> List[Optional[Incident]]: +) -> list[Incident | None]: """Returns all non-closed incidents based on the given incident type.""" return ( db_session.query(Incident) @@ -105,14 +104,14 @@ def get_by_name_or_raise( return incident -def get_all(*, db_session: Session, project_id: int) -> List[Optional[Incident]]: +def get_all(*, db_session: Session, project_id: int) -> list[Incident | None]: """Returns all incidents.""" return db_session.query(Incident).filter(Incident.project_id == project_id) def get_all_by_status( *, db_session: Session, status: str, project_id: int -) -> List[Optional[Incident]]: +) -> list[Incident | None]: """Returns all incidents based on the given status.""" return ( db_session.query(Incident) @@ -122,7 +121,7 @@ def get_all_by_status( ) -def get_all_last_x_hours(*, db_session: Session, hours: int) -> List[Optional[Incident]]: +def get_all_last_x_hours(*, db_session: Session, hours: int) -> list[Incident | None]: """Returns all incidents in the last x hours.""" now = datetime.utcnow() return ( @@ -132,7 +131,7 @@ def get_all_last_x_hours(*, db_session: Session, hours: int) -> List[Optional[In def get_all_last_x_hours_by_status( *, db_session: Session, status: str, hours: int, project_id: int -) -> List[Optional[Incident]]: +) -> list[Incident | None]: """Returns all incidents of a given status in the last x hours.""" now = datetime.utcnow() diff --git a/src/dispatch/incident/severity/service.py b/src/dispatch/incident/severity/service.py index 6cafd61ed9f2..f8fc37d6953d 100644 --- a/src/dispatch/incident/severity/service.py +++ b/src/dispatch/incident/severity/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from pydantic import ValidationError from sqlalchemy.sql.expression import true @@ -13,7 +12,7 @@ ) -def get(*, db_session, incident_severity_id: int) -> Optional[IncidentSeverity]: +def get(*, db_session, incident_severity_id: int) -> IncidentSeverity | None: """Returns an incident severity based on the given severity id.""" return ( db_session.query(IncidentSeverity) @@ -53,7 +52,7 @@ def get_default_or_raise(*, db_session, project_id: int) -> IncidentSeverity: return incident_severity -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[IncidentSeverity]: +def get_by_name(*, db_session, project_id: int, name: str) -> IncidentSeverity | None: """Returns an incident severity based on the given severity name.""" return ( db_session.query(IncidentSeverity) @@ -99,7 +98,7 @@ def get_by_name_or_default( return get_default_or_raise(db_session=db_session, project_id=project_id) -def get_all(*, db_session, project_id: int = None) -> List[Optional[IncidentSeverity]]: +def get_all(*, db_session, project_id: int = None) -> list[IncidentSeverity | None]: """Returns all incident severities.""" if project_id: return db_session.query(IncidentSeverity).filter(IncidentSeverity.project_id == project_id) @@ -107,7 +106,7 @@ def get_all(*, db_session, project_id: int = None) -> List[Optional[IncidentSeve return db_session.query(IncidentSeverity).all() -def get_all_enabled(*, db_session, project_id: int = None) -> List[Optional[IncidentSeverity]]: +def get_all_enabled(*, db_session, project_id: int = None) -> list[IncidentSeverity | None]: """Returns all enabled incident severities.""" if project_id: return ( diff --git a/src/dispatch/incident/type/service.py b/src/dispatch/incident/type/service.py index fe40b948ef81..b27bc46f6a00 100644 --- a/src/dispatch/incident/type/service.py +++ b/src/dispatch/incident/type/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from pydantic import ValidationError from sqlalchemy.sql.expression import true @@ -13,7 +12,7 @@ from .models import IncidentType, IncidentTypeCreate, IncidentTypeRead, IncidentTypeUpdate -def get(*, db_session, incident_type_id: int) -> Optional[IncidentType]: +def get(*, db_session, incident_type_id: int) -> IncidentType | None: """Returns an incident type based on the given type id.""" return db_session.query(IncidentType).filter(IncidentType.id == incident_type_id).one_or_none() @@ -47,7 +46,7 @@ def get_default_or_raise(*, db_session, project_id: int) -> IncidentType: return incident_type -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[IncidentType]: +def get_by_name(*, db_session, project_id: int, name: str) -> IncidentType | None: """Returns an incident type based on the given type name.""" return ( db_session.query(IncidentType) @@ -93,7 +92,7 @@ def get_by_name_or_default( return get_default_or_raise(db_session=db_session, project_id=project_id) -def get_by_slug(*, db_session, project_id: int, slug: str) -> Optional[IncidentType]: +def get_by_slug(*, db_session, project_id: int, slug: str) -> IncidentType | None: """Returns an incident type based on the given type slug.""" return ( db_session.query(IncidentType) @@ -103,14 +102,14 @@ def get_by_slug(*, db_session, project_id: int, slug: str) -> Optional[IncidentT ) -def get_all(*, db_session, project_id: int = None) -> List[Optional[IncidentType]]: +def get_all(*, db_session, project_id: int = None) -> list[IncidentType | None]: """Returns all incident types.""" if project_id: return db_session.query(IncidentType).filter(IncidentType.project_id == project_id) return db_session.query(IncidentType) -def get_all_enabled(*, db_session, project_id: int = None) -> List[Optional[IncidentType]]: +def get_all_enabled(*, db_session, project_id: int = None) -> list[IncidentType | None]: """Returns all enabled incident types.""" if project_id: return ( diff --git a/src/dispatch/incident/views.py b/src/dispatch/incident/views.py index 838188579589..2499342d3580 100644 --- a/src/dispatch/incident/views.py +++ b/src/dispatch/incident/views.py @@ -2,7 +2,6 @@ import json import logging from datetime import date, datetime -from typing import Annotated, List from dateutil.relativedelta import relativedelta from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, status @@ -73,7 +72,7 @@ def get_current_incident(db_session: DbSession, request: Request) -> Incident: @router.get("", summary="Retrieve a list of incidents.") def get_incidents( common: CommonParameters, - include: List[str] = Query([], alias="include[]"), + include: list[str] = Query([], alias="include[]"), expand: bool = Query(default=False), ): """Retrieves a list of incidents.""" diff --git a/src/dispatch/incident_cost/models.py b/src/dispatch/incident_cost/models.py index 398ca822378e..6c89a077f92a 100644 --- a/src/dispatch/incident_cost/models.py +++ b/src/dispatch/incident_cost/models.py @@ -3,7 +3,6 @@ from sqlalchemy import Column, ForeignKey, Integer, Numeric from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.orm import relationship -from typing import List, Optional from dispatch.database.core import Base from dispatch.incident_cost_type.models import IncidentCostTypeRead @@ -35,15 +34,15 @@ class IncidentCostCreate(IncidentCostBase): class IncidentCostUpdate(IncidentCostBase): - id: Optional[PrimaryKey] = None + id: PrimaryKey | None = None incident_cost_type: IncidentCostTypeRead class IncidentCostRead(IncidentCostBase): id: PrimaryKey incident_cost_type: IncidentCostTypeRead - updated_at: Optional[datetime] = None + updated_at: datetime | None = None class IncidentCostPagination(Pagination): - items: List[IncidentCostRead] = [] + items: list[IncidentCostRead] = [] diff --git a/src/dispatch/incident_cost/service.py b/src/dispatch/incident_cost/service.py index 38e1e1f9b719..e02f80486e38 100644 --- a/src/dispatch/incident_cost/service.py +++ b/src/dispatch/incident_cost/service.py @@ -1,7 +1,6 @@ from datetime import datetime, timedelta, timezone import logging import math -from typing import List, Optional from sqlalchemy.orm import Session @@ -27,19 +26,19 @@ log = logging.getLogger(__name__) -def get(*, db_session: Session, incident_cost_id: int) -> Optional[IncidentCost]: +def get(*, db_session: Session, incident_cost_id: int) -> IncidentCost | None: """Gets an incident cost by its id.""" return db_session.query(IncidentCost).filter(IncidentCost.id == incident_cost_id).one_or_none() -def get_by_incident_id(*, db_session: Session, incident_id: int) -> List[Optional[IncidentCost]]: +def get_by_incident_id(*, db_session: Session, incident_id: int) -> list[IncidentCost | None]: """Gets incident costs by their incident id.""" return db_session.query(IncidentCost).filter(IncidentCost.incident_id == incident_id).all() def get_by_incident_id_and_incident_cost_type_id( *, db_session: Session, incident_id: int, incident_cost_type_id: int -) -> Optional[IncidentCost]: +) -> IncidentCost | None: """Gets incident costs by their incident id and incident cost type id.""" return ( db_session.query(IncidentCost) @@ -49,7 +48,7 @@ def get_by_incident_id_and_incident_cost_type_id( ) -def get_all(*, db_session) -> List[Optional[IncidentCost]]: +def get_all(*, db_session) -> list[IncidentCost | None]: """Gets all incident costs.""" return db_session.query(IncidentCost) @@ -154,7 +153,7 @@ def calculate_response_cost( def get_default_incident_response_cost( incident: Incident, db_session: Session -) -> Optional[IncidentCost]: +) -> IncidentCost | None: response_cost_type = incident_cost_type_service.get_default( db_session=db_session, project_id=incident.project.id ) @@ -174,7 +173,7 @@ def get_default_incident_response_cost( def get_or_create_default_incident_response_cost( incident: Incident, db_session: Session -) -> Optional[IncidentCost]: +) -> IncidentCost | None: """Gets or creates the default incident cost for an incident. The default incident cost is the cost associated with the participant effort in an incident's response. @@ -211,7 +210,7 @@ def get_or_create_default_incident_response_cost( def fetch_incident_events( incident: Incident, activity: CostModelActivity, oldest: str, db_session: Session -) -> List[Optional[tuple[datetime.timestamp, str]]]: +) -> list[tuple[datetime.timestamp, str | None]]: plugin_instance = plugin_service.get_active_instance_by_slug( db_session=db_session, slug=activity.plugin_event.plugin.slug, diff --git a/src/dispatch/incident_cost_type/service.py b/src/dispatch/incident_cost_type/service.py index d1642f435d29..bc6bdeb0bb12 100644 --- a/src/dispatch/incident_cost_type/service.py +++ b/src/dispatch/incident_cost_type/service.py @@ -1,5 +1,4 @@ from sqlalchemy.sql.expression import true -from typing import List, Optional from dispatch.project import service as project_service @@ -10,7 +9,7 @@ ) -def get(*, db_session, incident_cost_type_id: int) -> Optional[IncidentCostType]: +def get(*, db_session, incident_cost_type_id: int) -> IncidentCostType | None: """Gets an incident cost type by its id.""" return ( db_session.query(IncidentCostType) @@ -19,7 +18,7 @@ def get(*, db_session, incident_cost_type_id: int) -> Optional[IncidentCostType] ) -def get_default(*, db_session, project_id: int) -> Optional[IncidentCostType]: +def get_default(*, db_session, project_id: int) -> IncidentCostType | None: """Returns the default incident cost type.""" return ( db_session.query(IncidentCostType) @@ -31,7 +30,7 @@ def get_default(*, db_session, project_id: int) -> Optional[IncidentCostType]: def get_by_name( *, db_session, project_id: int, incident_cost_type_name: str -) -> Optional[IncidentCostType]: +) -> IncidentCostType | None: """Gets an incident cost type by its name.""" return ( db_session.query(IncidentCostType) @@ -41,7 +40,7 @@ def get_by_name( ) -def get_all(*, db_session) -> List[Optional[IncidentCostType]]: +def get_all(*, db_session) -> list[IncidentCostType | None]: """Gets all incident cost types.""" return db_session.query(IncidentCostType).all() diff --git a/src/dispatch/incident_role/models.py b/src/dispatch/incident_role/models.py index 69285322608e..c0eb3e62fd7e 100644 --- a/src/dispatch/incident_role/models.py +++ b/src/dispatch/incident_role/models.py @@ -1,5 +1,4 @@ from datetime import datetime -from typing import Optional, List from pydantic import PositiveInt from sqlalchemy import Boolean, Column, Integer, String, PrimaryKeyConstraint, Table, ForeignKey @@ -65,14 +64,14 @@ class IncidentRole(Base, TimeStampMixin, ProjectMixin): # Pydantic models class IncidentRoleBase(DispatchBase): - enabled: Optional[bool] - tags: Optional[List[TagRead]] - order: Optional[PositiveInt] - incident_types: Optional[List[IncidentTypeRead]] - incident_priorities: Optional[List[IncidentPriorityRead]] - service: Optional[ServiceRead] - individual: Optional[IndividualContactRead] - engage_next_oncall: Optional[bool] + enabled: bool | None + tags: list[TagRead] | None + order: PositiveInt | None + incident_types: list[IncidentTypeRead] | None + incident_priorities: list[IncidentPriorityRead] | None + service: ServiceRead | None + individual: IndividualContactRead | None + engage_next_oncall: bool | None class IncidentRoleCreateUpdate(IncidentRoleBase): @@ -81,15 +80,15 @@ class IncidentRoleCreateUpdate(IncidentRoleBase): class IncidentRolesCreateUpdate(DispatchBase): - policies: List[IncidentRoleCreateUpdate] + policies: list[IncidentRoleCreateUpdate] class IncidentRoleRead(IncidentRoleBase): id: PrimaryKey role: ParticipantRoleType - created_at: Optional[datetime] = None - updated_at: Optional[datetime] = None + created_at: datetime | None = None + updated_at: datetime | None = None class IncidentRoles(DispatchBase): - policies: List[IncidentRoleRead] = [] + policies: list[IncidentRoleRead] = [] diff --git a/src/dispatch/incident_role/service.py b/src/dispatch/incident_role/service.py index 2052ddbe3a5a..53e21619cf5f 100644 --- a/src/dispatch/incident_role/service.py +++ b/src/dispatch/incident_role/service.py @@ -1,6 +1,5 @@ import logging -from typing import List, Optional from operator import attrgetter from pydantic import ValidationError @@ -22,19 +21,21 @@ log = logging.getLogger(__name__) -def get(*, db_session, incident_role_id: int) -> Optional[IncidentRole]: - """Gets an incident role by id.""" +def get(*, db_session, incident_role_id: int) -> IncidentRole | None: + """Returns an incident role based on the given id.""" return db_session.query(IncidentRole).filter(IncidentRole.id == incident_role_id).one_or_none() -def get_all(*, db_session): - """Gets all incident role.""" +def get_all(*, db_session, project_id: int = None) -> list[IncidentRole | None]: + """Returns all incident roles.""" + if project_id is not None: + return db_session.query(IncidentRole).filter(IncidentRole.project_id == project_id) return db_session.query(IncidentRole) def get_all_by_role( *, db_session, role: ParticipantRoleType, project_id: int -) -> Optional[List[IncidentRole]]: +) -> list[IncidentRole] | None: """Gets all policies for a given role.""" return ( db_session.query(IncidentRole) @@ -46,7 +47,7 @@ def get_all_by_role( def get_all_enabled_by_role( *, db_session, role: ParticipantRoleType, project_id: int -) -> Optional[List[IncidentRole]]: +) -> list[IncidentRole] | None: """Gets all enabled incident roles.""" return ( db_session.query(IncidentRole) @@ -61,8 +62,8 @@ def create_or_update( db_session, project_in: ProjectRead, role: ParticipantRoleType, - incident_roles_in: List[IncidentRoleCreateUpdate], -) -> List[IncidentRole]: + incident_roles_in: list[IncidentRoleCreateUpdate], +) -> list[IncidentRole]: """Updates a list of incident role policies.""" role_policies = [] @@ -176,7 +177,7 @@ def resolve_role( db_session, role: ParticipantRoleType, incident: Incident, -) -> Optional[IncidentRole]: +) -> IncidentRole | None: """Based on parameters currently associated to an incident determine who should be assigned which incident role.""" incident_roles = get_all_enabled_by_role( db_session=db_session, role=role, project_id=incident.project.id diff --git a/src/dispatch/individual/service.py b/src/dispatch/individual/service.py index 5ab8788daaba..65eec1466e36 100644 --- a/src/dispatch/individual/service.py +++ b/src/dispatch/individual/service.py @@ -1,5 +1,4 @@ from functools import lru_cache -from typing import List, Optional from pydantic import ValidationError from sqlalchemy.orm import Session @@ -24,7 +23,7 @@ def resolve_user_by_email(email: str, db_session: Session): return plugin.instance.get(email) -def get(*, db_session: Session, individual_contact_id: int) -> Optional[IndividualContact]: +def get(*, db_session: Session, individual_contact_id: int) -> IndividualContact | None: """Returns an individual given an individual id.""" return ( db_session.query(IndividualContact) @@ -35,7 +34,7 @@ def get(*, db_session: Session, individual_contact_id: int) -> Optional[Individu def get_by_email_and_project( *, db_session: Session, email: str, project_id: int -) -> Optional[IndividualContact]: +) -> IndividualContact | None: """Returns an individual given an email address and project id.""" return ( db_session.query(IndividualContact) @@ -66,7 +65,7 @@ def get_by_email_and_project_id_or_raise( return individual_contact -def get_all(*, db_session) -> List[Optional[IndividualContact]]: +def get_all(*, db_session) -> list[IndividualContact | None]: """Returns all individuals.""" return db_session.query(IndividualContact) diff --git a/src/dispatch/main.py b/src/dispatch/main.py index 8a729922cbf2..08e4cf5c6ac3 100644 --- a/src/dispatch/main.py +++ b/src/dispatch/main.py @@ -2,7 +2,6 @@ import time from contextvars import ContextVar from os import path -from typing import Final, Optional from uuid import uuid1 import warnings @@ -103,10 +102,10 @@ def get_path_template(request: Request) -> str: REQUEST_ID_CTX_KEY: Final[str] = "request_id" -_request_id_ctx_var: ContextVar[Optional[str]] = ContextVar(REQUEST_ID_CTX_KEY, default=None) +_request_id_ctx_var: ContextVar[str | None] = ContextVar(REQUEST_ID_CTX_KEY, default=None) -def get_request_id() -> Optional[str]: +def get_request_id() -> str | None: return _request_id_ctx_var.get() diff --git a/src/dispatch/messaging/strings.py b/src/dispatch/messaging/strings.py index 923425ec8987..a791e7e2c3c4 100644 --- a/src/dispatch/messaging/strings.py +++ b/src/dispatch/messaging/strings.py @@ -1,6 +1,5 @@ import copy -from typing import List, Optional from dispatch.messaging.email.filters import env from dispatch.conversation.enums import ConversationButtonActions @@ -1230,7 +1229,7 @@ class MessageType(DispatchEnum): ] -def render_message_template(message_template: List[dict], **kwargs): +def render_message_template(message_template: list[dict], **kwargs): """Renders the jinja data included in the template itself.""" data = [] new_copy = copy.deepcopy(message_template) @@ -1302,7 +1301,7 @@ def render_message_template(message_template: List[dict], **kwargs): def generate_welcome_message( welcome_message: EmailTemplates, is_incident: bool = True -) -> Optional[List[dict]]: +) -> list[dict | None]: """Generates the welcome message.""" if welcome_message is None: if is_incident: diff --git a/src/dispatch/models.py b/src/dispatch/models.py index f8f955d9449b..3510f0df1ce3 100644 --- a/src/dispatch/models.py +++ b/src/dispatch/models.py @@ -1,8 +1,6 @@ """Shared models and mixins for the Dispatch application.""" from datetime import datetime, timedelta, timezone -from typing import ClassVar -from typing_extensions import Annotated from pydantic import EmailStr from pydantic import Field, StringConstraints, ConfigDict, BaseModel diff --git a/src/dispatch/monitor/models.py b/src/dispatch/monitor/models.py index 506ee1fa965a..d7d02dca5b53 100644 --- a/src/dispatch/monitor/models.py +++ b/src/dispatch/monitor/models.py @@ -1,4 +1,3 @@ -from typing import Optional from sqlalchemy.orm import relationship from sqlalchemy import Column, ForeignKey, Integer, JSON, Boolean @@ -29,8 +28,8 @@ class Monitor(Base, ResourceMixin, TimeStampMixin): class MonitorBase(ResourceBase): - enabled: Optional[bool] - status: Optional[dict] + enabled: bool | None + status: dict | None class MonitorCreate(MonitorBase): diff --git a/src/dispatch/monitor/scheduled.py b/src/dispatch/monitor/scheduled.py index fd92caceafdd..d6e651f8571e 100644 --- a/src/dispatch/monitor/scheduled.py +++ b/src/dispatch/monitor/scheduled.py @@ -2,7 +2,6 @@ from sqlalchemy.orm import Session from schedule import every -from typing import List from dispatch.database.core import resolve_attr from dispatch.decorators import scheduled_project_task, timer @@ -30,7 +29,7 @@ def run_monitors( db_session: Session, project: Project, monitor_plugin: Plugin, - incidents: List[Incident], + incidents: list[Incident], notify: bool = False, ): """Performs monitor run.""" diff --git a/src/dispatch/monitor/service.py b/src/dispatch/monitor/service.py index e86385a94bdf..2c19c453b9d9 100644 --- a/src/dispatch/monitor/service.py +++ b/src/dispatch/monitor/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from sqlalchemy.sql.expression import true from dispatch.incident import service as incident_service @@ -12,22 +11,22 @@ ) -def get(*, db_session, monitor_id: int) -> Optional[Monitor]: +def get(*, db_session, monitor_id: int) -> Monitor | None: """Returns a monitor based on the given monitor id.""" return db_session.query(Monitor).filter(Monitor.id == monitor_id).one_or_none() -def get_all(*, db_session) -> List[Optional[Monitor]]: +def get_all(*, db_session) -> list[Monitor | None]: """Returns all monitors.""" return db_session.query(Monitor) -def get_enabled(*, db_session) -> List[Optional[Monitor]]: +def get_enabled(*, db_session) -> list[Monitor | None]: """Fetches all enabled monitors.""" return db_session.query(Monitor).filter(Monitor.enabled == true()).all() -def get_by_weblink(*, db_session, weblink: str) -> Optional[Monitor]: +def get_by_weblink(*, db_session, weblink: str) -> Monitor | None: """Fetches a monitor by it's weblink""" return db_session.query(Monitor).filter(Monitor.weblink == weblink).one_or_none() diff --git a/src/dispatch/nlp.py b/src/dispatch/nlp.py index 807d54a7dee0..aa759a90af49 100644 --- a/src/dispatch/nlp.py +++ b/src/dispatch/nlp.py @@ -1,5 +1,4 @@ import logging -from typing import List import spacy from spacy.matcher import PhraseMatcher @@ -10,7 +9,7 @@ nlp.vocab.lex_attr_getters = {} -def build_term_vocab(terms: List[str]): +def build_term_vocab(terms: list[str]): """Builds nlp vocabulary.""" for v in terms: texts = [v, v.lower(), v.upper(), v.title()] @@ -22,14 +21,14 @@ def build_term_vocab(terms: List[str]): yield phrase -def build_phrase_matcher(name: str, phrases: List[str]) -> PhraseMatcher: +def build_phrase_matcher(name: str, phrases: list[str]) -> PhraseMatcher: """Builds a PhraseMatcher object.""" matcher = PhraseMatcher(nlp.tokenizer.vocab) matcher.add(name, phrases) return matcher -def extract_terms_from_text(text: str, matcher: PhraseMatcher) -> List[str]: +def extract_terms_from_text(text: str, matcher: PhraseMatcher) -> list[str]: """Extracts key terms out of test.""" terms = [] doc = nlp.tokenizer(text) diff --git a/src/dispatch/notification/models.py b/src/dispatch/notification/models.py index 7dd3cce870d4..4466bc964844 100644 --- a/src/dispatch/notification/models.py +++ b/src/dispatch/notification/models.py @@ -1,5 +1,4 @@ from datetime import datetime -from typing import Optional, List from pydantic import Field from sqlalchemy import Boolean, Column, Integer, String, ForeignKey, Table @@ -63,27 +62,27 @@ class Notification(Base, TimeStampMixin, ProjectMixin, EvergreenMixin): # Pydantic models class NotificationBase(EvergreenBase): name: NameStr - description: Optional[str] = Field(None, nullable=True) + description: str | None = Field(None, nullable=True) type: NotificationTypeEnum target: str - enabled: Optional[bool] + enabled: bool | None class NotificationCreate(NotificationBase): - filters: Optional[List[SearchFilterRead]] + filters: list[SearchFilterRead | None] project: ProjectRead class NotificationUpdate(NotificationBase): - filters: Optional[List[SearchFilterUpdate]] + filters: list[SearchFilterUpdate | None] class NotificationRead(NotificationBase): id: PrimaryKey - created_at: Optional[datetime] = None - updated_at: Optional[datetime] = None - filters: Optional[List[SearchFilterRead]] + created_at: datetime | None = None + updated_at: datetime | None = None + filters: list[SearchFilterRead | None] class NotificationPagination(Pagination): - items: List[NotificationRead] = [] + items: list[NotificationRead] = [] diff --git a/src/dispatch/notification/service.py b/src/dispatch/notification/service.py index ce42faeec7b7..855b9c150d77 100644 --- a/src/dispatch/notification/service.py +++ b/src/dispatch/notification/service.py @@ -1,6 +1,5 @@ import logging -from typing import List, Optional, Type from dispatch.database.core import Base from dispatch.models import PrimaryKey @@ -14,7 +13,7 @@ log = logging.getLogger(__name__) -def get(*, db_session, notification_id: int) -> Optional[Notification]: +def get(*, db_session, notification_id: int) -> Notification | None: """Gets a notification by id.""" return db_session.query(Notification).filter(Notification.id == notification_id).one_or_none() @@ -24,7 +23,7 @@ def get_all(*, db_session): return db_session.query(Notification) -def get_all_enabled(*, db_session, project_id: int) -> Optional[List[Notification]]: +def get_all_enabled(*, db_session, project_id: int) -> list[Notification | None]: """Gets all enabled notifications.""" return ( db_session.query(Notification) @@ -35,7 +34,7 @@ def get_all_enabled(*, db_session, project_id: int) -> Optional[List[Notificatio def get_overdue_evergreen_notifications( *, db_session, project_id: int -) -> List[Optional[Notification]]: +) -> list[Notification | None]: """Returns all notifications that have not had a recent evergreen notification.""" query = ( db_session.query(Notification) @@ -134,7 +133,7 @@ def filter_and_send( *, db_session, project_id: PrimaryKey, - class_instance: Type[Base], + class_instance: type[Base], notification_params: dict = None, ): """Sends notifications.""" diff --git a/src/dispatch/organization/service.py b/src/dispatch/organization/service.py index dbe9d9ecca52..ba4b7679b026 100644 --- a/src/dispatch/organization/service.py +++ b/src/dispatch/organization/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from pydantic import ValidationError from sqlalchemy.sql.expression import true @@ -11,12 +10,12 @@ from .models import Organization, OrganizationCreate, OrganizationRead, OrganizationUpdate -def get(*, db_session, organization_id: int) -> Optional[Organization]: +def get(*, db_session, organization_id: int) -> Organization | None: """Gets an organization.""" return db_session.query(Organization).filter(Organization.id == organization_id).first() -def get_default(*, db_session) -> Optional[Organization]: +def get_default(*, db_session) -> Organization | None: """Gets the default organization.""" return db_session.query(Organization).filter(Organization.default == true()).one_or_none() @@ -36,7 +35,7 @@ def get_default_or_raise(*, db_session) -> Organization: return organization -def get_by_name(*, db_session, name: str) -> Optional[Organization]: +def get_by_name(*, db_session, name: str) -> Organization | None: """Gets an organization by its name.""" return db_session.query(Organization).filter(Organization.name == name).one_or_none() @@ -60,7 +59,7 @@ def get_by_name_or_raise(*, db_session, organization_in: OrganizationRead) -> Or return organization -def get_by_slug(*, db_session, slug: str) -> Optional[Organization]: +def get_by_slug(*, db_session, slug: str) -> Organization | None: """Gets an organization by its slug.""" return db_session.query(Organization).filter(Organization.slug == slug).one_or_none() @@ -92,7 +91,7 @@ def get_by_name_or_default(*, db_session, organization_in: OrganizationRead) -> return get_default_or_raise(db_session=db_session) -def get_all(*, db_session) -> List[Optional[Organization]]: +def get_all(*, db_session) -> list[Organization | None]: """Gets all organizations.""" return db_session.query(Organization) diff --git a/src/dispatch/participant/flows.py b/src/dispatch/participant/flows.py index 68cf51a8b53c..9d37abfb0213 100644 --- a/src/dispatch/participant/flows.py +++ b/src/dispatch/participant/flows.py @@ -1,5 +1,4 @@ import logging -from typing import List, Optional, TypeVar from sqlalchemy.orm import Session @@ -28,7 +27,7 @@ def add_participant( subject: Subject, db_session: Session, service_id: int = None, - roles: Optional[List[str]] = None, + roles: list[str | None] = None, ) -> Participant: """Adds a participant to an incident or a case.""" # we get or create a new individual diff --git a/src/dispatch/participant/service.py b/src/dispatch/participant/service.py index 9d4a71f76f07..ea873a4bd253 100644 --- a/src/dispatch/participant/service.py +++ b/src/dispatch/participant/service.py @@ -6,7 +6,6 @@ """ import logging -from typing import List, Optional from sqlalchemy.orm import Session @@ -26,14 +25,14 @@ log = logging.getLogger(__name__) -def get(*, db_session: Session, participant_id: int) -> Optional[Participant]: +def get(*, db_session: Session, participant_id: int) -> Participant | None: """Returns a participant based on the given participant id.""" return db_session.query(Participant).filter(Participant.id == participant_id).first() def get_by_individual_contact_id( *, db_session: Session, individual_id: int -) -> List[Optional[Participant]]: +) -> list[Participant | None]: """Returns all participants with the given individual contact id.""" return ( db_session.query(Participant) @@ -42,14 +41,14 @@ def get_by_individual_contact_id( ) -def get_by_incident_id(*, db_session: Session, incident_id: int) -> List[Optional[Participant]]: +def get_by_incident_id(*, db_session: Session, incident_id: int) -> list[Participant | None]: """Returns all participants for the given incident id.""" return db_session.query(Participant).filter(Participant.incident_id == incident_id).all() def get_by_incident_id_and_role( *, db_session: Session, incident_id: int, role: str -) -> Optional[Participant]: +) -> Participant | None: """Returns all participants that have the given role for the given incident id.""" return ( db_session.query(Participant) @@ -63,7 +62,7 @@ def get_by_incident_id_and_role( def get_by_case_id_and_role( *, db_session: Session, case_id: int, role: str -) -> Optional[Participant]: +) -> Participant | None: """Get a participant by case id and role name.""" return ( db_session.query(Participant) @@ -77,7 +76,7 @@ def get_by_case_id_and_role( def get_by_incident_id_and_email( *, db_session: Session, incident_id: int, email: str -) -> Optional[Participant]: +) -> Participant | None: """Returns the participant with the given email for the given incident id.""" return ( db_session.query(Participant) @@ -90,7 +89,7 @@ def get_by_incident_id_and_email( def get_by_case_id_and_email( *, db_session: Session, case_id: int, email: str -) -> Optional[Participant]: +) -> Participant | None: """Get a participant by case id and email.""" return ( db_session.query(Participant) @@ -104,7 +103,7 @@ def get_by_case_id_and_email( @timer def get_by_incident_id_and_service_id( *, db_session: Session, incident_id: int, service_id: int -) -> Optional[Participant]: +) -> Participant | None: """Get participant by incident and service id.""" return ( db_session.query(Participant) @@ -116,7 +115,7 @@ def get_by_incident_id_and_service_id( def get_by_case_id_and_service_id( *, db_session: Session, case_id: int, service_id: int -) -> Optional[Participant]: +) -> Participant | None: """Get participant by incident and service id.""" return ( db_session.query(Participant) @@ -128,7 +127,7 @@ def get_by_case_id_and_service_id( def get_by_incident_id_and_conversation_id( *, db_session: Session, incident_id: int, user_conversation_id: str -) -> Optional[Participant]: +) -> Participant | None: """Get participant by incident and user_conversation id.""" return ( db_session.query(Participant) @@ -140,7 +139,7 @@ def get_by_incident_id_and_conversation_id( def get_by_case_id_and_conversation_id( *, db_session: Session, case_id: int, user_conversation_id: str -) -> Optional[Participant]: +) -> Participant | None: """Get participant by case and user_conversation id.""" return ( db_session.query(Participant) @@ -150,12 +149,12 @@ def get_by_case_id_and_conversation_id( ) -def get_all(*, db_session: Session) -> List[Optional[Participant]]: +def get_all(*, db_session: Session) -> list[Participant | None]: """Returns all participants.""" return db_session.query(Participant).all() -def get_all_by_incident_id(*, db_session: Session, incident_id: int) -> List[Optional[Participant]]: +def get_all_by_incident_id(*, db_session: Session, incident_id: int) -> list[Participant | None]: """Get all participants by incident id.""" return db_session.query(Participant).filter(Participant.incident_id == incident_id).all() @@ -167,7 +166,7 @@ def get_or_create( subject_type: str, individual_id: int, service_id: int, - participant_roles: List[ParticipantRoleCreate], + participant_roles: list[ParticipantRoleCreate], ) -> Participant: """Gets an existing participant object or creates a new one.""" query = db_session.query(Participant) @@ -260,8 +259,8 @@ def create(*, db_session: Session, participant_in: ParticipantCreate) -> Partici def create_all( - *, db_session: Session, participants_in: List[ParticipantCreate] -) -> List[Participant]: + *, db_session: Session, participants_in: list[ParticipantCreate] +) -> list[Participant]: """Create a list of participants.""" participants = [Participant(**t.dict()) for t in participants_in] db_session.bulk_save_objects(participants) diff --git a/src/dispatch/participant_role/flows.py b/src/dispatch/participant_role/flows.py index afcfec85b762..9c7f1e2683ad 100644 --- a/src/dispatch/participant_role/flows.py +++ b/src/dispatch/participant_role/flows.py @@ -6,7 +6,6 @@ """ import logging -from typing import Any from sqlalchemy.orm import Session diff --git a/src/dispatch/participant_role/models.py b/src/dispatch/participant_role/models.py index 5698725f2d4e..67a523ccce1c 100644 --- a/src/dispatch/participant_role/models.py +++ b/src/dispatch/participant_role/models.py @@ -1,6 +1,5 @@ from datetime import datetime -from typing import List, Optional from sqlalchemy import Column, DateTime, ForeignKey, Integer, String @@ -34,9 +33,9 @@ class ParticipantRoleUpdate(ParticipantRoleBase): class ParticipantRoleRead(ParticipantRoleBase): id: PrimaryKey - assumed_at: Optional[datetime] = None - renounced_at: Optional[datetime] = None - activity: Optional[int] + assumed_at: datetime | None = None + renounced_at: datetime | None = None + activity: int | None class ParticipantRoleReadMinimal(ParticipantRoleRead): @@ -44,4 +43,4 @@ class ParticipantRoleReadMinimal(ParticipantRoleRead): class ParticipantRolePagination(ParticipantRoleBase): - items: List[ParticipantRoleRead] = [] + items: list[ParticipantRoleRead] = [] diff --git a/src/dispatch/participant_role/service.py b/src/dispatch/participant_role/service.py index 9005c824b19d..b222ab7e58af 100644 --- a/src/dispatch/participant_role/service.py +++ b/src/dispatch/participant_role/service.py @@ -1,5 +1,4 @@ from datetime import datetime -from typing import List, Optional from dispatch.participant import service as participant_service @@ -11,7 +10,7 @@ ) -def get(*, db_session, participant_role_id: int) -> Optional[ParticipantRole]: +def get(*, db_session, participant_role_id: int) -> ParticipantRole | None: """Returns a participant role based on the given id.""" return ( db_session.query(ParticipantRole).filter(ParticipantRole.id == participant_role_id).first() @@ -22,7 +21,7 @@ def get_last_active_role( *, db_session, participant_id: int, -) -> Optional[ParticipantRole]: +) -> ParticipantRole | None: """Returns the participant's last active role.""" return ( db_session.query(ParticipantRole) @@ -32,7 +31,7 @@ def get_last_active_role( ) -def get_all_active_roles(*, db_session, participant_id: int) -> List[Optional[ParticipantRole]]: +def get_all_active_roles(*, db_session, participant_id: int) -> list[ParticipantRole | None]: """Returns all active roles for the given participant id.""" return ( db_session.query(ParticipantRole) diff --git a/src/dispatch/plugin/models.py b/src/dispatch/plugin/models.py index 1cae6c5f3f0e..c704320e34ce 100644 --- a/src/dispatch/plugin/models.py +++ b/src/dispatch/plugin/models.py @@ -2,7 +2,6 @@ from pydantic import Field, SecretStr from pydantic.json import pydantic_encoder -from typing import Any, List, Optional from sqlalchemy import Column, Integer, String, Boolean, ForeignKey from sqlalchemy.ext.associationproxy import association_proxy @@ -163,14 +162,14 @@ class PluginRead(PluginBase): type: str multiple: bool configuration_schema: Any - description: Optional[str] = Field(None, nullable=True) + description: str | None = Field(None, nullable=True) class PluginEventBase(DispatchBase): name: NameStr slug: str plugin: PluginRead - description: Optional[str] = Field(None, nullable=True) + description: str | None = Field(None, nullable=True) class PluginEventRead(PluginEventBase): @@ -182,54 +181,54 @@ class PluginEventCreate(PluginEventBase): class PluginEventPagination(Pagination): - items: List[PluginEventRead] = [] + items: list[PluginEventRead] = [] class PluginInstanceRead(PluginBase): id: PrimaryKey - enabled: Optional[bool] - configuration: Optional[dict] + enabled: bool | None + configuration: dict | None configuration_schema: Any plugin: PluginRead - project: Optional[ProjectRead] - broken: Optional[bool] + project: ProjectRead | None + broken: bool | None class PluginInstanceReadMinimal(PluginBase): id: PrimaryKey - enabled: Optional[bool] + enabled: bool | None configuration_schema: Any plugin: PluginRead - project: Optional[ProjectRead] - broken: Optional[bool] + project: ProjectRead | None + broken: bool | None class PluginInstanceCreate(PluginBase): - enabled: Optional[bool] - configuration: Optional[dict] + enabled: bool | None + configuration: dict | None plugin: PluginRead project: ProjectRead class PluginInstanceUpdate(PluginBase): id: PrimaryKey = None - enabled: Optional[bool] - configuration: Optional[dict] + enabled: bool | None + configuration: dict | None class KeyValue(DispatchBase): key: str - value: str | List[str] | dict + value: str | list[str] | dict class PluginMetadata(DispatchBase): slug: str - metadata: List[KeyValue] = [] + metadata: list[KeyValue] = [] class PluginPagination(Pagination): - items: List[PluginRead] = [] + items: list[PluginRead] = [] class PluginInstancePagination(Pagination): - items: List[PluginInstanceReadMinimal] = [] + items: list[PluginInstanceReadMinimal] = [] diff --git a/src/dispatch/plugin/service.py b/src/dispatch/plugin/service.py index 0a9a4ac82296..c87e2600801d 100644 --- a/src/dispatch/plugin/service.py +++ b/src/dispatch/plugin/service.py @@ -1,6 +1,5 @@ import logging from pydantic import ValidationError -from typing import List, Optional from sqlalchemy.orm import Session @@ -21,7 +20,7 @@ log = logging.getLogger(__name__) -def get(*, db_session: Session, plugin_id: int) -> Optional[Plugin]: +def get(*, db_session: Session, plugin_id: int) -> Plugin | None: """Returns a plugin based on the given plugin id.""" return db_session.query(Plugin).filter(Plugin.id == plugin_id).one_or_none() @@ -31,17 +30,17 @@ def get_by_slug(*, db_session: Session, slug: str) -> Plugin: return db_session.query(Plugin).filter(Plugin.slug == slug).one_or_none() -def get_all(*, db_session) -> List[Optional[Plugin]]: +def get_all(*, db_session) -> list[Plugin | None]: """Returns all plugins.""" return db_session.query(Plugin).all() -def get_by_type(*, db_session: Session, plugin_type: str) -> List[Optional[Plugin]]: +def get_by_type(*, db_session: Session, plugin_type: str) -> list[Plugin | None]: """Fetches all plugins for a given type.""" return db_session.query(Plugin).filter(Plugin.type == plugin_type).all() -def get_instance(*, db_session: Session, plugin_instance_id: int) -> Optional[PluginInstance]: +def get_instance(*, db_session: Session, plugin_instance_id: int) -> PluginInstance | None: """Returns a plugin instance based on the given instance id.""" return ( db_session.query(PluginInstance) @@ -52,7 +51,7 @@ def get_instance(*, db_session: Session, plugin_instance_id: int) -> Optional[Pl def get_active_instance( *, db_session: Session, plugin_type: str, project_id=None -) -> Optional[PluginInstance]: +) -> PluginInstance | None: """Fetches the current active plugin for the given type.""" return ( db_session.query(PluginInstance) @@ -66,7 +65,7 @@ def get_active_instance( def get_active_instances( *, db_session: Session, plugin_type: str, project_id=None -) -> Optional[PluginInstance]: +) -> PluginInstance | None: """Fetches the current active plugin for the given type.""" return ( db_session.query(PluginInstance) @@ -80,7 +79,7 @@ def get_active_instances( def get_active_instance_by_slug( *, db_session: Session, slug: str, project_id: int | None = None -) -> Optional[PluginInstance]: +) -> PluginInstance | None: """Fetches the current active plugin for the given type.""" return ( db_session.query(PluginInstance) @@ -94,7 +93,7 @@ def get_active_instance_by_slug( def get_enabled_instances_by_type( *, db_session: Session, project_id: int, plugin_type: str -) -> List[Optional[PluginInstance]]: +) -> list[PluginInstance | None]: """Fetches all enabled plugins for a given type.""" return ( db_session.query(PluginInstance) @@ -176,19 +175,19 @@ def delete_instance(*, db_session: Session, plugin_instance_id: int): db_session.commit() -def get_plugin_event_by_id(*, db_session: Session, plugin_event_id: int) -> Optional[PluginEvent]: +def get_plugin_event_by_id(*, db_session: Session, plugin_event_id: int) -> PluginEvent | None: """Returns a plugin event based on the plugin event id.""" return db_session.query(PluginEvent).filter(PluginEvent.id == plugin_event_id).one_or_none() -def get_plugin_event_by_slug(*, db_session: Session, slug: str) -> Optional[PluginEvent]: +def get_plugin_event_by_slug(*, db_session: Session, slug: str) -> PluginEvent | None: """Returns a project based on the plugin event slug.""" return db_session.query(PluginEvent).filter(PluginEvent.slug == slug).one_or_none() def get_all_events_for_plugin( *, db_session: Session, plugin_id: int -) -> List[Optional[PluginEvent]]: +) -> list[PluginEvent | None]: """Returns all plugin events for a given plugin.""" return db_session.query(PluginEvent).filter(PluginEvent.plugin_id == plugin_id).all() diff --git a/src/dispatch/plugins/base/v1.py b/src/dispatch/plugins/base/v1.py index 691e517541bd..21059be8f278 100644 --- a/src/dispatch/plugins/base/v1.py +++ b/src/dispatch/plugins/base/v1.py @@ -9,7 +9,6 @@ import logging from threading import local -from typing import Any, List, Optional from pydantic import BaseModel @@ -21,8 +20,8 @@ class PluginConfiguration(BaseModel): class IPluginEvent: - name: Optional[str] = None - description: Optional[str] = None + name: str | None = None + description: str | None = None # stolen from https://github.com/getsentry/sentry/ @@ -55,21 +54,21 @@ class IPlugin(local): """ # Generic plugin information - title: Optional[str] = None - slug: Optional[str] = None - description: Optional[str] = None - version: Optional[str] = None - author: Optional[str] = None - author_url: Optional[str] = None - configuration: Optional[dict] = None - project_id: Optional[int] = None + title: str | None = None + slug: str | None = None + description: str | None = None + version: str | None = None + author: str | None = None + author_url: str | None = None + configuration: dict | None = None + project_id: int | None = None resource_links = () schema: PluginConfiguration - commands: List[Any] = [] + commands: list[Any] = [] events: Any = None - plugin_events: Optional[List[IPluginEvent]] = [] + plugin_events: list[IPluginEvent | None] = [] # Global enabled state enabled: bool = False @@ -87,14 +86,14 @@ def is_enabled(self) -> bool: return True return True - def get_title(self) -> Optional[str]: + def get_title(self) -> str | None: """ Returns the general title for this plugin. >>> plugin.get_title() """ return self.title - def get_description(self) -> Optional[str]: + def get_description(self) -> str | None: """ Returns the description for this plugin. This is shown on the plugin configuration page. @@ -102,7 +101,7 @@ def get_description(self) -> Optional[str]: """ return self.description - def get_resource_links(self) -> List[Any]: + def get_resource_links(self) -> list[Any]: """ Returns a list of tuples pointing to various resources for this plugin. >>> def get_resource_links(self): @@ -114,7 +113,7 @@ def get_resource_links(self) -> List[Any]: """ return self.resource_links - def get_event(self, event) -> Optional[IPluginEvent]: + def get_event(self, event) -> IPluginEvent | None: for plugin_event in self.plugin_events: if plugin_event.slug == event.slug: return plugin_event diff --git a/src/dispatch/plugins/dispatch_atlassian_confluence/docs/plugin.py b/src/dispatch/plugins/dispatch_atlassian_confluence/docs/plugin.py index b81a52983aa2..1b9cdc2b2a3d 100644 --- a/src/dispatch/plugins/dispatch_atlassian_confluence/docs/plugin.py +++ b/src/dispatch/plugins/dispatch_atlassian_confluence/docs/plugin.py @@ -2,10 +2,9 @@ from dispatch.plugins.bases import DocumentPlugin from dispatch.plugins.dispatch_atlassian_confluence.config import ConfluenceConfigurationBase from atlassian import Confluence -from typing import List -def replace_content(client: Confluence, document_id: str, replacements: List[str]) -> {}: +def replace_content(client: Confluence, document_id: str, replacements: list[str]) -> {}: # read content based on document_id current_content = client.get_page_by_id( document_id, expand="body.storage", status=None, version=None diff --git a/src/dispatch/plugins/dispatch_atlassian_confluence/plugin.py b/src/dispatch/plugins/dispatch_atlassian_confluence/plugin.py index 7d894474ed3f..6b062ccc6fe4 100644 --- a/src/dispatch/plugins/dispatch_atlassian_confluence/plugin.py +++ b/src/dispatch/plugins/dispatch_atlassian_confluence/plugin.py @@ -8,7 +8,6 @@ import requests from requests.auth import HTTPBasicAuth import logging -from typing import List logger = logging.getLogger(__name__) @@ -52,7 +51,7 @@ def __init__(self): self.configuration_schema = ConfluenceConfiguration def create_file( - self, drive_id: str, name: str, participants: List[str] = None, file_type: str = "folder" + self, drive_id: str, name: str, participants: list[str] = None, file_type: str = "folder" ): """Creates a new Home page for the incident documents..""" try: diff --git a/src/dispatch/plugins/dispatch_aws/plugin.py b/src/dispatch/plugins/dispatch_aws/plugin.py index 4f66bc358cb9..a95666408e17 100644 --- a/src/dispatch/plugins/dispatch_aws/plugin.py +++ b/src/dispatch/plugins/dispatch_aws/plugin.py @@ -10,7 +10,6 @@ import json import logging import zlib -from typing import TypedDict import boto3 from psycopg2.errors import UniqueViolation diff --git a/src/dispatch/plugins/dispatch_core/plugin.py b/src/dispatch/plugins/dispatch_core/plugin.py index 050e2626596e..85695b7cf4c5 100644 --- a/src/dispatch/plugins/dispatch_core/plugin.py +++ b/src/dispatch/plugins/dispatch_core/plugin.py @@ -9,7 +9,6 @@ import json import logging import time -from typing import Literal from uuid import UUID import requests diff --git a/src/dispatch/plugins/dispatch_duo/plugin.py b/src/dispatch/plugins/dispatch_duo/plugin.py index cecd15fe1601..aba0718cdfde 100644 --- a/src/dispatch/plugins/dispatch_duo/plugin.py +++ b/src/dispatch/plugins/dispatch_duo/plugin.py @@ -7,7 +7,6 @@ """ import logging -from typing import NewType from dispatch.decorators import apply, counter, timer from dispatch.plugins.bases import MultiFactorAuthenticationPlugin diff --git a/src/dispatch/plugins/dispatch_google/calendar/plugin.py b/src/dispatch/plugins/dispatch_google/calendar/plugin.py index efaf735cc26c..6b4ef50a3759 100644 --- a/src/dispatch/plugins/dispatch_google/calendar/plugin.py +++ b/src/dispatch/plugins/dispatch_google/calendar/plugin.py @@ -10,7 +10,6 @@ import time import uuid from datetime import datetime, timedelta -from typing import Any, List from googleapiclient.errors import HttpError from pytz import timezone @@ -77,7 +76,7 @@ def create_event( name: str, description: str = None, title: str = None, - participants: List[str] = None, + participants: list[str] = None, start_time: str = None, duration: int = 60000, # duration in mins ~6 weeks ): @@ -136,7 +135,7 @@ def __init__(self): self.configuration_schema = GoogleConfiguration def create( - self, name: str, description: str = None, title: str = None, participants: List[str] = None + self, name: str, description: str = None, title: str = None, participants: list[str] = None ): """Create a new event.""" client = get_service(self.configuration, "calendar", "v3", self.scopes) diff --git a/src/dispatch/plugins/dispatch_google/docs/plugin.py b/src/dispatch/plugins/dispatch_google/docs/plugin.py index 2a4f4b9f487d..c4f5710a41be 100644 --- a/src/dispatch/plugins/dispatch_google/docs/plugin.py +++ b/src/dispatch/plugins/dispatch_google/docs/plugin.py @@ -7,7 +7,6 @@ """ import logging -from typing import Any from collections.abc import Generator import unicodedata diff --git a/src/dispatch/plugins/dispatch_google/drive/drive.py b/src/dispatch/plugins/dispatch_google/drive/drive.py index 98dcc36c0ed3..2570329775f7 100644 --- a/src/dispatch/plugins/dispatch_google/drive/drive.py +++ b/src/dispatch/plugins/dispatch_google/drive/drive.py @@ -10,7 +10,6 @@ import io import json import logging -from typing import Any, List from datetime import datetime, timedelta, timezone from googleapiclient.errors import HttpError @@ -178,7 +177,7 @@ def create_file( client: Any, parent_id: str, name: str, - members: List[str], + members: list[str], role: Roles = Roles.writer, file_type: str = "folder", ): diff --git a/src/dispatch/plugins/dispatch_google/drive/plugin.py b/src/dispatch/plugins/dispatch_google/drive/plugin.py index 1967bd0ceca5..1f370d9d1bb3 100644 --- a/src/dispatch/plugins/dispatch_google/drive/plugin.py +++ b/src/dispatch/plugins/dispatch_google/drive/plugin.py @@ -1,4 +1,3 @@ -from typing import List from pydantic import Field from dispatch.decorators import apply, counter, timer @@ -69,7 +68,7 @@ def get(self, file_id: str, mime_type=None): def add_participant( self, team_drive_or_file_id: str, - participants: List[str], + participants: list[str], role: str = Roles.writer, user_type: str = UserTypes.user, ): @@ -78,7 +77,7 @@ def add_participant( for p in participants: add_permission(client, p, team_drive_or_file_id, role, user_type) - def remove_participant(self, team_drive_or_file_id: str, participants: List[str]): + def remove_participant(self, team_drive_or_file_id: str, participants: list[str]): """Removes participants from an existing Google Drive.""" client = get_service(self.configuration, "drive", "v3", self.scopes) for p in participants: @@ -98,7 +97,7 @@ def create_file( self, parent_id: str, name: str, - participants: List[str] = None, + participants: list[str] = None, role: str = Roles.writer, file_type: str = "folder", ): diff --git a/src/dispatch/plugins/dispatch_google/drive/task.py b/src/dispatch/plugins/dispatch_google/drive/task.py index 00cff0c9b856..3cf2de2b4d76 100644 --- a/src/dispatch/plugins/dispatch_google/drive/task.py +++ b/src/dispatch/plugins/dispatch_google/drive/task.py @@ -9,7 +9,6 @@ import re import logging -from typing import Any, List from dispatch.task.enums import TaskStatus from enum import Enum @@ -45,7 +44,7 @@ class AssignmentSubTypes(str, Enum): reassigned = "REASSIGNED" -def find_urls(text: str) -> List[str]: +def find_urls(text: str) -> list[str]: """Finds a url in a text blob.""" # findall() has been used # with valid conditions for urls in string @@ -54,7 +53,7 @@ def find_urls(text: str) -> List[str]: return [x[0] for x in url] -def get_tickets(replies: List[dict]): +def get_tickets(replies: list[dict]): """Fetches urls/tickets from task replies.""" tickets = [] for r in replies: diff --git a/src/dispatch/plugins/dispatch_google/gmail/plugin.py b/src/dispatch/plugins/dispatch_google/gmail/plugin.py index d29c1bb883a8..b71cba8ad3da 100644 --- a/src/dispatch/plugins/dispatch_google/gmail/plugin.py +++ b/src/dispatch/plugins/dispatch_google/gmail/plugin.py @@ -8,7 +8,6 @@ import time from email.mime.text import MIMEText -from typing import Dict, List, Optional import base64 import logging @@ -84,7 +83,7 @@ def send( notification_text: str, notification_template: dict, notification_type: MessageType, - items: Optional[List] = None, + items: List | None = None, **kwargs, ): """Sends an html email based on the type.""" diff --git a/src/dispatch/plugins/dispatch_google/groups/plugin.py b/src/dispatch/plugins/dispatch_google/groups/plugin.py index 1b0faecad4d2..277093c1bf2a 100644 --- a/src/dispatch/plugins/dispatch_google/groups/plugin.py +++ b/src/dispatch/plugins/dispatch_google/groups/plugin.py @@ -7,7 +7,6 @@ import logging import time -from typing import Any, List from googleapiclient.errors import HttpError from tenacity import TryAgain, retry, retry_if_exception_type, stop_after_attempt, wait_exponential @@ -144,7 +143,7 @@ def __init__(self): ] def create( - self, name: str, participants: List[str], description: str = None, role: str = "MEMBER" + self, name: str, participants: list[str], description: str = None, role: str = "MEMBER" ): """Creates a new Google Group.""" client = get_service(self.configuration, "admin", "directory_v1", self.scopes) @@ -166,13 +165,13 @@ def create( ) return group - def add(self, email: str, participants: List[str], role: str = "MEMBER"): + def add(self, email: str, participants: list[str], role: str = "MEMBER"): """Adds participants to an existing Google Group.""" client = get_service(self.configuration, "admin", "directory_v1", self.scopes) for p in participants: add_member(client, email, p, role) - def remove(self, email: str, participants: List[str]): + def remove(self, email: str, participants: list[str]): """Removes participants from an existing Google Group.""" client = get_service(self.configuration, "admin", "directory_v1", self.scopes) for p in participants: diff --git a/src/dispatch/plugins/dispatch_jira/plugin.py b/src/dispatch/plugins/dispatch_jira/plugin.py index 31c5b592326f..81d099796305 100644 --- a/src/dispatch/plugins/dispatch_jira/plugin.py +++ b/src/dispatch/plugins/dispatch_jira/plugin.py @@ -5,7 +5,6 @@ :license: Apache, see LICENSE for more details. """ -from typing import Any import json import logging diff --git a/src/dispatch/plugins/dispatch_microsoft_teams/conference/client.py b/src/dispatch/plugins/dispatch_microsoft_teams/conference/client.py index d22ce7e25f60..edd2841e3db6 100644 --- a/src/dispatch/plugins/dispatch_microsoft_teams/conference/client.py +++ b/src/dispatch/plugins/dispatch_microsoft_teams/conference/client.py @@ -2,7 +2,6 @@ import logging import requests import json -from typing import Any logger = logging.getLogger(__name__) diff --git a/src/dispatch/plugins/dispatch_microsoft_teams/conference/plugin.py b/src/dispatch/plugins/dispatch_microsoft_teams/conference/plugin.py index d290ee7651e6..4f2f5165c2f0 100644 --- a/src/dispatch/plugins/dispatch_microsoft_teams/conference/plugin.py +++ b/src/dispatch/plugins/dispatch_microsoft_teams/conference/plugin.py @@ -1,5 +1,4 @@ import logging -from typing import List from dispatch.plugins.bases import ConferencePlugin from dispatch.plugins.dispatch_microsoft_teams import conference as teams_plugin @@ -26,7 +25,7 @@ def __init__(self): @apply(counter, exclude=["__init__"]) @apply(timer, exclude=["__init__"]) def create( - self, name: str, description: str = None, title: str = None, participants: List[str] = None + self, name: str, description: str = None, title: str = None, participants: list[str] = None ): try: client = MSTeamsClient( diff --git a/src/dispatch/plugins/dispatch_pagerduty/plugin.py b/src/dispatch/plugins/dispatch_pagerduty/plugin.py index 5d501e976cf1..a2619618fcd4 100644 --- a/src/dispatch/plugins/dispatch_pagerduty/plugin.py +++ b/src/dispatch/plugins/dispatch_pagerduty/plugin.py @@ -7,7 +7,6 @@ from pdpyras import APISession from pydantic import Field, SecretStr, EmailStr -from typing import Optional import logging from dispatch.config import BaseConfigurationModel @@ -86,7 +85,7 @@ def page( event_type=kwargs.get("event_type", "incident"), ) - def did_oncall_just_go_off_shift(self, schedule_id: str, hour: int) -> Optional[dict]: + def did_oncall_just_go_off_shift(self, schedule_id: str, hour: int) -> dict | None: client = APISession(self.configuration.api_key.get_secret_value()) client.url = self.configuration.pagerduty_api_url return oncall_shift_check( @@ -95,7 +94,7 @@ def did_oncall_just_go_off_shift(self, schedule_id: str, hour: int) -> Optional[ hour=hour, ) - def get_schedule_id_from_service_id(self, service_id: str) -> Optional[str]: + def get_schedule_id_from_service_id(self, service_id: str) -> str | None: if not service_id: return None @@ -118,7 +117,7 @@ def get_schedule_id_from_service_id(self, service_id: str) -> Optional[str]: log.error("Error trying to retrieve schedule_id from service_id") log.exception(e) - def get_service_url(self, service_id: str) -> Optional[str]: + def get_service_url(self, service_id: str) -> str | None: if not service_id: return None @@ -132,7 +131,7 @@ def get_service_url(self, service_id: str) -> Optional[str]: log.exception(e) return None - def get_next_oncall(self, service_id: str) -> Optional[str]: + def get_next_oncall(self, service_id: str) -> str | None: schedule_id = self.get_schedule_id_from_service_id(service_id) client = APISession(self.configuration.api_key.get_secret_value()) diff --git a/src/dispatch/plugins/dispatch_pagerduty/service.py b/src/dispatch/plugins/dispatch_pagerduty/service.py index f53d6f5b8a5a..cc84c51d329c 100644 --- a/src/dispatch/plugins/dispatch_pagerduty/service.py +++ b/src/dispatch/plugins/dispatch_pagerduty/service.py @@ -1,6 +1,5 @@ from datetime import datetime, timedelta from http import HTTPStatus -from typing import Optional import logging from pdpyras import APISession, PDHTTPError, PDClientError @@ -139,7 +138,7 @@ def page_oncall( return create_incident(client, headers, data) -def get_oncall_at_time(client: APISession, schedule_id: str, utctime: str) -> Optional[dict]: +def get_oncall_at_time(client: APISession, schedule_id: str, utctime: str) -> dict | None: """Retrieves the email of the oncall person at the utc time given.""" try: oncalls = list( @@ -182,7 +181,7 @@ def get_oncall_at_time(client: APISession, schedule_id: str, utctime: str) -> Op raise e -def oncall_shift_check(client: APISession, schedule_id: str, hour: int) -> Optional[dict]: +def oncall_shift_check(client: APISession, schedule_id: str, hour: int) -> dict | None: """Determines whether the oncall person just went off shift and returns their email.""" now = datetime.utcnow() # in case scheduler is late, replace hour with exact one for shift comparison @@ -211,7 +210,7 @@ def oncall_shift_check(client: APISession, schedule_id: str, hour: int) -> Optio return previous_oncall -def get_next_oncall(client: APISession, schedule_id: str) -> Optional[str]: +def get_next_oncall(client: APISession, schedule_id: str) -> str | None: """Retrieves the email of the next oncall person. Assumes 12-hour shifts""" now = datetime.utcnow() diff --git a/src/dispatch/plugins/dispatch_slack/bolt.py b/src/dispatch/plugins/dispatch_slack/bolt.py index 12e1dfca313d..a20852055292 100644 --- a/src/dispatch/plugins/dispatch_slack/bolt.py +++ b/src/dispatch/plugins/dispatch_slack/bolt.py @@ -1,7 +1,6 @@ import logging import uuid from http import HTTPStatus -from typing import Any from blockkit import Context, MarkdownText, Modal from slack_bolt.app import App diff --git a/src/dispatch/plugins/dispatch_slack/case/messages.py b/src/dispatch/plugins/dispatch_slack/case/messages.py index 4c5dc0aa3b56..eac39d478ef2 100644 --- a/src/dispatch/plugins/dispatch_slack/case/messages.py +++ b/src/dispatch/plugins/dispatch_slack/case/messages.py @@ -1,5 +1,4 @@ import logging -from typing import NamedTuple, Tuple from blockkit import ( Actions, @@ -369,7 +368,7 @@ def create_genai_signal_message_metadata_blocks( def create_genai_signal_analysis_message( case: Case, db_session: Session, -) -> Tuple[str | dict[str, str], list[Block]]: +) -> tuple[str | dict[str, str], list[Block]]: """ Generates a GenAI signal analysis message for a given case. @@ -381,7 +380,7 @@ def create_genai_signal_analysis_message( db_session (Session): The database session to use for querying and generating the case signal summary. Returns: - Tuple[str | dict[str, str], list[Block]]: A tuple containing the GenAI analysis message (either as a string or a dictionary) + tuple[str | dict[str, str], list[Block]]: A tuple containing the GenAI analysis message (either as a string or a dictionary) and the updated list of signal metadata blocks with the GenAI analysis section appended. """ signal_metadata_blocks = [] diff --git a/src/dispatch/plugins/dispatch_slack/config.py b/src/dispatch/plugins/dispatch_slack/config.py index 155c51267fcc..37c47a84e9ba 100644 --- a/src/dispatch/plugins/dispatch_slack/config.py +++ b/src/dispatch/plugins/dispatch_slack/config.py @@ -1,4 +1,3 @@ -from typing import Optional from pydantic import Field, SecretStr from dispatch.config import BaseConfigurationModel @@ -12,7 +11,7 @@ class SlackConfiguration(BaseConfigurationModel): api_bot_token: SecretStr = Field( title="API Bot Token", description="Token to use when plugin is in http/api mode." ) - socket_mode_app_token: Optional[SecretStr] = Field( + socket_mode_app_token: SecretStr | None = Field( title="Socket Mode App Token", description="Token used when plugin is in socket mode." ) signing_secret: SecretStr = Field( @@ -24,16 +23,16 @@ class SlackConfiguration(BaseConfigurationModel): class SlackContactConfiguration(SlackConfiguration): """Slack contact configuration.""" - profile_department_field_id: Optional[str] = Field( + profile_department_field_id: str | None = Field( None, title="Profile Department Field Id", description="Defines the field in the slack profile where Dispatch should fetch the users department.", ) - profile_team_field_id: Optional[str] = Field( + profile_team_field_id: str | None = Field( title="Profile Team Field Id", description="Defines the field in the slack profile where Dispatch should fetch a users team.", ) - profile_weblink_field_id: Optional[str] = Field( + profile_weblink_field_id: str | None = Field( title="Profile Weblink Field Id", description="Defines the field in the slack profile where Dispatch should fetch the users weblink.", ) diff --git a/src/dispatch/plugins/dispatch_slack/events.py b/src/dispatch/plugins/dispatch_slack/events.py index 850214b8ee13..6ffc67c0ef38 100644 --- a/src/dispatch/plugins/dispatch_slack/events.py +++ b/src/dispatch/plugins/dispatch_slack/events.py @@ -1,6 +1,5 @@ import logging from slack_sdk import WebClient -from typing import List from dispatch.plugins.base import IPluginEvent diff --git a/src/dispatch/plugins/dispatch_slack/fields.py b/src/dispatch/plugins/dispatch_slack/fields.py index bf967f5251b1..0cee3bd609ab 100644 --- a/src/dispatch/plugins/dispatch_slack/fields.py +++ b/src/dispatch/plugins/dispatch_slack/fields.py @@ -1,7 +1,6 @@ import logging from datetime import timedelta from sqlalchemy.orm import Session -from typing import List from blockkit import ( Checkboxes, @@ -254,7 +253,7 @@ def datetime_picker_block( def static_select_block( - options: List[str], + options: list[str], placeholder: str, action_id: str = None, block_id: str = None, @@ -277,7 +276,7 @@ def static_select_block( def multi_select_block( - options: List[str], + options: list[str], placeholder: str, action_id: str = None, block_id: str = None, @@ -695,7 +694,7 @@ def entity_select( def participant_select( - participants: List[Participant], + participants: list[Participant], action_id: str = DefaultActionIds.participant_select, block_id: str = DefaultBlockIds.participant_select, label: str = "Participant", diff --git a/src/dispatch/plugins/dispatch_slack/handler.py b/src/dispatch/plugins/dispatch_slack/handler.py index b848dfa08a5a..37c89be00c62 100644 --- a/src/dispatch/plugins/dispatch_slack/handler.py +++ b/src/dispatch/plugins/dispatch_slack/handler.py @@ -5,7 +5,6 @@ """ from http import HTTPStatus -from typing import Dict, Any, Optional from starlette.requests import Request from starlette.responses import Response @@ -17,7 +16,7 @@ def to_bolt_request( req: Request, body: bytes, - addition_context_properties: Optional[Dict[str, Any]] = None, + addition_context_properties: dict[str, Any | None] = None, ) -> BoltRequest: request = BoltRequest( body=body.decode("utf-8"), @@ -59,7 +58,7 @@ def handle( self, req: Request, body: bytes, - addition_context_properties: Optional[Dict[str, Any]] = None, + addition_context_properties: dict[str, Any | None] = None, ) -> Response: if req.method == "GET": if self.app.oauth_flow is not None: diff --git a/src/dispatch/plugins/dispatch_slack/incident/interactive.py b/src/dispatch/plugins/dispatch_slack/incident/interactive.py index 73f45eab1168..be0130b60a0f 100644 --- a/src/dispatch/plugins/dispatch_slack/incident/interactive.py +++ b/src/dispatch/plugins/dispatch_slack/incident/interactive.py @@ -3,7 +3,6 @@ import uuid from functools import partial from datetime import datetime, timedelta -from typing import Any import pytz from blockkit import ( diff --git a/src/dispatch/plugins/dispatch_slack/messaging.py b/src/dispatch/plugins/dispatch_slack/messaging.py index 50d8493df0dc..c55a5375ed83 100644 --- a/src/dispatch/plugins/dispatch_slack/messaging.py +++ b/src/dispatch/plugins/dispatch_slack/messaging.py @@ -6,7 +6,6 @@ """ import logging -from typing import Any, List, Optional from blockkit import ( Actions, @@ -57,7 +56,7 @@ def get_template(message_type: MessageType): def get_incident_conversation_command_message( - command_string: str, config: Optional[SlackConfiguration] = None + command_string: str, config: SlackConfiguration | None = None ) -> dict[str, str]: """Fetches a custom message and response type for each respective slash command.""" @@ -263,9 +262,9 @@ def default_notification(items: list): def create_message_blocks( - message_template: List[dict], + message_template: list[dict], message_type: MessageType, - items: Optional[List] = None, + items: List | None = None, **kwargs, ): """Creates all required blocks for a given message type and template.""" diff --git a/src/dispatch/plugins/dispatch_slack/middleware.py b/src/dispatch/plugins/dispatch_slack/middleware.py index f391930989df..a464132c1d41 100644 --- a/src/dispatch/plugins/dispatch_slack/middleware.py +++ b/src/dispatch/plugins/dispatch_slack/middleware.py @@ -1,6 +1,5 @@ import logging import json -from typing import Callable, NamedTuple, Optional from slack_bolt import BoltContext, BoltRequest from slack_sdk.web import WebClient @@ -36,7 +35,7 @@ @timer -def resolve_context_from_conversation(channel_id: str, thread_id: str = None) -> Optional[Subject]: +def resolve_context_from_conversation(channel_id: str, thread_id: str = None) -> Subject | None: """Attempts to resolve a conversation based on the channel id and thread_id.""" organization_slugs = [] with get_session() as db_session: diff --git a/src/dispatch/plugins/dispatch_slack/models.py b/src/dispatch/plugins/dispatch_slack/models.py index 06dad73a9755..597da2c79735 100644 --- a/src/dispatch/plugins/dispatch_slack/models.py +++ b/src/dispatch/plugins/dispatch_slack/models.py @@ -1,6 +1,5 @@ """Models for Slack command payloads in the Dispatch application.""" -from typing import NewType, TypedDict from pydantic import BaseModel, AnyHttpUrl diff --git a/src/dispatch/plugins/dispatch_slack/plugin.py b/src/dispatch/plugins/dispatch_slack/plugin.py index 336792bfabdb..a57fa4734528 100644 --- a/src/dispatch/plugins/dispatch_slack/plugin.py +++ b/src/dispatch/plugins/dispatch_slack/plugin.py @@ -9,7 +9,6 @@ import io import json import logging -from typing import Any, List, Optional from blockkit import Message from blockkit.surfaces import Block @@ -253,11 +252,11 @@ def send( self, conversation_id: str, text: str, - message_template: List[dict], + message_template: list[dict], notification_type: str, - items: Optional[List] = None, - blocks: Optional[List] = None, - ts: Optional[str] = None, + items: List | None = None, + blocks: List | None = None, + ts: str | None = None, persist: bool = False, **kwargs, ): @@ -298,9 +297,9 @@ def send_direct( text: str, message_template: dict, notification_type: str, - items: Optional[List] = None, - ts: Optional[str] = None, - blocks: Optional[List] = None, + items: List | None = None, + ts: str | None = None, + blocks: List | None = None, **kwargs, ): """Sends a message directly to a user if the user exists.""" @@ -323,8 +322,8 @@ def send_ephemeral( text: str, message_template: dict = None, notification_type: str = None, - items: Optional[List] = None, - blocks: Optional[List] = None, + items: List | None = None, + blocks: List | None = None, **kwargs, ): """Sends an ephemeral message to a user in a channel if the user exists.""" @@ -342,7 +341,7 @@ def send_ephemeral( if not archived: send_ephemeral_message(client, conversation_id, user_id, text, blocks) - def add(self, conversation_id: str, participants: List[str]): + def add(self, conversation_id: str, participants: list[str]): """Adds users to conversation if it is not archived.""" client = create_slack_client(self.configuration) archived = conversation_archived(client, conversation_id) @@ -350,7 +349,7 @@ def add(self, conversation_id: str, participants: List[str]): participants = [resolve_user(client, p)["id"] for p in set(participants)] add_users_to_conversation(client, conversation_id, participants) - def add_to_thread(self, conversation_id: str, thread_id: str, participants: List[str]): + def add_to_thread(self, conversation_id: str, thread_id: str, participants: list[str]): """Adds users to a thread conversation.""" client = create_slack_client(self.configuration) user_ids = emails_to_user_ids(client=client, participants=participants) diff --git a/src/dispatch/plugins/dispatch_slack/service.py b/src/dispatch/plugins/dispatch_slack/service.py index de3986ea680f..f3f7fedd2094 100644 --- a/src/dispatch/plugins/dispatch_slack/service.py +++ b/src/dispatch/plugins/dispatch_slack/service.py @@ -2,7 +2,6 @@ import heapq import logging from datetime import datetime -from typing import Dict, List, Optional from blockkit import Message, Section from requests import Timeout @@ -285,7 +284,7 @@ def get_user_avatar_url(client: WebClient, email: str) -> str: return get_user_info_by_email(client, email)["profile"]["image_512"] -def get_conversations_by_user_id(client: WebClient, user_id: str, type: str) -> List[Conversation]: +def get_conversations_by_user_id(client: WebClient, user_id: str, type: str) -> list[Conversation]: result = make_call( client, SlackAPIGetEndpoints.users_conversations, @@ -434,7 +433,7 @@ def add_users_to_conversation_thread( send_message(client=client, conversation_id=conversation_id, blocks=blocks, ts=thread_id) -def add_users_to_conversation(client: WebClient, conversation_id: str, user_ids: List[str]) -> None: +def add_users_to_conversation(client: WebClient, conversation_id: str, user_ids: list[str]) -> None: """Add users to conversation.""" # NOTE this will trigger a member_joined_channel event, which we will capture and run # the incident.incident_add_or_reactivate_participant_flow() as a result @@ -466,7 +465,7 @@ def send_message( conversation_id: str, text: str = None, ts: str = None, - blocks: List[Dict] = None, + blocks: list[dict] = None, persist: bool = False, ) -> dict: """Sends a message to the given conversation.""" @@ -495,7 +494,7 @@ def update_message( conversation_id: str, text: str = None, ts: str = None, - blocks: List[Dict] = None, + blocks: list[dict] = None, ) -> dict: """Updates a message for the given conversation.""" response = make_call( @@ -519,8 +518,8 @@ def send_ephemeral_message( conversation_id: str, user_id: str, text: str, - blocks: Optional[List] = None, - thread_ts: Optional[str] = None, + blocks: list | None = None, + thread_ts: str | None = None, ) -> dict: """Sends an ephemeral message to a user in a channel or thread.""" if thread_ts: @@ -560,7 +559,7 @@ def is_user(config: SlackConversationConfiguration, user_id: str) -> bool: def get_thread_activity( client: WebClient, conversation_id: str, ts: str, oldest: str = "0" -) -> List: +) -> list: """Gets all messages for a given Slack thread. Returns: @@ -596,7 +595,7 @@ def get_thread_activity( return heapq.nsmallest(len(result), result) -def get_channel_activity(client: WebClient, conversation_id: str, oldest: str = "0") -> List: +def get_channel_activity(client: WebClient, conversation_id: str, oldest: str = "0") -> list: """Gets all top-level messages for a given Slack channel. Returns: diff --git a/src/dispatch/plugins/dispatch_test/conversation.py b/src/dispatch/plugins/dispatch_test/conversation.py index f278b60a8ee5..b35264ca6096 100644 --- a/src/dispatch/plugins/dispatch_test/conversation.py +++ b/src/dispatch/plugins/dispatch_test/conversation.py @@ -1,6 +1,5 @@ from datetime import datetime from slack_sdk import WebClient -from typing import Any from dispatch.plugins.bases import ConversationPlugin from dispatch.plugins.dispatch_slack.events import ChannelActivityEvent diff --git a/src/dispatch/plugins/dispatch_zoom/plugin.py b/src/dispatch/plugins/dispatch_zoom/plugin.py index a0b97d0f719f..5a352ff86a52 100644 --- a/src/dispatch/plugins/dispatch_zoom/plugin.py +++ b/src/dispatch/plugins/dispatch_zoom/plugin.py @@ -8,7 +8,6 @@ import logging import random -from typing import List from dispatch.decorators import apply, counter, timer from dispatch.plugins import dispatch_zoom as zoom_plugin @@ -67,7 +66,7 @@ def __init__(self): self.configuration_schema = ZoomConfiguration def create( - self, name: str, description: str = None, title: str = None, participants: List[str] = None + self, name: str, description: str = None, title: str = None, participants: list[str] = None ): """Create a new event.""" client = ZoomClient( diff --git a/src/dispatch/project/models.py b/src/dispatch/project/models.py index 5bb6e5a86d80..d3713ff9975d 100644 --- a/src/dispatch/project/models.py +++ b/src/dispatch/project/models.py @@ -1,6 +1,5 @@ from pydantic import EmailStr from slugify import slugify -from typing import List, Optional from pydantic import Field from sqlalchemy.ext.hybrid import hybrid_property @@ -91,38 +90,38 @@ def slug(self): class Service(DispatchBase): id: PrimaryKey - description: Optional[str] = Field(None, nullable=True) + description: str | None = Field(None, nullable=True) external_id: str - is_active: Optional[bool] = None + is_active: bool | None = None name: NameStr - type: Optional[str] = Field(None, nullable=True) + type: str | None = Field(None, nullable=True) class ProjectBase(DispatchBase): - id: Optional[PrimaryKey] + id: PrimaryKey | None name: NameStr - display_name: Optional[str] = Field("", nullable=False) - owner_email: Optional[EmailStr] = Field(None, nullable=True) - owner_conversation: Optional[str] = Field(None, nullable=True) - annual_employee_cost: Optional[int] - business_year_hours: Optional[int] - description: Optional[str] = Field(None, nullable=True) + display_name: str | None = Field("", nullable=False) + owner_email: EmailStr | None = Field(None, nullable=True) + owner_conversation: str | None = Field(None, nullable=True) + annual_employee_cost: int | None + business_year_hours: int | None + description: str | None = Field(None, nullable=True) default: bool = False - color: Optional[str] = Field(None, nullable=True) - send_daily_reports: Optional[bool] = Field(True, nullable=True) - send_weekly_reports: Optional[bool] = Field(False, nullable=True) - weekly_report_notification_id: Optional[int] = Field(None, nullable=True) - enabled: Optional[bool] = Field(True, nullable=True) - storage_folder_one: Optional[str] = Field(None, nullable=True) - storage_folder_two: Optional[str] = Field(None, nullable=True) - storage_use_folder_one_as_primary: Optional[bool] = Field(True, nullable=True) - storage_use_title: Optional[bool] = Field(False, nullable=True) - allow_self_join: Optional[bool] = Field(True, nullable=True) - select_commander_visibility: Optional[bool] = Field(True, nullable=True) - report_incident_instructions: Optional[str] = Field(None, nullable=True) - report_incident_title_hint: Optional[str] = Field(None, nullable=True) - report_incident_description_hint: Optional[str] = Field(None, nullable=True) - snooze_extension_oncall_service: Optional[Service] = None + color: str | None = Field(None, nullable=True) + send_daily_reports: bool | None = Field(True, nullable=True) + send_weekly_reports: bool | None = Field(False, nullable=True) + weekly_report_notification_id: int | None = Field(None, nullable=True) + enabled: bool | None = Field(True, nullable=True) + storage_folder_one: str | None = Field(None, nullable=True) + storage_folder_two: str | None = Field(None, nullable=True) + storage_use_folder_one_as_primary: bool | None = Field(True, nullable=True) + storage_use_title: bool | None = Field(False, nullable=True) + allow_self_join: bool | None = Field(True, nullable=True) + select_commander_visibility: bool | None = Field(True, nullable=True) + report_incident_instructions: str | None = Field(None, nullable=True) + report_incident_title_hint: str | None = Field(None, nullable=True) + report_incident_description_hint: str | None = Field(None, nullable=True) + snooze_extension_oncall_service: Service | None = None class ProjectCreate(ProjectBase): @@ -130,17 +129,17 @@ class ProjectCreate(ProjectBase): class ProjectUpdate(ProjectBase): - send_daily_reports: Optional[bool] = Field(True, nullable=True) - send_weekly_reports: Optional[bool] = Field(False, nullable=True) - weekly_report_notification_id: Optional[int] = Field(None, nullable=True) - stable_priority_id: Optional[int] - snooze_extension_oncall_service_id: Optional[int] + send_daily_reports: bool | None = Field(True, nullable=True) + send_weekly_reports: bool | None = Field(False, nullable=True) + weekly_report_notification_id: int | None = Field(None, nullable=True) + stable_priority_id: int | None + snooze_extension_oncall_service_id: int | None class ProjectRead(ProjectBase): - id: Optional[PrimaryKey] - stable_priority: Optional[IncidentPriorityRead] = None + id: PrimaryKey | None + stable_priority: IncidentPriorityRead | None = None class ProjectPagination(Pagination): - items: List[ProjectRead] = [] + items: list[ProjectRead] = [] diff --git a/src/dispatch/project/service.py b/src/dispatch/project/service.py index 0da442e8fcf4..d5c505d711f8 100644 --- a/src/dispatch/project/service.py +++ b/src/dispatch/project/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from pydantic import ValidationError from sqlalchemy.orm import Session @@ -13,7 +12,7 @@ def get(*, db_session: Session, project_id: int) -> Project | None: return db_session.query(Project).filter(Project.id == project_id).first() -def get_default(*, db_session: Session) -> Optional[Project]: +def get_default(*, db_session: Session) -> Project | None: """Returns the default project.""" return db_session.query(Project).filter(Project.default == true()).one_or_none() @@ -33,7 +32,7 @@ def get_default_or_raise(*, db_session: Session) -> Project: return project -def get_by_name(*, db_session: Session, name: str) -> Optional[Project]: +def get_by_name(*, db_session: Session, name: str) -> Project | None: """Returns a project based on the given project name.""" return db_session.query(Project).filter(Project.name == name).one_or_none() @@ -64,7 +63,7 @@ def get_by_name_or_default(*, db_session, project_in: ProjectRead) -> Project: return get_default_or_raise(db_session=db_session) -def get_all(*, db_session) -> List[Optional[Project]]: +def get_all(*, db_session) -> list[Project | None]: """Returns all projects.""" return db_session.query(Project) diff --git a/src/dispatch/report/models.py b/src/dispatch/report/models.py index 6781b7706362..0e83b07e2861 100644 --- a/src/dispatch/report/models.py +++ b/src/dispatch/report/models.py @@ -1,6 +1,5 @@ from datetime import datetime -from typing import List, Optional from sqlalchemy import Column, DateTime, Integer, String, ForeignKey, event from sqlalchemy.orm import relationship @@ -38,7 +37,7 @@ def __declare_last__(cls): # Pydantic models... class ReportBase(DispatchBase): - details: Optional[dict] = None + details: dict | None = None type: ReportTypes @@ -52,11 +51,11 @@ class ReportUpdate(ReportBase): class ReportRead(ReportBase): id: int - created_at: Optional[datetime] = None + created_at: datetime | None = None class ReportPagination(Pagination): - items: List[ReportRead] = [] + items: list[ReportRead] = [] class TacticalReportCreate(DispatchBase): diff --git a/src/dispatch/report/scheduled.py b/src/dispatch/report/scheduled.py index f9ff8be212b0..edfc73cb8382 100644 --- a/src/dispatch/report/scheduled.py +++ b/src/dispatch/report/scheduled.py @@ -8,7 +8,6 @@ import logging from datetime import datetime, timedelta from schedule import every -from typing import Optional from sqlalchemy.orm import Session from dispatch.decorators import scheduled_project_task, timer @@ -24,7 +23,7 @@ log = logging.getLogger(__name__) -def reminder_set_in_future(reminder: Optional[datetime]) -> bool: +def reminder_set_in_future(reminder: datetime | None) -> bool: """if this reminder has been manually delayed, do not send regularly scheduled one""" if reminder and reminder - datetime.utcnow() > timedelta(minutes=1): return True diff --git a/src/dispatch/report/service.py b/src/dispatch/report/service.py index 1309e91353f0..8299ddf0e226 100644 --- a/src/dispatch/report/service.py +++ b/src/dispatch/report/service.py @@ -1,17 +1,16 @@ -from typing import List, Optional from .enums import ReportTypes from .models import Report, ReportCreate, ReportUpdate -def get(*, db_session, report_id: int) -> Optional[Report]: +def get(*, db_session, report_id: int) -> Report | None: """Get a report by id.""" return db_session.query(Report).filter(Report.id == report_id).one_or_none() def get_most_recent_by_incident_id_and_type( *, db_session, incident_id: int, report_type: ReportTypes -) -> Optional[Report]: +) -> Report | None: """Get most recent report by incident id and report type.""" return ( db_session.query(Report) @@ -24,7 +23,7 @@ def get_most_recent_by_incident_id_and_type( def get_all_by_incident_id_and_type( *, db_session, incident_id: int, report_type: ReportTypes -) -> Optional[Report]: +) -> Report | None: """Get all reports by incident id and report type.""" return ( db_session.query(Report) @@ -33,7 +32,7 @@ def get_all_by_incident_id_and_type( ) -def get_all(*, db_session) -> List[Optional[Report]]: +def get_all(*, db_session) -> list[Report | None]: """Get all reports.""" return db_session.query(Report) diff --git a/src/dispatch/route/models.py b/src/dispatch/route/models.py index bb7bc92fbc3a..5ca31b1e7392 100644 --- a/src/dispatch/route/models.py +++ b/src/dispatch/route/models.py @@ -1,4 +1,3 @@ -from typing import Optional from datetime import datetime from sqlalchemy import Boolean, Column, ForeignKey, Integer, DateTime, String @@ -35,7 +34,7 @@ class RecommendationMatchBase(DispatchBase): class RecommendationBase(DispatchBase): - matches: Optional[list[RecommendationMatchBase]] + matches: list[RecommendationMatchBase | None] class RouteBase(DispatchBase): diff --git a/src/dispatch/route/service.py b/src/dispatch/route/service.py index 695a71a7975c..1c1446fa470a 100644 --- a/src/dispatch/route/service.py +++ b/src/dispatch/route/service.py @@ -1,6 +1,5 @@ import json import logging -from typing import Any, List from dispatch.database.core import Base from dispatch.route.models import Recommendation, RecommendationMatch @@ -11,7 +10,7 @@ def get_resource_matches( *, db_session, project_id: int, class_instance: Base, model: Any -) -> List[RecommendationMatch]: +) -> list[RecommendationMatch]: """Fetches all matching model entities for the given class instance.""" # get all entities with an associated filter model_cls, model_state = model @@ -44,7 +43,7 @@ def get_resource_matches( return matched_resources -def get(*, db_session, project_id: int, class_instance: Base, models: List[Any]) -> Recommendation: +def get(*, db_session, project_id: int, class_instance: Base, models: list[Any]) -> Recommendation: """Get routed resources.""" matches = [] diff --git a/src/dispatch/search/fulltext/__init__.py b/src/dispatch/search/fulltext/__init__.py index beeac442b431..7a0150b8feaf 100644 --- a/src/dispatch/search/fulltext/__init__.py +++ b/src/dispatch/search/fulltext/__init__.py @@ -4,7 +4,6 @@ """ import os from functools import reduce -from typing import Any from sqlalchemy import event, inspect, func, desc, text, MetaData, Table, Index, orm from sqlalchemy.dialects.postgresql.base import RESERVED_WORDS diff --git a/src/dispatch/search/models.py b/src/dispatch/search/models.py index 39dd2a1c1037..a18ab78fa972 100644 --- a/src/dispatch/search/models.py +++ b/src/dispatch/search/models.py @@ -1,6 +1,5 @@ """Models for search functionality in the Dispatch application.""" -from typing import ClassVar from pydantic import ConfigDict, Field from dispatch.case.models import CaseRead diff --git a/src/dispatch/search/views.py b/src/dispatch/search/views.py index bd2dc101acdf..8ff9a73e00c8 100644 --- a/src/dispatch/search/views.py +++ b/src/dispatch/search/views.py @@ -1,4 +1,3 @@ -from typing import List from fastapi import APIRouter from fastapi.params import Query from starlette.responses import JSONResponse @@ -19,7 +18,7 @@ @router.get("", response_class=JSONResponse) def search( common: CommonParameters, - type: List[SearchTypes] = Query(..., alias="type[]"), + type: list[SearchTypes] = Query(..., alias="type[]"), ): """Perform a search.""" if common["query_str"]: diff --git a/src/dispatch/search_filter/models.py b/src/dispatch/search_filter/models.py index 8303e3580975..8068431a25be 100644 --- a/src/dispatch/search_filter/models.py +++ b/src/dispatch/search_filter/models.py @@ -1,5 +1,4 @@ from datetime import datetime -from typing import List, Optional from pydantic import Field @@ -47,30 +46,30 @@ class SearchFilter(Base, ProjectMixin, TimeStampMixin): # Pydantic models... class IndividualContactRead(DispatchBase): - id: Optional[PrimaryKey] + id: PrimaryKey | None name: str email: str class TeamRead(DispatchBase): - id: Optional[PrimaryKey] + id: PrimaryKey | None name: str class ServiceRead(DispatchBase): - id: Optional[PrimaryKey] + id: PrimaryKey | None name: str class NotificationRead(DispatchBase): - id: Optional[PrimaryKey] + id: PrimaryKey | None name: str class SearchFilterBase(DispatchBase): - description: Optional[str] = Field(None, nullable=True) - enabled: Optional[bool] - expression: List[dict] + description: str | None = Field(None, nullable=True) + enabled: bool | None + expression: list[dict] name: NameStr subject: SearchFilterSubject = SearchFilterSubject.incident @@ -85,15 +84,15 @@ class SearchFilterUpdate(SearchFilterBase): class SearchFilterRead(SearchFilterBase): id: PrimaryKey - created_at: Optional[datetime] = None - updated_at: Optional[datetime] = None - project: Optional[ProjectRead] - creator: Optional[UserRead] - individuals: Optional[List[IndividualContactRead]] = [] - notifications: Optional[List[NotificationRead]] = [] - services: Optional[List[ServiceRead]] = [] - teams: Optional[List[TeamRead]] = [] + created_at: datetime | None = None + updated_at: datetime | None = None + project: ProjectRead | None + creator: UserRead | None + individuals: list[IndividualContactRead | None] = [] + notifications: list[NotificationRead | None] = [] + services: list[ServiceRead | None] = [] + teams: list[TeamRead | None] = [] class SearchFilterPagination(Pagination): - items: List[SearchFilterRead] + items: list[SearchFilterRead] diff --git a/src/dispatch/search_filter/service.py b/src/dispatch/search_filter/service.py index 2fdf337f10fd..67ef809671cd 100644 --- a/src/dispatch/search_filter/service.py +++ b/src/dispatch/search_filter/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from sqlalchemy_filters import apply_filters @@ -9,12 +8,12 @@ from .models import SearchFilter, SearchFilterCreate, SearchFilterUpdate -def get(*, db_session, search_filter_id: int) -> Optional[SearchFilter]: +def get(*, db_session, search_filter_id: int) -> SearchFilter | None: """Gets a search filter by id.""" return db_session.query(SearchFilter).filter(SearchFilter.id == search_filter_id).first() -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[SearchFilter]: +def get_by_name(*, db_session, project_id: int, name: str) -> SearchFilter | None: """Gets a search filter by name.""" return ( db_session.query(SearchFilter) @@ -24,7 +23,7 @@ def get_by_name(*, db_session, project_id: int, name: str) -> Optional[SearchFil ) -def match(*, db_session, subject: str, filter_spec: List[dict], class_instance: Base): +def match(*, db_session, subject: str, filter_spec: list[dict], class_instance: Base): """Matches a class instance with a given search filter.""" table_name = get_table_name_by_class_instance(class_instance) diff --git a/src/dispatch/service/models.py b/src/dispatch/service/models.py index 11ddbabc658f..c6f8d686cdbd 100644 --- a/src/dispatch/service/models.py +++ b/src/dispatch/service/models.py @@ -1,5 +1,4 @@ from datetime import datetime -from typing import List, Optional from pydantic import Field from dispatch.models import EvergreenBase, EvergreenMixin, PrimaryKey @@ -43,30 +42,30 @@ class Service(Base, TimeStampMixin, ProjectMixin, EvergreenMixin): # Pydantic models... class ServiceBase(EvergreenBase): - description: Optional[str] = Field(None, nullable=True) - external_id: Optional[str] = Field(None, nullable=True) - health_metrics: Optional[bool] = None - is_active: Optional[bool] = None - name: Optional[str] = Field(None, nullable=True) - type: Optional[str] = Field(None, nullable=True) - shift_hours_type: Optional[int] = Field(24, nullable=True) + description: str | None = Field(None, nullable=True) + external_id: str | None = Field(None, nullable=True) + health_metrics: bool | None = None + is_active: bool | None = None + name: str | None = Field(None, nullable=True) + type: str | None = Field(None, nullable=True) + shift_hours_type: int | None = Field(24, nullable=True) class ServiceCreate(ServiceBase): - filters: Optional[List[SearchFilterRead]] = [] + filters: list[SearchFilterRead | None] = [] project: ProjectRead class ServiceUpdate(ServiceBase): - filters: Optional[List[SearchFilterRead]] = [] + filters: list[SearchFilterRead | None] = [] class ServiceRead(ServiceBase): id: PrimaryKey - filters: Optional[List[SearchFilterRead]] = [] - created_at: Optional[datetime] = None - updated_at: Optional[datetime] = None + filters: list[SearchFilterRead | None] = [] + created_at: datetime | None = None + updated_at: datetime | None = None class ServicePagination(Pagination): - items: List[ServiceRead] = [] + items: list[ServiceRead] = [] diff --git a/src/dispatch/service/service.py b/src/dispatch/service/service.py index 9e2b4e744537..6352d1f1dd4b 100644 --- a/src/dispatch/service/service.py +++ b/src/dispatch/service/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from pydantic import ValidationError @@ -10,22 +9,22 @@ from .models import Service, ServiceCreate, ServiceRead, ServiceUpdate -def get(*, db_session, service_id: int) -> Optional[Service]: +def get(*, db_session, service_id: int) -> Service | None: """Gets a service by id.""" return db_session.query(Service).filter(Service.id == service_id).first() -def get_by_external_id(*, db_session, external_id: str) -> Optional[Service]: +def get_by_external_id(*, db_session, external_id: str) -> Service | None: """Gets a service by external id (e.g. PagerDuty service id).""" return db_session.query(Service).filter(Service.external_id == external_id).first() -def get_all_by_external_ids(*, db_session, external_ids: List[str]) -> Optional[List[Service]]: +def get_all_by_external_ids(*, db_session, external_ids: list[str]) -> list[Service | None]: """Gets a service by external id (e.g. PagerDuty service id) and project id.""" return db_session.query(Service).filter(Service.external_id.in_(external_ids)).all() -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[Service]: +def get_by_name(*, db_session, project_id: int, name: str) -> Service | None: """Gets a service by its name.""" return ( db_session.query(Service) @@ -54,7 +53,7 @@ def get_by_name_or_raise(*, db_session, project_id, service_in: ServiceRead) -> def get_by_external_id_and_project_id( *, db_session, external_id: str, project_id: int -) -> Optional[Service]: +) -> Service | None: """Gets a service by external id (e.g. PagerDuty service id) and project id.""" return ( db_session.query(Service) @@ -86,7 +85,7 @@ def get_by_external_id_and_project_id_or_raise( return service -def get_overdue_evergreen_services(*, db_session, project_id: int) -> List[Optional[Service]]: +def get_overdue_evergreen_services(*, db_session, project_id: int) -> list[Service | None]: """Returns all services that have not had a recent evergreen notification.""" query = ( db_session.query(Service) @@ -99,7 +98,7 @@ def get_overdue_evergreen_services(*, db_session, project_id: int) -> List[Optio def get_by_external_id_and_project_name( *, db_session, external_id: str, project_name: str -) -> Optional[Service]: +) -> Service | None: """Gets a service by external id (e.g. PagerDuty service id) and project name.""" project = project_service.get_by_name_or_raise( db_session=db_session, project_in=ProjectRead(name=project_name) @@ -122,7 +121,7 @@ def get_all_by_status(*, db_session, is_active: bool): def get_all_by_type_and_status( *, db_session, service_type: str, is_active: bool -) -> List[Optional[Service]]: +) -> list[Service | None]: """Gets services by type and status.""" return ( db_session.query(Service) @@ -134,7 +133,7 @@ def get_all_by_type_and_status( def get_all_by_project_id_and_status( *, db_session, project_id: id, is_active: bool -) -> List[Optional[Service]]: +) -> list[Service | None]: """Gets services by project id and status.""" return ( db_session.query(Service) @@ -146,7 +145,7 @@ def get_all_by_project_id_and_status( def get_all_by_health_metrics( *, db_session, service_type: str, health_metrics: bool, project_id: int -) -> List[Optional[Service]]: +) -> list[Service | None]: """Gets all services based on the given health metrics value for a given project.""" return ( db_session.query(Service) diff --git a/src/dispatch/service/views.py b/src/dispatch/service/views.py index 18fa03404f2a..7f24aa5aec61 100644 --- a/src/dispatch/service/views.py +++ b/src/dispatch/service/views.py @@ -1,6 +1,5 @@ from fastapi import APIRouter, Body, HTTPException, status, Query from pydantic import ValidationError -from typing import List from sqlalchemy.exc import IntegrityError @@ -28,10 +27,10 @@ def get_services(common: CommonParameters): return search_filter_sort_paginate(model="Service", **common) -@router.get("/externalids", response_model=List[ServiceRead]) +@router.get("/externalids", response_model=list[ServiceRead]) def get_services_by_external_ids( db_session: DbSession, - ids: List[str] = Query(..., alias="ids[]"), + ids: list[str] = Query(..., alias="ids[]"), ): """Retrieves all services given list of external ids.""" return get_all_by_external_ids(db_session=db_session, external_ids=ids) diff --git a/src/dispatch/signal/models.py b/src/dispatch/signal/models.py index 8aececf63a1f..686e1359ccd0 100644 --- a/src/dispatch/signal/models.py +++ b/src/dispatch/signal/models.py @@ -1,6 +1,5 @@ import uuid from datetime import datetime -from typing import Any from pydantic import Field from sqlalchemy import ( diff --git a/src/dispatch/signal/service.py b/src/dispatch/signal/service.py index 9f641845aed5..774086d01c00 100644 --- a/src/dispatch/signal/service.py +++ b/src/dispatch/signal/service.py @@ -2,8 +2,6 @@ import logging import uuid from datetime import datetime, timedelta, timezone -from typing import Optional, Union -from collections import defaultdict from fastapi import HTTPException, status from pydantic import ValidationError @@ -59,7 +57,7 @@ def get_signal_engagement( *, db_session: Session, signal_engagement_id: int -) -> Optional[SignalEngagement]: +) -> SignalEngagement | None: """Gets a signal engagement by id.""" return ( db_session.query(SignalEngagement) @@ -70,7 +68,7 @@ def get_signal_engagement( def get_signal_engagement_by_name( *, db_session, project_id: int, name: str -) -> Optional[SignalEngagement]: +) -> SignalEngagement | None: """Gets a signal engagement by its name.""" return ( db_session.query(SignalEngagement) diff --git a/src/dispatch/signal/views.py b/src/dispatch/signal/views.py index 169bda610f1b..5599dd18bfb0 100644 --- a/src/dispatch/signal/views.py +++ b/src/dispatch/signal/views.py @@ -1,5 +1,4 @@ import logging -from typing import Union from fastapi import ( APIRouter, @@ -302,7 +301,7 @@ def return_signal_stats( @router.get("/{signal_id}/stats", response_model=SignalStats) def return_single_signal_stats( db_session: DbSession, - signal_id: Union[str, PrimaryKey], + signal_id: str | PrimaryKey, entity_value: str = Query(..., description="The name of the entity"), entity_type_id: int = Query(..., description="The ID of the entity type"), num_days: int = Query(None, description="The number of days to look back"), @@ -333,7 +332,7 @@ def return_single_signal_stats( @router.get("/{signal_id}", response_model=SignalRead) -def get_signal(db_session: DbSession, signal_id: Union[str, PrimaryKey]): +def get_signal(db_session: DbSession, signal_id: str | PrimaryKey): """Gets a signal by its id.""" signal = get_by_primary_or_external_id(db_session=db_session, signal_id=signal_id) if not signal: @@ -364,7 +363,7 @@ def create_signal(db_session: DbSession, signal_in: SignalCreate, current_user: ) def update_signal( db_session: DbSession, - signal_id: Union[str, PrimaryKey], + signal_id: str | PrimaryKey, signal_in: SignalUpdate, current_user: CurrentUser, ): @@ -405,7 +404,7 @@ def update_signal( response_model=None, dependencies=[Depends(PermissionsDependency([SensitiveProjectActionPermission]))], ) -def delete_signal(db_session: DbSession, signal_id: Union[str, PrimaryKey]): +def delete_signal(db_session: DbSession, signal_id: str | PrimaryKey): """Deletes a signal.""" signal = get_by_primary_or_external_id(db_session=db_session, signal_id=signal_id) if not signal: diff --git a/src/dispatch/storage/flows.py b/src/dispatch/storage/flows.py index aed50395ea9d..9fae1a582cb0 100644 --- a/src/dispatch/storage/flows.py +++ b/src/dispatch/storage/flows.py @@ -1,4 +1,3 @@ -from typing import TypeVar, List import logging from sqlalchemy.orm import Session @@ -16,10 +15,10 @@ log = logging.getLogger(__name__) -Subject = TypeVar("Subject", Case, Incident) +Subject = Case | Incident -def create_storage(subject: Subject, storage_members: List[str], db_session: Session): +def create_storage(subject: Subject, storage_members: list[str], db_session: Session): """Creates a storage.""" plugin = plugin_service.get_active_instance( db_session=db_session, project_id=subject.project.id, plugin_type="storage" @@ -108,7 +107,7 @@ def create_storage(subject: Subject, storage_members: List[str], db_session: Ses def update_storage( subject: Subject, storage_action: StorageAction, - storage_members: List[str], + storage_members: list[str], db_session: Session, ): """Updates an existing storage.""" diff --git a/src/dispatch/storage/service.py b/src/dispatch/storage/service.py index ea48edc6e0a3..d2f6a6b4678a 100644 --- a/src/dispatch/storage/service.py +++ b/src/dispatch/storage/service.py @@ -1,16 +1,15 @@ -from typing import Optional from sqlalchemy.orm import Session from .models import Storage, StorageCreate -def get(*, db_session: Session, storage_id: int) -> Optional[Storage]: +def get(*, db_session: Session, storage_id: int) -> Storage | None: """Gets a storage by its storage id.""" return db_session.query(Storage).filter(Storage.id == storage_id).one() -def get_by_resource_id(*, db_session: Session, resource_id: str) -> Optional[Storage]: +def get_by_resource_id(*, db_session: Session, resource_id: str) -> Storage | None: """Gets a storage by its resource id.""" return db_session.query(Storage).filter(Storage.resource_id == resource_id).one() diff --git a/src/dispatch/tag/models.py b/src/dispatch/tag/models.py index 92bc1549f2f2..382fdf98de44 100644 --- a/src/dispatch/tag/models.py +++ b/src/dispatch/tag/models.py @@ -1,4 +1,3 @@ -from typing import Optional, List from pydantic import Field from sqlalchemy import Column, Integer, String, Boolean, ForeignKey @@ -36,30 +35,30 @@ class Tag(Base, TimeStampMixin, ProjectMixin): # Pydantic models class TagBase(DispatchBase): - name: Optional[str] = Field(None, nullable=True) - source: Optional[str] = Field(None, nullable=True) - uri: Optional[str] = Field(None, nullable=True) - discoverable: Optional[bool] = True - external_id: Optional[str] = Field(None, nullable=True) - description: Optional[str] = Field(None, nullable=True) + name: str | None = Field(None, nullable=True) + source: str | None = Field(None, nullable=True) + uri: str | None = Field(None, nullable=True) + discoverable: bool | None = True + external_id: str | None = Field(None, nullable=True) + description: str | None = Field(None, nullable=True) class TagCreate(TagBase): - id: Optional[PrimaryKey] = None + id: PrimaryKey | None = None tag_type: TagTypeCreate project: ProjectRead class TagUpdate(TagBase): - id: Optional[PrimaryKey] = None - tag_type: Optional[TagTypeUpdate] = None + id: PrimaryKey | None = None + tag_type: TagTypeUpdate | None = None class TagRead(TagBase): id: PrimaryKey - tag_type: Optional[TagTypeRead] + tag_type: TagTypeRead | None project: ProjectRead class TagPagination(Pagination): - items: List[TagRead] + items: list[TagRead] diff --git a/src/dispatch/tag/recommender.py b/src/dispatch/tag/recommender.py index 8cedb85fa5f1..0e1105627d75 100644 --- a/src/dispatch/tag/recommender.py +++ b/src/dispatch/tag/recommender.py @@ -6,7 +6,6 @@ """ import logging -from typing import List, Any from collections import defaultdict import tempfile @@ -65,7 +64,7 @@ def correlate_with_every_tag(df, tag_a): return correlation_list -def get_unique_tags(items: List[Any]): +def get_unique_tags(items: list[Any]): """Get unique tags.""" unique_tags = {} for i in items: @@ -88,7 +87,7 @@ def create_correlation_dataframe(dataframe): return correlated_dataframe.set_index("index") -def create_boolean_dataframe(items: List[Any]): +def create_boolean_dataframe(items: list[Any]): """Create a boolean dataframe with tag and item data.""" unique_tags = get_unique_tags(items) boolean_df = pd.DataFrame(columns=unique_tags.values()) @@ -139,7 +138,7 @@ def find_highest_correlations(correlated_dataframe, recommendations): def get_recommendations( db_session: Session, - tag_ids: List[str], + tag_ids: list[str], organization_slug: str, project_slug: str, model_name: str, @@ -176,7 +175,7 @@ def get_recommendations( return tags -def build_model(items: List[Any], organization_slug: str, project_slug: str, model_name: str): +def build_model(items: list[Any], organization_slug: str, project_slug: str, model_name: str): """Builds the correlation dataframe for items.""" boolean_dataframe = create_boolean_dataframe(items) correlation_dataframe = create_correlation_dataframe(boolean_dataframe) diff --git a/src/dispatch/tag/scheduled.py b/src/dispatch/tag/scheduled.py index 97f3e0ac4c50..2bc6aba3aee6 100644 --- a/src/dispatch/tag/scheduled.py +++ b/src/dispatch/tag/scheduled.py @@ -7,7 +7,6 @@ import logging from schedule import every -from typing import NoReturn from sqlalchemy.orm import Session diff --git a/src/dispatch/tag/service.py b/src/dispatch/tag/service.py index 03b29cbe6ac3..238b7eac633f 100644 --- a/src/dispatch/tag/service.py +++ b/src/dispatch/tag/service.py @@ -1,5 +1,3 @@ -from typing import Optional - from pydantic import ValidationError from dispatch.project import service as project_service @@ -8,12 +6,12 @@ from .models import Tag, TagCreate, TagRead, TagUpdate -def get(*, db_session, tag_id: int) -> Optional[Tag]: +def get(*, db_session, tag_id: int): """Gets a tag by its id.""" return db_session.query(Tag).filter(Tag.id == tag_id).one_or_none() -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[Tag]: +def get_by_name(*, db_session, project_id: int, name: str): """Gets a tag by its project and name.""" return ( db_session.query(Tag) @@ -23,7 +21,7 @@ def get_by_name(*, db_session, project_id: int, name: str) -> Optional[Tag]: ) -def get_by_name_or_raise(*, db_session, project_id: int, tag_in: TagRead) -> TagRead: +def get_by_name_or_raise(*, db_session, project_id: int, tag_in: TagRead): """Returns the tag specified or raises ValidationError.""" tag = get_by_name(db_session=db_session, project_id=project_id, name=tag_in.name) diff --git a/src/dispatch/tag_type/models.py b/src/dispatch/tag_type/models.py index 238fb0c6866f..0c697a64fc34 100644 --- a/src/dispatch/tag_type/models.py +++ b/src/dispatch/tag_type/models.py @@ -1,4 +1,3 @@ -from typing import List, Optional from pydantic import Field from sqlalchemy import Column, Integer, String @@ -40,18 +39,18 @@ class TagType(Base, TimeStampMixin, ProjectMixin): # Pydantic models class TagTypeBase(DispatchBase): name: NameStr - exclusive: Optional[bool] = False - required: Optional[bool] = False - discoverable_case: Optional[bool] = True - discoverable_incident: Optional[bool] = True - discoverable_query: Optional[bool] = True - discoverable_signal: Optional[bool] = True - discoverable_source: Optional[bool] = True - discoverable_document: Optional[bool] = True - description: Optional[str] = Field(None, nullable=True) - color: Optional[str] = Field(None, nullable=True) - icon: Optional[str] = Field(None, nullable=True) - use_for_project_folder: Optional[bool] = False + exclusive: bool | None = False + required: bool | None = False + discoverable_case: bool | None = True + discoverable_incident: bool | None = True + discoverable_query: bool | None = True + discoverable_signal: bool | None = True + discoverable_source: bool | None = True + discoverable_document: bool | None = True + description: str | None = Field(None, nullable=True) + color: str | None = Field(None, nullable=True) + icon: str | None = Field(None, nullable=True) + use_for_project_folder: bool | None = False class TagTypeCreate(TagTypeBase): @@ -59,7 +58,7 @@ class TagTypeCreate(TagTypeBase): class TagTypeUpdate(TagTypeBase): - id: PrimaryKey = None + id: PrimaryKey | None = None class TagTypeRead(TagTypeBase): @@ -68,4 +67,4 @@ class TagTypeRead(TagTypeBase): class TagTypePagination(Pagination): - items: List[TagTypeRead] + items: list[TagTypeRead] diff --git a/src/dispatch/tag_type/service.py b/src/dispatch/tag_type/service.py index 5642d34bf5c5..cddd312fea33 100644 --- a/src/dispatch/tag_type/service.py +++ b/src/dispatch/tag_type/service.py @@ -1,5 +1,3 @@ -from typing import Optional - from pydantic import ValidationError from dispatch.project import service as project_service @@ -7,12 +5,12 @@ from .models import TagType, TagTypeCreate, TagTypeRead, TagTypeUpdate -def get(*, db_session, tag_type_id: int) -> Optional[TagType]: +def get(*, db_session, tag_type_id: int): """Gets a tag type by its id.""" return db_session.query(TagType).filter(TagType.id == tag_type_id).one_or_none() -def get_by_name(*, db_session, project_id: int, name: str) -> Optional[TagType]: +def get_by_name(*, db_session, project_id: int, name: str): """Gets a tag type by its name.""" return ( db_session.query(TagType) @@ -22,7 +20,7 @@ def get_by_name(*, db_session, project_id: int, name: str) -> Optional[TagType]: ) -def get_storage_tag_type_for_project(*, db_session, project_id) -> TagType | None: +def get_storage_tag_type_for_project(*, db_session, project_id): """Returns the storage tag type for a project.""" return ( db_session.query(TagType) @@ -32,7 +30,7 @@ def get_storage_tag_type_for_project(*, db_session, project_id) -> TagType | Non ) -def get_by_name_or_raise(*, db_session, project_id: int, tag_type_in: TagTypeRead) -> TagType: +def get_by_name_or_raise(*, db_session, project_id: int, tag_type_in: TagTypeRead): """Returns the tag_type specified or raises ValidationError.""" tag_type = get_by_name(db_session=db_session, project_id=project_id, name=tag_type_in.name) diff --git a/src/dispatch/task/flows.py b/src/dispatch/task/flows.py index a91bfec19f87..95c24bc80e21 100644 --- a/src/dispatch/task/flows.py +++ b/src/dispatch/task/flows.py @@ -10,7 +10,6 @@ import logging from collections import defaultdict from datetime import datetime -from typing import List from sqlalchemy.orm import Session @@ -40,7 +39,7 @@ def group_tasks_by_assignee(tasks): return grouped -def create_reminder(db_session: Session, assignee_email: str, tasks: List[Task], project_id: int): +def create_reminder(db_session: Session, assignee_email: str, tasks: list[Task], project_id: int): """Contains the logic for incident task reminders.""" # send email plugin = plugin_service.get_active_instance( @@ -94,7 +93,7 @@ def send_task_notification( incident: Incident, message_template: str, creator: Participant, - assignees: List[Participant], + assignees: list[Participant], description: str, weblink: str, db_session: Session, diff --git a/src/dispatch/task/models.py b/src/dispatch/task/models.py index 9cae8c461476..32136802033b 100644 --- a/src/dispatch/task/models.py +++ b/src/dispatch/task/models.py @@ -1,5 +1,4 @@ from datetime import datetime, timedelta -from typing import List, Optional from pydantic import Field from sqlalchemy import ( @@ -91,40 +90,40 @@ def __declare_last__(cls): # Pydantic models class TaskBase(ResourceBase): - assignees: List[Optional[ParticipantRead]] = [] - created_at: Optional[datetime] - creator: Optional[ParticipantRead] - description: Optional[str] = Field(None, nullable=True) + assignees: list[ParticipantRead | None] = [] + created_at: datetime | None + creator: ParticipantRead | None + description: str | None = Field(None, nullable=True) incident: IncidentReadBasic - owner: Optional[ParticipantRead] - priority: Optional[str] = Field(None, nullable=True) - resolve_by: Optional[datetime] - resolved_at: Optional[datetime] - resource_id: Optional[str] = Field(None, nullable=True) - source: Optional[str] = Field(None, nullable=True) + owner: ParticipantRead | None + priority: str | None = Field(None, nullable=True) + resolve_by: datetime | None + resolved_at: datetime | None + resource_id: str | None = Field(None, nullable=True) + source: str | None = Field(None, nullable=True) status: TaskStatus = TaskStatus.open - updated_at: Optional[datetime] + updated_at: datetime | None class TaskCreate(TaskBase): - assignees: List[Optional[ParticipantUpdate]] = [] - creator: Optional[ParticipantUpdate] - owner: Optional[ParticipantUpdate] - resource_type: Optional[str] + assignees: list[ParticipantUpdate | None] = [] + creator: ParticipantUpdate | None + owner: ParticipantUpdate | None + resource_type: str | None status: TaskStatus = TaskStatus.open class TaskUpdate(TaskBase): - assignees: List[Optional[ParticipantUpdate]] = [] - owner: Optional[ParticipantUpdate] - creator: Optional[ParticipantUpdate] + assignees: list[ParticipantUpdate | None] = [] + owner: ParticipantUpdate | None + creator: ParticipantUpdate | None class TaskRead(TaskBase): id: PrimaryKey - project: Optional[ProjectRead] - ticket: Optional[TicketRead] = None + project: ProjectRead | None + ticket: TicketRead | None = None class TaskPagination(Pagination): - items: List[TaskRead] = [] + items: list[TaskRead] = [] diff --git a/src/dispatch/task/service.py b/src/dispatch/task/service.py index 150236de743a..acb291f0ec9b 100644 --- a/src/dispatch/task/service.py +++ b/src/dispatch/task/service.py @@ -1,5 +1,4 @@ from datetime import datetime, timedelta -from typing import List, Optional from sqlalchemy import or_ @@ -17,29 +16,29 @@ from .models import Task, TaskCreate, TaskUpdate -def get(*, db_session, task_id: int) -> Optional[Task]: +def get(*, db_session, task_id: int) -> Task | None: """Get a single task by id.""" return db_session.query(Task).filter(Task.id == task_id).first() -def get_by_resource_id(*, db_session, resource_id: str) -> Optional[Task]: +def get_by_resource_id(*, db_session, resource_id: str) -> Task | None: """Get a single task by resource id.""" return db_session.query(Task).filter(Task.resource_id == resource_id).one_or_none() -def get_all(*, db_session) -> List[Optional[Task]]: +def get_all(*, db_session) -> list[Task | None]: """Return all tasks.""" return db_session.query(Task) -def get_all_by_incident_id(*, db_session, incident_id: int) -> List[Optional[Task]]: +def get_all_by_incident_id(*, db_session, incident_id: int) -> list[Task | None]: """Get all tasks by incident id.""" return db_session.query(Task).filter(Task.incident_id == incident_id) def get_all_by_incident_id_and_status( *, db_session, incident_id: int, status: str -) -> List[Optional[Task]]: +) -> list[Task | None]: """Get all tasks by incident id and status.""" return ( db_session.query(Task) @@ -49,7 +48,7 @@ def get_all_by_incident_id_and_status( ) -def get_overdue_tasks(*, db_session, project_id: int) -> List[Optional[Task]]: +def get_overdue_tasks(*, db_session, project_id: int) -> list[Task | None]: """Returns all tasks that have not been resolved and are past due date.""" # TODO ensure that we don't send reminders more than their interval return ( diff --git a/src/dispatch/task/views.py b/src/dispatch/task/views.py index fb09aff989c6..3a7eedddf01a 100644 --- a/src/dispatch/task/views.py +++ b/src/dispatch/task/views.py @@ -1,5 +1,4 @@ import json -from typing import List from fastapi import APIRouter, HTTPException, Query, status @@ -25,7 +24,7 @@ @router.get("", summary="Retrieve a list of all tasks.") -def get_tasks(common: CommonParameters, include: List[str] = Query([], alias="include[]")): +def get_tasks(common: CommonParameters, include: list[str] = Query([], alias="include[]")): """Retrieve all tasks.""" pagination = search_filter_sort_paginate(model="Task", **common) diff --git a/src/dispatch/team/models.py b/src/dispatch/team/models.py index 539c150cff96..861f5925aad3 100644 --- a/src/dispatch/team/models.py +++ b/src/dispatch/team/models.py @@ -1,5 +1,4 @@ from datetime import datetime -from typing import List, Optional from pydantic import Field from sqlalchemy import Column, ForeignKey, Integer, PrimaryKeyConstraint, String, Table @@ -54,24 +53,24 @@ class TeamContact(Base, ContactMixin, ProjectMixin, EvergreenMixin): class TeamContactBase(ContactBase, EvergreenBase): name: NameStr - notes: Optional[str] = Field(None, nullable=True) + notes: str | None = Field(None, nullable=True) class TeamContactCreate(TeamContactBase): - filters: Optional[List[SearchFilterRead]] = [] + filters: list[SearchFilterRead | None] = [] project: ProjectRead class TeamContactUpdate(TeamContactBase): - filters: Optional[List[SearchFilterRead]] = [] + filters: list[SearchFilterRead | None] = [] class TeamContactRead(TeamContactBase): id: PrimaryKey - filters: Optional[List[SearchFilterRead]] = [] + filters: list[SearchFilterRead | None] = [] created_at: datetime updated_at: datetime class TeamPagination(Pagination): - items: List[TeamContactRead] = [] + items: list[TeamContactRead] = [] diff --git a/src/dispatch/team/service.py b/src/dispatch/team/service.py index d13025a61f8d..72c3c788d236 100644 --- a/src/dispatch/team/service.py +++ b/src/dispatch/team/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from dispatch.project import service as project_service from dispatch.project.models import Project @@ -7,11 +6,11 @@ from .models import TeamContact, TeamContactCreate, TeamContactUpdate -def get(*, db_session, team_contact_id: int) -> Optional[TeamContact]: +def get(*, db_session, team_contact_id: int) -> TeamContact | None: return db_session.query(TeamContact).filter(TeamContact.id == team_contact_id).first() -def get_by_email(*, db_session, email: str, project_id: int) -> Optional[TeamContact]: +def get_by_email(*, db_session, email: str, project_id: int) -> TeamContact | None: return ( db_session.query(TeamContact) .filter(TeamContact.email == email) @@ -20,7 +19,7 @@ def get_by_email(*, db_session, email: str, project_id: int) -> Optional[TeamCon ) -def get_all(*, db_session) -> List[Optional[TeamContact]]: +def get_all(*, db_session) -> list[TeamContact | None]: return db_session.query(TeamContact) @@ -34,7 +33,7 @@ def get_or_create(*, db_session, email: str, project: Project, **kwargs) -> Team return contact -def get_overdue_evergreen_teams(*, db_session, project_id: int) -> List[Optional[TeamContact]]: +def get_overdue_evergreen_teams(*, db_session, project_id: int) -> list[TeamContact | None]: """Returns all teams that have not had a recent evergreen notification.""" query = ( db_session.query(TeamContact) @@ -64,7 +63,7 @@ def create(*, db_session, team_contact_in: TeamContactCreate) -> TeamContact: return team -def create_all(*, db_session, team_contacts_in: List[TeamContactCreate]) -> List[TeamContact]: +def create_all(*, db_session, team_contacts_in: list[TeamContactCreate]) -> list[TeamContact]: contacts = [TeamContact(**t.dict()) for t in team_contacts_in] db_session.bulk_save_objects(contacts) db_session.commit() diff --git a/src/dispatch/term/models.py b/src/dispatch/term/models.py index 6094f3a11808..1a9411e4ad75 100644 --- a/src/dispatch/term/models.py +++ b/src/dispatch/term/models.py @@ -1,4 +1,3 @@ -from typing import List, Optional from pydantic import Field from sqlalchemy import Column, Integer, String, Boolean @@ -32,24 +31,24 @@ class Term(Base, ProjectMixin): # Pydantic models... class TermBase(DispatchBase): - id: Optional[PrimaryKey] = None - text: Optional[str] = Field(None, nullable=True) - discoverable: Optional[bool] = True + id: PrimaryKey | None = None + text: str | None = Field(None, nullable=True) + discoverable: bool | None = True class TermCreate(TermBase): - definitions: Optional[List[DefinitionRead]] = [] + definitions: list[DefinitionRead | None] = [] project: ProjectRead class TermUpdate(TermBase): - definitions: Optional[List[DefinitionRead]] = [] + definitions: list[DefinitionRead | None] = [] class TermRead(TermBase): id: PrimaryKey - definitions: Optional[List[DefinitionRead]] = [] + definitions: list[DefinitionRead | None] = [] class TermPagination(Pagination): - items: List[TermRead] = [] + items: list[TermRead] = [] diff --git a/src/dispatch/term/service.py b/src/dispatch/term/service.py index 709ef78cba98..a7a891e1e028 100644 --- a/src/dispatch/term/service.py +++ b/src/dispatch/term/service.py @@ -1,4 +1,3 @@ -from typing import Optional from dispatch.definition import service as definition_service from dispatch.project import service as project_service @@ -6,11 +5,11 @@ from .models import Term, TermCreate, TermUpdate -def get(*, db_session, term_id: int) -> Optional[Term]: +def get(*, db_session, term_id: int) -> Term | None: return db_session.query(Term).filter(Term.id == term_id).first() -def get_by_text(*, db_session, text: str) -> Optional[Term]: +def get_by_text(*, db_session, text: str) -> Term | None: return db_session.query(Term).filter(Term.text == text).first() diff --git a/src/dispatch/ticket/service.py b/src/dispatch/ticket/service.py index de94978a5c5f..92ceb5e6fdeb 100644 --- a/src/dispatch/ticket/service.py +++ b/src/dispatch/ticket/service.py @@ -1,21 +1,20 @@ -from typing import Optional from sqlalchemy.orm import Session from .models import Ticket, TicketCreate -def get(*, db_session: Session, ticket_id: int) -> Optional[Ticket]: +def get(*, db_session: Session, ticket_id: int) -> Ticket | None: """Fetch a ticket by its ticket id.""" return db_session.query(Ticket).filter(Ticket.id == ticket_id).one() -def get_by_resource_id(*, db_session: Session, resource_id: str) -> Optional[Ticket]: +def get_by_resource_id(*, db_session: Session, resource_id: str) -> Ticket | None: """Fetch a ticket by its resource id.""" return db_session.query(Ticket).filter(Ticket.resource_id == resource_id).one() -def get_by_weblink(*, db_session: Session, weblink: str) -> Optional[Ticket]: +def get_by_weblink(*, db_session: Session, weblink: str) -> Ticket | None: """Fetch a ticket by its weblink.""" return db_session.query(Ticket).filter(Ticket.weblink == weblink).one_or_none() diff --git a/src/dispatch/workflow/service.py b/src/dispatch/workflow/service.py index 477442c6cda9..a55c50ebcacb 100644 --- a/src/dispatch/workflow/service.py +++ b/src/dispatch/workflow/service.py @@ -1,4 +1,3 @@ -from typing import List, Optional from sqlalchemy.orm import Session from sqlalchemy.sql.expression import true @@ -26,12 +25,12 @@ from pydantic import ValidationError -def get(*, db_session, workflow_id: int) -> Optional[Workflow]: +def get(*, db_session, workflow_id: int) -> Workflow | None: """Returns a workflow based on the given workflow id.""" return db_session.query(Workflow).filter(Workflow.id == workflow_id).one_or_none() -def get_by_name(*, db_session, name: str) -> Optional[Workflow]: +def get_by_name(*, db_session, name: str) -> Workflow | None: """Returns a workflow based on the given workflow name.""" return db_session.query(Workflow).filter(Workflow.name == name).one_or_none() @@ -49,12 +48,12 @@ def get_by_name_or_raise(*, db_session: Session, workflow_in: WorkflowRead) -> W return workflow -def get_all(*, db_session) -> List[Optional[Workflow]]: +def get_all(*, db_session) -> list[Workflow | None]: """Returns all workflows.""" return db_session.query(Workflow) -def get_enabled(*, db_session, project_id: int = None) -> List[Optional[Workflow]]: +def get_enabled(*, db_session, project_id: int = None) -> list[Workflow | None]: """Fetches all enabled workflows.""" if project_id: return ( @@ -117,7 +116,7 @@ def get_instance(*, db_session, instance_id: int) -> WorkflowInstance: ) -def get_running_instances(*, db_session, project_id: int) -> List[WorkflowInstance]: +def get_running_instances(*, db_session, project_id: int) -> list[WorkflowInstance]: """Fetches all running instances.""" return ( db_session.query(WorkflowInstance) From 67931dd9a389aee153dc90c69ed49b9441170027 Mon Sep 17 00:00:00 2001 From: Marc Vilanova Date: Thu, 8 May 2025 10:06:10 -0700 Subject: [PATCH 2/5] removes Field --- src/dispatch/auth/models.py | 20 +++++++------- src/dispatch/case/priority/models.py | 6 ++--- src/dispatch/case/severity/models.py | 6 ++--- src/dispatch/case_cost_type/models.py | 4 +-- src/dispatch/cost_model/models.py | 2 +- src/dispatch/data/alert/models.py | 6 ++--- src/dispatch/data/query/models.py | 6 ++--- .../data/source/data_format/models.py | 2 +- .../data/source/environment/models.py | 2 +- src/dispatch/data/source/models.py | 16 ++++++------ src/dispatch/data/source/status/models.py | 2 +- src/dispatch/data/source/transport/models.py | 2 +- src/dispatch/data/source/type/models.py | 2 +- src/dispatch/definition/models.py | 4 +-- src/dispatch/email_templates/models.py | 10 +++---- src/dispatch/entity/models.py | 18 ++++++------- src/dispatch/entity_type/models.py | 10 +++---- src/dispatch/feedback/incident/models.py | 4 +-- src/dispatch/feedback/service/models.py | 2 +- src/dispatch/forms/models.py | 14 +++++----- src/dispatch/forms/type/models.py | 10 +++---- src/dispatch/notification/models.py | 4 +-- src/dispatch/participant/models.py | 16 +++++------- src/dispatch/plugin/models.py | 4 +-- src/dispatch/project/models.py | 26 +++++++++---------- src/dispatch/search_filter/models.py | 4 +-- src/dispatch/service/models.py | 8 +++--- src/dispatch/tag/models.py | 12 ++++----- src/dispatch/tag_type/models.py | 8 +++--- src/dispatch/task/models.py | 10 +++---- src/dispatch/team/models.py | 4 +-- src/dispatch/term/models.py | 4 +-- 32 files changed, 108 insertions(+), 140 deletions(-) diff --git a/src/dispatch/auth/models.py b/src/dispatch/auth/models.py index 8dee241c29d8..c5f3d30267ed 100644 --- a/src/dispatch/auth/models.py +++ b/src/dispatch/auth/models.py @@ -7,7 +7,7 @@ import bcrypt from jose import jwt -from pydantic import field_validator, Field +from pydantic import field_validator from pydantic import EmailStr from sqlalchemy import DateTime, Column, String, LargeBinary, Integer, Boolean @@ -131,14 +131,14 @@ class UserProject(DispatchBase): """Pydantic model for a user's project membership.""" project: ProjectRead default: bool | None = False - role: str | None = Field(None, nullable=True) + role: str | None = None class UserOrganization(DispatchBase): """Pydantic model for a user's organization membership.""" organization: OrganizationRead default: bool | None = False - role: str | None = Field(None, nullable=True) + role: str | None = None class UserBase(DispatchBase): @@ -171,7 +171,7 @@ def password_required(cls, v): class UserRegister(UserLogin): """Pydantic model for user registration data.""" - password: str = Field(None, nullable=True) + password: str = None @field_validator("password", mode="before") @classmethod @@ -184,13 +184,13 @@ def password_required(cls, v): class UserLoginResponse(DispatchBase): """Pydantic model for the response after user login.""" projects: list[UserProject] | None - token: str | None = Field(None, nullable=True) + token: str | None = None class UserRead(UserBase): """Pydantic model for reading user data.""" id: PrimaryKey - role: str | None = Field(None, nullable=True) + role: str | None = None experimental_features: bool | None @@ -200,7 +200,7 @@ class UserUpdate(DispatchBase): projects: list[UserProject] | None organizations: list[UserOrganization] | None experimental_features: bool | None - role: str | None = Field(None, nullable=True) + role: str | None = None class UserPasswordUpdate(DispatchBase): @@ -249,10 +249,10 @@ def validate_password(cls, v): class UserCreate(DispatchBase): """Pydantic model for creating a new user.""" email: EmailStr - password: str | None = Field(None, nullable=True) + password: str | None = None projects: list[UserProject] | None organizations: list[UserOrganization] | None - role: str | None = Field(None, nullable=True) + role: str | None = None @field_validator("password", mode="before") @classmethod @@ -263,7 +263,7 @@ def hash(cls, v): class UserRegisterResponse(DispatchBase): """Pydantic model for the response after user registration.""" - token: str | None = Field(None, nullable=True) + token: str | None = None class UserPagination(Pagination): diff --git a/src/dispatch/case/priority/models.py b/src/dispatch/case/priority/models.py index 057ea0a9f082..527aa87614fa 100644 --- a/src/dispatch/case/priority/models.py +++ b/src/dispatch/case/priority/models.py @@ -1,6 +1,4 @@ """Models and schemas for the Dispatch case priority system.""" -from pydantic import Field - from sqlalchemy import Column, Integer, String, Boolean from sqlalchemy.sql.schema import UniqueConstraint from sqlalchemy.event import listen @@ -37,10 +35,10 @@ class CasePriority(Base, ProjectMixin): # Pydantic models class CasePriorityBase(DispatchBase): """Base Pydantic model for case priority data.""" - color: str | None = Field(None, nullable=True) + color: str | None = None default: bool | None page_assignee: bool | None - description: str | None = Field(None, nullable=True) + description: str | None = None enabled: bool | None name: NameStr project: ProjectRead | None diff --git a/src/dispatch/case/severity/models.py b/src/dispatch/case/severity/models.py index 8a50b9dbcad4..0c9a1e213d17 100644 --- a/src/dispatch/case/severity/models.py +++ b/src/dispatch/case/severity/models.py @@ -1,7 +1,5 @@ """Models and schemas for the Dispatch case severity system.""" -from pydantic import Field - from sqlalchemy import Column, Integer, String, Boolean from sqlalchemy.sql.schema import UniqueConstraint from sqlalchemy.event import listen @@ -41,9 +39,9 @@ class CaseSeverity(Base, ProjectMixin): # Pydantic models class CaseSeverityBase(DispatchBase): """Base Pydantic model for case severity data.""" - color: str | None = Field(None, nullable=True) + color: str | None = None default: bool | None - description: str | None = Field(None, nullable=True) + description: str | None = None enabled: bool | None name: NameStr project: ProjectRead | None diff --git a/src/dispatch/case_cost_type/models.py b/src/dispatch/case_cost_type/models.py index eafe4326354c..9157403e6db3 100644 --- a/src/dispatch/case_cost_type/models.py +++ b/src/dispatch/case_cost_type/models.py @@ -37,8 +37,8 @@ class CaseCostType(Base, TimeStampMixin, ProjectMixin): # Pydantic Models class CaseCostTypeBase(DispatchBase): name: NameStr - description: str | None = Field(None, nullable=True) - category: str | None = Field(None, nullable=True) + description: str | None = None + category: str | None = None details: dict | None = {} created_at: datetime | None editable: bool | None diff --git a/src/dispatch/cost_model/models.py b/src/dispatch/cost_model/models.py index ba4616ead6e7..ad25807b07e1 100644 --- a/src/dispatch/cost_model/models.py +++ b/src/dispatch/cost_model/models.py @@ -86,7 +86,7 @@ class CostModelActivityUpdate(CostModelActivityBase): class CostModelBase(DispatchBase): name: NameStr - description: str | None = Field(None, nullable=True) + description: str | None = None enabled: bool | None = Field(True, nullable=True) created_at: datetime | None = None updated_at: datetime | None = None diff --git a/src/dispatch/data/alert/models.py b/src/dispatch/data/alert/models.py index 7ecb74d25e18..19a98ac1dc62 100644 --- a/src/dispatch/data/alert/models.py +++ b/src/dispatch/data/alert/models.py @@ -20,9 +20,9 @@ class Alert(Base, TimeStampMixin): # Pydantic models class AlertBase(DispatchBase): name: str | None = Field(None, nullable=False) - description: str | None = Field(None, nullable=True) - originator: str | None = Field(None, nullable=True) - external_link: str | None = Field(None, nullable=True) + description: str | None = None + originator: str | None = None + external_link: str | None = None class AlertCreate(AlertBase): diff --git a/src/dispatch/data/query/models.py b/src/dispatch/data/query/models.py index 5733fdf52665..240b9bd887a2 100644 --- a/src/dispatch/data/query/models.py +++ b/src/dispatch/data/query/models.py @@ -50,9 +50,9 @@ class Query(Base, TimeStampMixin, ProjectMixin): # Pydantic models class QueryBase(DispatchBase): name: str | None = Field(None, nullable=False) - description: str | None = Field(None, nullable=True) - language: str | None = Field(None, nullable=True) - text: str | None = Field(None, nullable=True) + description: str | None = None + language: str | None = None + text: str | None = None tags: list[TagRead | None] = [] source: SourceRead project: ProjectRead diff --git a/src/dispatch/data/source/data_format/models.py b/src/dispatch/data/source/data_format/models.py index d16b07cab94b..2706ffb0acd1 100644 --- a/src/dispatch/data/source/data_format/models.py +++ b/src/dispatch/data/source/data_format/models.py @@ -24,7 +24,7 @@ class SourceDataFormat(Base, ProjectMixin): class SourceDataFormatBase(DispatchBase): name: str | None = Field(None, nullable=False) - description: str | None = Field(None, nullable=True) + description: str | None = None class SourceDataFormatRead(SourceDataFormatBase): diff --git a/src/dispatch/data/source/environment/models.py b/src/dispatch/data/source/environment/models.py index 81aeafe19e97..68a57c17837c 100644 --- a/src/dispatch/data/source/environment/models.py +++ b/src/dispatch/data/source/environment/models.py @@ -24,7 +24,7 @@ class SourceEnvironment(Base, ProjectMixin): class SourceEnvironmentBase(DispatchBase): name: str | None = Field(None, nullable=False) - description: str | None = Field(None, nullable=True) + description: str | None = None class SourceEnvironmentRead(SourceEnvironmentBase): diff --git a/src/dispatch/data/source/models.py b/src/dispatch/data/source/models.py index 96ab6d7a3183..d651a9351a44 100644 --- a/src/dispatch/data/source/models.py +++ b/src/dispatch/data/source/models.py @@ -111,7 +111,7 @@ class Link(DispatchBase): # Pydantic models class SourceBase(DispatchBase): name: str | None = Field(None, nullable=False) - description: str | None = Field(None, nullable=True) + description: str | None = None data_last_loaded_at: datetime | None = Field(None, nullable=True, title="Last Loaded") sampling_rate: int | None = Field( None, @@ -121,12 +121,12 @@ class SourceBase(DispatchBase): gt=1, description="Rate at which data is sampled (as a percentage) 100% meaning all data is captured.", ) - source_schema: str | None = Field(None, nullable=True) - documentation: str | None = Field(None, nullable=True) - retention: int | None = Field(None, nullable=True) - delay: int | None = Field(None, nullable=True) - size: int | None = Field(None, nullable=True) - external_id: str | None = Field(None, nullable=True) + source_schema: str | None = None + documentation: str | None = None + retention: int | None = None + delay: int | None = None + size: int | None = None + external_id: str | None = None aggregated: bool | None = Field(False, nullable=True) links: list[Link | None] = Field(default_factory=list) tags: list[TagRead | None] = [] @@ -134,7 +134,7 @@ class SourceBase(DispatchBase): queries: list[QueryReadMinimal | None] = [] alerts: list[AlertRead | None] = [] cost: float | None - owner: ServiceRead | None = Field(None, nullable=True) + owner: ServiceRead | None = None source_type: SourceTypeRead | None source_environment: SourceEnvironmentRead | None source_data_format: SourceDataFormatRead | None diff --git a/src/dispatch/data/source/status/models.py b/src/dispatch/data/source/status/models.py index fc7a8314dbeb..4bd72da942ca 100644 --- a/src/dispatch/data/source/status/models.py +++ b/src/dispatch/data/source/status/models.py @@ -24,7 +24,7 @@ class SourceStatus(Base, ProjectMixin): class SourceStatusBase(DispatchBase): name: str | None = Field(None, nullable=False) - description: str | None = Field(None, nullable=True) + description: str | None = None class SourceStatusRead(SourceStatusBase): diff --git a/src/dispatch/data/source/transport/models.py b/src/dispatch/data/source/transport/models.py index ed7b0024a2fd..7d675ae97127 100644 --- a/src/dispatch/data/source/transport/models.py +++ b/src/dispatch/data/source/transport/models.py @@ -24,7 +24,7 @@ class SourceTransport(Base, ProjectMixin): class SourceTransportBase(DispatchBase): name: str | None = Field(None, nullable=False) - description: str | None = Field(None, nullable=True) + description: str | None = None class SourceTransportRead(SourceTransportBase): diff --git a/src/dispatch/data/source/type/models.py b/src/dispatch/data/source/type/models.py index b7271097abbe..c69f7e3362ca 100644 --- a/src/dispatch/data/source/type/models.py +++ b/src/dispatch/data/source/type/models.py @@ -24,7 +24,7 @@ class SourceType(Base, ProjectMixin): class SourceTypeBase(DispatchBase): name: str | None = Field(None, nullable=False) - description: str | None = Field(None, nullable=True) + description: str | None = None class SourceTypeRead(SourceTypeBase): diff --git a/src/dispatch/definition/models.py b/src/dispatch/definition/models.py index c4043ce71ae2..e3afba53e314 100644 --- a/src/dispatch/definition/models.py +++ b/src/dispatch/definition/models.py @@ -1,5 +1,3 @@ -from pydantic import Field - from sqlalchemy import Table, Column, Integer, String, ForeignKey, PrimaryKeyConstraint from sqlalchemy.orm import relationship from sqlalchemy.sql.schema import UniqueConstraint @@ -51,7 +49,7 @@ class DefinitionTerm(DispatchBase): # Pydantic models... class DefinitionBase(DispatchBase): text: str - source: str | None = Field(None, nullable=True) + source: str | None = None class DefinitionCreate(DefinitionBase): diff --git a/src/dispatch/email_templates/models.py b/src/dispatch/email_templates/models.py index f8dcaef13814..d5d75217a5ae 100644 --- a/src/dispatch/email_templates/models.py +++ b/src/dispatch/email_templates/models.py @@ -1,6 +1,4 @@ from datetime import datetime -from pydantic import Field - from sqlalchemy import Column, Integer, String, Boolean, UniqueConstraint from dispatch.database.core import Base @@ -21,10 +19,10 @@ class EmailTemplates(TimeStampMixin, ProjectMixin, Base): # Pydantic models class EmailTemplatesBase(DispatchBase): - email_template_type: str | None = Field(None, nullable=True) - welcome_text: str | None = Field(None, nullable=True) - welcome_body: str | None = Field(None, nullable=True) - components: str | None = Field(None, nullable=True) + email_template_type: str | None = None + welcome_text: str | None = None + welcome_body: str | None = None + components: str | None = None enabled: bool | None diff --git a/src/dispatch/entity/models.py b/src/dispatch/entity/models.py index 4d0aeb50e5cf..39cac0b05e05 100644 --- a/src/dispatch/entity/models.py +++ b/src/dispatch/entity/models.py @@ -1,5 +1,3 @@ -from pydantic import Field - from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import relationship from sqlalchemy.sql.schema import UniqueConstraint @@ -49,10 +47,10 @@ class Entity(Base, TimeStampMixin, ProjectMixin): # Pydantic models class EntityBase(DispatchBase): - name: str | None = Field(None, nullable=True) - source: str | None = Field(None, nullable=True) - value: str | None = Field(None, nullable=True) - description: str | None = Field(None, nullable=True) + name: str | None = None + source: str | None = None + value: str | None = None + description: str | None = None class EntityCreate(EntityBase): @@ -77,10 +75,10 @@ class EntityRead(EntityBase): class EntityReadMinimal(DispatchBase): id: PrimaryKey - name: str | None = Field(None, nullable=True) - source: str | None = Field(None, nullable=True) - value: str | None = Field(None, nullable=True) - description: str | None = Field(None, nullable=True) + name: str | None = None + source: str | None = None + value: str | None = None + description: str | None = None entity_type: EntityTypeReadMinimal | None diff --git a/src/dispatch/entity_type/models.py b/src/dispatch/entity_type/models.py index 8a338239206f..925db27f40a9 100644 --- a/src/dispatch/entity_type/models.py +++ b/src/dispatch/entity_type/models.py @@ -55,12 +55,12 @@ class SignalRead(DispatchBase): class EntityTypeBase(DispatchBase): name: NameStr | None - description: str | None = Field(None, nullable=True) - jpath: str | None = Field(None, nullable=True) + description: str | None = None + jpath: str | None = None scope: EntityScopeEnum | None = Field(EntityScopeEnum.single, nullable=False) enabled: bool | None signals: list[SignalRead | None] = Field([], nullable=True) - regular_expression: str | None = Field(None, nullable=True) + regular_expression: str | None = None class EntityTypeCreate(EntityTypeBase): @@ -80,10 +80,10 @@ class EntityTypeRead(EntityTypeBase): class EntityTypeReadMinimal(DispatchBase): id: PrimaryKey name: NameStr - description: str | None = Field(None, nullable=True) + description: str | None = None scope: EntityScopeEnum enabled: bool | None - regular_expression: str | None = Field(None, nullable=True) + regular_expression: str | None = None class EntityTypePagination(Pagination): diff --git a/src/dispatch/feedback/incident/models.py b/src/dispatch/feedback/incident/models.py index 9f56f415415b..865736d2ee63 100644 --- a/src/dispatch/feedback/incident/models.py +++ b/src/dispatch/feedback/incident/models.py @@ -1,6 +1,4 @@ from datetime import datetime -from pydantic import Field - from sqlalchemy import Column, Integer, ForeignKey from sqlalchemy_utils import TSVectorType @@ -43,7 +41,7 @@ class Feedback(TimeStampMixin, FeedbackMixin, ProjectMixin, Base): class FeedbackBase(DispatchBase): created_at: datetime | None = None rating: FeedbackRating = FeedbackRating.very_satisfied - feedback: str | None = Field(None, nullable=True) + feedback: str | None = None incident: IncidentReadBasic | None = None case: CaseReadMinimal | None = None participant: ParticipantRead | None = None diff --git a/src/dispatch/feedback/service/models.py b/src/dispatch/feedback/service/models.py index c18b8e9b822f..0da24e10440b 100644 --- a/src/dispatch/feedback/service/models.py +++ b/src/dispatch/feedback/service/models.py @@ -39,7 +39,7 @@ class ServiceFeedback(TimeStampMixin, FeedbackMixin, Base): # Pydantic models class ServiceFeedbackBase(DispatchBase): - feedback: str | None = Field(None, nullable=True) + feedback: str | None = None hours: float | None individual: IndividualContactReadMinimal | None rating: ServiceFeedbackRating = ServiceFeedbackRating.little_effort diff --git a/src/dispatch/forms/models.py b/src/dispatch/forms/models.py index 8fb35069d7e4..024a320c3907 100644 --- a/src/dispatch/forms/models.py +++ b/src/dispatch/forms/models.py @@ -1,6 +1,4 @@ from datetime import datetime -from pydantic import Field - from sqlalchemy import Column, Integer, ForeignKey, String from sqlalchemy.orm import relationship @@ -40,14 +38,14 @@ class Forms(TimeStampMixin, ProjectMixin, Base): class FormsBase(DispatchBase): form_type: FormsTypeRead | None creator: IndividualContactReadMinimal | None - form_data: str | None = Field(None, nullable=True) - attorney_form_data: str | None = Field(None, nullable=True) - status: str | None = Field(None, nullable=True) - attorney_status: str | None = Field(None, nullable=True) + form_data: str | None = None + attorney_form_data: str | None = None + status: str | None = None + attorney_status: str | None = None project: ProjectRead | None incident: IncidentReadBasic | None - attorney_questions: str | None = Field(None, nullable=True) - attorney_analysis: str | None = Field(None, nullable=True) + attorney_questions: str | None = None + attorney_analysis: str | None = None score: int | None diff --git a/src/dispatch/forms/type/models.py b/src/dispatch/forms/type/models.py index 1e6ab699bb9e..2196f62dbd7d 100644 --- a/src/dispatch/forms/type/models.py +++ b/src/dispatch/forms/type/models.py @@ -1,6 +1,4 @@ from datetime import datetime -from pydantic import Field - from sqlalchemy import Boolean, Column, Integer, ForeignKey, String from sqlalchemy.sql.schema import UniqueConstraint from sqlalchemy.orm import relationship @@ -40,11 +38,11 @@ class FormsType(ProjectMixin, TimeStampMixin, Base): # Pydantic models class FormsTypeBase(DispatchBase): name: NameStr - description: str | None = Field(None, nullable=True) + description: str | None = None enabled: bool | None - form_schema: str | None = Field(None, nullable=True) - attorney_form_schema: str | None = Field(None, nullable=True) - scoring_schema: str | None = Field(None, nullable=True) + form_schema: str | None = None + attorney_form_schema: str | None = None + scoring_schema: str | None = None creator: IndividualContactReadMinimal | None project: ProjectRead | None service: ServiceRead | None diff --git a/src/dispatch/notification/models.py b/src/dispatch/notification/models.py index 4466bc964844..5717ce79ef20 100644 --- a/src/dispatch/notification/models.py +++ b/src/dispatch/notification/models.py @@ -1,6 +1,4 @@ from datetime import datetime -from pydantic import Field - from sqlalchemy import Boolean, Column, Integer, String, ForeignKey, Table from sqlalchemy.orm import relationship from sqlalchemy.sql.schema import PrimaryKeyConstraint @@ -62,7 +60,7 @@ class Notification(Base, TimeStampMixin, ProjectMixin, EvergreenMixin): # Pydantic models class NotificationBase(EvergreenBase): name: NameStr - description: str | None = Field(None, nullable=True) + description: str | None = None type: NotificationTypeEnum target: str enabled: bool | None diff --git a/src/dispatch/participant/models.py b/src/dispatch/participant/models.py index 8f57d3d3a34b..0555b8705814 100644 --- a/src/dispatch/participant/models.py +++ b/src/dispatch/participant/models.py @@ -1,5 +1,3 @@ -from pydantic import Field - from sqlalchemy.orm import relationship, backref from sqlalchemy import Column, Boolean, String, Integer, ForeignKey, select from sqlalchemy.ext.hybrid import hybrid_property @@ -66,17 +64,17 @@ def active_roles(cls): class ParticipantBase(DispatchBase): - location: str | None = Field(None, nullable=True) - team: str | None = Field(None, nullable=True) - department: str | None = Field(None, nullable=True) - added_reason: str | None = Field(None, nullable=True) + location: str | None = None + team: str | None = None + department: str | None = None + added_reason: str | None = None class ParticipantCreate(ParticipantBase): participant_roles: list[ParticipantRoleCreate] | None = [] - location: str | None = Field(None, nullable=True) - team: str | None = Field(None, nullable=True) - department: str | None = Field(None, nullable=True) + location: str | None = None + team: str | None = None + department: str | None = None service: ServiceRead | None = None diff --git a/src/dispatch/plugin/models.py b/src/dispatch/plugin/models.py index c704320e34ce..eecf2e107857 100644 --- a/src/dispatch/plugin/models.py +++ b/src/dispatch/plugin/models.py @@ -162,14 +162,14 @@ class PluginRead(PluginBase): type: str multiple: bool configuration_schema: Any - description: str | None = Field(None, nullable=True) + description: str | None = None class PluginEventBase(DispatchBase): name: NameStr slug: str plugin: PluginRead - description: str | None = Field(None, nullable=True) + description: str | None = None class PluginEventRead(PluginEventBase): diff --git a/src/dispatch/project/models.py b/src/dispatch/project/models.py index d3713ff9975d..81be1877d9d9 100644 --- a/src/dispatch/project/models.py +++ b/src/dispatch/project/models.py @@ -90,37 +90,37 @@ def slug(self): class Service(DispatchBase): id: PrimaryKey - description: str | None = Field(None, nullable=True) + description: str | None = None external_id: str is_active: bool | None = None name: NameStr - type: str | None = Field(None, nullable=True) + type: str | None = None class ProjectBase(DispatchBase): id: PrimaryKey | None name: NameStr display_name: str | None = Field("", nullable=False) - owner_email: EmailStr | None = Field(None, nullable=True) - owner_conversation: str | None = Field(None, nullable=True) + owner_email: EmailStr | None = None + owner_conversation: str | None = None annual_employee_cost: int | None business_year_hours: int | None - description: str | None = Field(None, nullable=True) + description: str | None = None default: bool = False - color: str | None = Field(None, nullable=True) + color: str | None = None send_daily_reports: bool | None = Field(True, nullable=True) send_weekly_reports: bool | None = Field(False, nullable=True) - weekly_report_notification_id: int | None = Field(None, nullable=True) + weekly_report_notification_id: int | None = None enabled: bool | None = Field(True, nullable=True) - storage_folder_one: str | None = Field(None, nullable=True) - storage_folder_two: str | None = Field(None, nullable=True) + storage_folder_one: str | None = None + storage_folder_two: str | None = None storage_use_folder_one_as_primary: bool | None = Field(True, nullable=True) storage_use_title: bool | None = Field(False, nullable=True) allow_self_join: bool | None = Field(True, nullable=True) select_commander_visibility: bool | None = Field(True, nullable=True) - report_incident_instructions: str | None = Field(None, nullable=True) - report_incident_title_hint: str | None = Field(None, nullable=True) - report_incident_description_hint: str | None = Field(None, nullable=True) + report_incident_instructions: str | None = None + report_incident_title_hint: str | None = None + report_incident_description_hint: str | None = None snooze_extension_oncall_service: Service | None = None @@ -131,7 +131,7 @@ class ProjectCreate(ProjectBase): class ProjectUpdate(ProjectBase): send_daily_reports: bool | None = Field(True, nullable=True) send_weekly_reports: bool | None = Field(False, nullable=True) - weekly_report_notification_id: int | None = Field(None, nullable=True) + weekly_report_notification_id: int | None = None stable_priority_id: int | None snooze_extension_oncall_service_id: int | None diff --git a/src/dispatch/search_filter/models.py b/src/dispatch/search_filter/models.py index 8068431a25be..6fa5bb752c71 100644 --- a/src/dispatch/search_filter/models.py +++ b/src/dispatch/search_filter/models.py @@ -1,7 +1,5 @@ from datetime import datetime -from pydantic import Field - from sqlalchemy import Column, ForeignKey, Integer, String, Boolean from sqlalchemy.orm import relationship from sqlalchemy.sql.schema import UniqueConstraint @@ -67,7 +65,7 @@ class NotificationRead(DispatchBase): class SearchFilterBase(DispatchBase): - description: str | None = Field(None, nullable=True) + description: str | None = None enabled: bool | None expression: list[dict] name: NameStr diff --git a/src/dispatch/service/models.py b/src/dispatch/service/models.py index c6f8d686cdbd..827a35efa4e3 100644 --- a/src/dispatch/service/models.py +++ b/src/dispatch/service/models.py @@ -42,12 +42,12 @@ class Service(Base, TimeStampMixin, ProjectMixin, EvergreenMixin): # Pydantic models... class ServiceBase(EvergreenBase): - description: str | None = Field(None, nullable=True) - external_id: str | None = Field(None, nullable=True) + description: str | None = None + external_id: str | None = None health_metrics: bool | None = None is_active: bool | None = None - name: str | None = Field(None, nullable=True) - type: str | None = Field(None, nullable=True) + name: str | None = None + type: str | None = None shift_hours_type: int | None = Field(24, nullable=True) diff --git a/src/dispatch/tag/models.py b/src/dispatch/tag/models.py index 382fdf98de44..6b8bd8dfcbef 100644 --- a/src/dispatch/tag/models.py +++ b/src/dispatch/tag/models.py @@ -1,5 +1,3 @@ -from pydantic import Field - from sqlalchemy import Column, Integer, String, Boolean, ForeignKey from sqlalchemy.orm import relationship from sqlalchemy.sql.schema import UniqueConstraint @@ -35,12 +33,12 @@ class Tag(Base, TimeStampMixin, ProjectMixin): # Pydantic models class TagBase(DispatchBase): - name: str | None = Field(None, nullable=True) - source: str | None = Field(None, nullable=True) - uri: str | None = Field(None, nullable=True) + name: str | None = None + source: str | None = None + uri: str | None = None discoverable: bool | None = True - external_id: str | None = Field(None, nullable=True) - description: str | None = Field(None, nullable=True) + external_id: str | None = None + description: str | None = None class TagCreate(TagBase): diff --git a/src/dispatch/tag_type/models.py b/src/dispatch/tag_type/models.py index 0c697a64fc34..0cb6b7c6d580 100644 --- a/src/dispatch/tag_type/models.py +++ b/src/dispatch/tag_type/models.py @@ -1,5 +1,3 @@ -from pydantic import Field - from sqlalchemy import Column, Integer, String from sqlalchemy.sql.schema import UniqueConstraint from sqlalchemy.sql.sqltypes import Boolean @@ -47,9 +45,9 @@ class TagTypeBase(DispatchBase): discoverable_signal: bool | None = True discoverable_source: bool | None = True discoverable_document: bool | None = True - description: str | None = Field(None, nullable=True) - color: str | None = Field(None, nullable=True) - icon: str | None = Field(None, nullable=True) + description: str | None = None + color: str | None = None + icon: str | None = None use_for_project_folder: bool | None = False diff --git a/src/dispatch/task/models.py b/src/dispatch/task/models.py index 32136802033b..0a5cbf0df38b 100644 --- a/src/dispatch/task/models.py +++ b/src/dispatch/task/models.py @@ -1,6 +1,4 @@ from datetime import datetime, timedelta -from pydantic import Field - from sqlalchemy import ( Boolean, Column, @@ -93,14 +91,14 @@ class TaskBase(ResourceBase): assignees: list[ParticipantRead | None] = [] created_at: datetime | None creator: ParticipantRead | None - description: str | None = Field(None, nullable=True) + description: str | None = None incident: IncidentReadBasic owner: ParticipantRead | None - priority: str | None = Field(None, nullable=True) + priority: str | None = None resolve_by: datetime | None resolved_at: datetime | None - resource_id: str | None = Field(None, nullable=True) - source: str | None = Field(None, nullable=True) + resource_id: str | None = None + source: str | None = None status: TaskStatus = TaskStatus.open updated_at: datetime | None diff --git a/src/dispatch/team/models.py b/src/dispatch/team/models.py index 861f5925aad3..b031593da2f4 100644 --- a/src/dispatch/team/models.py +++ b/src/dispatch/team/models.py @@ -1,6 +1,4 @@ from datetime import datetime -from pydantic import Field - from sqlalchemy import Column, ForeignKey, Integer, PrimaryKeyConstraint, String, Table from sqlalchemy.orm import relationship from sqlalchemy.sql.schema import UniqueConstraint @@ -53,7 +51,7 @@ class TeamContact(Base, ContactMixin, ProjectMixin, EvergreenMixin): class TeamContactBase(ContactBase, EvergreenBase): name: NameStr - notes: str | None = Field(None, nullable=True) + notes: str | None = None class TeamContactCreate(TeamContactBase): diff --git a/src/dispatch/term/models.py b/src/dispatch/term/models.py index 1a9411e4ad75..6dd263cf1395 100644 --- a/src/dispatch/term/models.py +++ b/src/dispatch/term/models.py @@ -1,5 +1,3 @@ -from pydantic import Field - from sqlalchemy import Column, Integer, String, Boolean from sqlalchemy.sql.schema import UniqueConstraint from sqlalchemy_utils import TSVectorType @@ -32,7 +30,7 @@ class Term(Base, ProjectMixin): # Pydantic models... class TermBase(DispatchBase): id: PrimaryKey | None = None - text: str | None = Field(None, nullable=True) + text: str | None = None discoverable: bool | None = True From b599bf33b126f251df83b10e333a8abbd4303fe7 Mon Sep 17 00:00:00 2001 From: Marc Vilanova Date: Thu, 8 May 2025 10:14:24 -0700 Subject: [PATCH 3/5] missing imports --- src/dispatch/auth/service.py | 1 + src/dispatch/case/models.py | 2 +- src/dispatch/database/core.py | 2 +- src/dispatch/database/logging.py | 1 + src/dispatch/database/service.py | 1 + src/dispatch/document/flows.py | 2 +- src/dispatch/group/flows.py | 2 +- src/dispatch/models.py | 1 + src/dispatch/participant/flows.py | 1 + src/dispatch/participant_role/flows.py | 2 +- src/dispatch/plugin/models.py | 1 + src/dispatch/plugins/base/v1.py | 1 + .../plugins/dispatch_slack/case/messages.py | 2 ++ src/dispatch/plugins/dispatch_slack/models.py | 6 ++++-- src/dispatch/search/fulltext/__init__.py | 1 + src/dispatch/signal/models.py | 2 +- src/dispatch/signal/service.py | 16 ++++++++-------- tests/database/test_service.py | 1 - 18 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/dispatch/auth/service.py b/src/dispatch/auth/service.py index c395695f6928..931f596b0713 100644 --- a/src/dispatch/auth/service.py +++ b/src/dispatch/auth/service.py @@ -6,6 +6,7 @@ """ import logging +from typing import Annotated from fastapi import HTTPException, Depends from starlette.requests import Request diff --git a/src/dispatch/case/models.py b/src/dispatch/case/models.py index 8eab493e3d33..95eb1fd72aa4 100644 --- a/src/dispatch/case/models.py +++ b/src/dispatch/case/models.py @@ -1,7 +1,7 @@ """Models and schemas for the Dispatch case management system.""" from collections import Counter, defaultdict from datetime import datetime - +from typing import Any from pydantic import field_validator, Field from sqlalchemy import ( Boolean, diff --git a/src/dispatch/database/core.py b/src/dispatch/database/core.py index 296d06ff21b3..a68726db472b 100644 --- a/src/dispatch/database/core.py +++ b/src/dispatch/database/core.py @@ -17,7 +17,7 @@ from sqlalchemy.sql.expression import true from sqlalchemy_utils import get_mapper from starlette.requests import Request - +from typing import Annotated, Any from dispatch import config from dispatch.search.fulltext import make_searchable from dispatch.database.logging import SessionTracker diff --git a/src/dispatch/database/logging.py b/src/dispatch/database/logging.py index ff8c65ab2931..f297696e3f93 100644 --- a/src/dispatch/database/logging.py +++ b/src/dispatch/database/logging.py @@ -1,6 +1,7 @@ import logging import uuid from datetime import datetime +from typing import Any from sqlalchemy.orm import Session diff --git a/src/dispatch/database/service.py b/src/dispatch/database/service.py index f1a663dfcdcc..dab8d1d9127f 100644 --- a/src/dispatch/database/service.py +++ b/src/dispatch/database/service.py @@ -41,6 +41,7 @@ from dispatch.tag.models import Tag from dispatch.tag_type.models import TagType from dispatch.task.models import Task +from typing import Annotated log = logging.getLogger(__file__) diff --git a/src/dispatch/document/flows.py b/src/dispatch/document/flows.py index abf05c1ab185..41fd5cdc094e 100644 --- a/src/dispatch/document/flows.py +++ b/src/dispatch/document/flows.py @@ -1,5 +1,5 @@ import logging - +from typing import Any from sqlalchemy.orm import Session from dispatch.database.core import resolve_attr diff --git a/src/dispatch/group/flows.py b/src/dispatch/group/flows.py index eaedb2fe2b58..d959ceb7e129 100644 --- a/src/dispatch/group/flows.py +++ b/src/dispatch/group/flows.py @@ -1,5 +1,5 @@ import logging - +from typing import TypeVar from sqlalchemy.orm import Session from dispatch.case.models import Case diff --git a/src/dispatch/models.py b/src/dispatch/models.py index 3510f0df1ce3..19822c9e7cc9 100644 --- a/src/dispatch/models.py +++ b/src/dispatch/models.py @@ -11,6 +11,7 @@ from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.orm import relationship +from typing import Annotated, ClassVar # pydantic type that limits the range of primary keys PrimaryKey = Annotated[int, Field(gt=0, lt=2147483647)] diff --git a/src/dispatch/participant/flows.py b/src/dispatch/participant/flows.py index 9d37abfb0213..5cb0a8cca814 100644 --- a/src/dispatch/participant/flows.py +++ b/src/dispatch/participant/flows.py @@ -16,6 +16,7 @@ ParticipantRoleType, ) from dispatch.service import service as service_service +from typing import TypeVar log = logging.getLogger(__name__) diff --git a/src/dispatch/participant_role/flows.py b/src/dispatch/participant_role/flows.py index 9c7f1e2683ad..4b8b4064ca07 100644 --- a/src/dispatch/participant_role/flows.py +++ b/src/dispatch/participant_role/flows.py @@ -6,7 +6,7 @@ """ import logging - +from typing import Any from sqlalchemy.orm import Session from dispatch.database.core import get_table_name_by_class_instance diff --git a/src/dispatch/plugin/models.py b/src/dispatch/plugin/models.py index eecf2e107857..166684e1496a 100644 --- a/src/dispatch/plugin/models.py +++ b/src/dispatch/plugin/models.py @@ -15,6 +15,7 @@ from dispatch.models import DispatchBase, ProjectMixin, Pagination, PrimaryKey, NameStr from dispatch.plugins.base import plugins from dispatch.project.models import ProjectRead +from typing import Any logger = logging.getLogger(__name__) diff --git a/src/dispatch/plugins/base/v1.py b/src/dispatch/plugins/base/v1.py index 21059be8f278..ba4ce45fcdb8 100644 --- a/src/dispatch/plugins/base/v1.py +++ b/src/dispatch/plugins/base/v1.py @@ -11,6 +11,7 @@ from threading import local from pydantic import BaseModel +from typing import Any logger = logging.getLogger(__name__) diff --git a/src/dispatch/plugins/dispatch_slack/case/messages.py b/src/dispatch/plugins/dispatch_slack/case/messages.py index eac39d478ef2..f617a6ddddbd 100644 --- a/src/dispatch/plugins/dispatch_slack/case/messages.py +++ b/src/dispatch/plugins/dispatch_slack/case/messages.py @@ -1,4 +1,6 @@ import logging +from typing import Any, NamedTuple + from blockkit import ( Actions, diff --git a/src/dispatch/plugins/dispatch_slack/models.py b/src/dispatch/plugins/dispatch_slack/models.py index 597da2c79735..028be85546b9 100644 --- a/src/dispatch/plugins/dispatch_slack/models.py +++ b/src/dispatch/plugins/dispatch_slack/models.py @@ -1,10 +1,12 @@ """Models for Slack command payloads in the Dispatch application.""" - +from typing import TypedDict, NewType from pydantic import BaseModel, AnyHttpUrl - +import logging from dispatch.enums import DispatchEnum +log = logging.getLogger(__name__) + class SlackCommandPayload(TypedDict): """TypedDict for Slack command payload values.""" diff --git a/src/dispatch/search/fulltext/__init__.py b/src/dispatch/search/fulltext/__init__.py index 7a0150b8feaf..322c72b06844 100644 --- a/src/dispatch/search/fulltext/__init__.py +++ b/src/dispatch/search/fulltext/__init__.py @@ -10,6 +10,7 @@ from sqlalchemy.engine import Connection from sqlalchemy.schema import DDL from sqlalchemy_utils import TSVectorType +from typing import Any from .vectorizers import Vectorizer diff --git a/src/dispatch/signal/models.py b/src/dispatch/signal/models.py index 686e1359ccd0..8835cca48c39 100644 --- a/src/dispatch/signal/models.py +++ b/src/dispatch/signal/models.py @@ -1,6 +1,6 @@ import uuid from datetime import datetime - +from typing import Any from pydantic import Field from sqlalchemy import ( JSON, diff --git a/src/dispatch/signal/service.py b/src/dispatch/signal/service.py index 774086d01c00..9f5d9a8f6914 100644 --- a/src/dispatch/signal/service.py +++ b/src/dispatch/signal/service.py @@ -263,7 +263,7 @@ def get_signal_filter_by_name_or_raise( return signal_filter -def get_signal_filter_by_name(*, db_session, project_id: int, name: str) -> Optional[SignalFilter]: +def get_signal_filter_by_name(*, db_session, project_id: int, name: str) -> SignalFilter | None: """Gets a signal filter by its name.""" return ( db_session.query(SignalFilter) @@ -280,7 +280,7 @@ def get_signal_filter(*, db_session: Session, signal_filter_id: int) -> SignalFi def get_signal_instance( *, db_session: Session, signal_instance_id: int | str -) -> Optional[SignalInstance]: +) -> SignalInstance | None: """Gets a signal instance by its UUID.""" return ( db_session.query(SignalInstance) @@ -289,12 +289,12 @@ def get_signal_instance( ) -def get(*, db_session: Session, signal_id: Union[str, int]) -> Optional[Signal]: +def get(*, db_session: Session, signal_id: str | int) -> Signal | None: """Gets a signal by id.""" return db_session.query(Signal).filter(Signal.id == signal_id).one_or_none() -def get_default(*, db_session: Session, project_id: int) -> Optional[Signal]: +def get_default(*, db_session: Session, project_id: int) -> Signal | None: """Gets the default signal definition.""" return ( db_session.query(Signal) @@ -304,8 +304,8 @@ def get_default(*, db_session: Session, project_id: int) -> Optional[Signal]: def get_by_primary_or_external_id( - *, db_session: Session, signal_id: Union[str, int] -) -> Optional[Signal]: + *, db_session: Session, signal_id: str | int +) -> Signal | None: """Gets a signal by id or external_id.""" if is_valid_uuid(signal_id): signal = db_session.query(Signal).filter(Signal.external_id == signal_id).one_or_none() @@ -320,7 +320,7 @@ def get_by_primary_or_external_id( def get_by_variant_or_external_id( *, db_session: Session, project_id: int, external_id: str = None, variant: str = None -) -> Optional[Signal]: +) -> Signal | None: """Gets a signal by its variant or external id.""" if variant: return ( @@ -989,7 +989,7 @@ def get_signal_stats( entity_type_id: int, signal_id: int | None = None, num_days: int | None = None, -) -> Optional[SignalStats]: +) -> SignalStats | None: """ Gets signal statistics for a given named entity and type. diff --git a/tests/database/test_service.py b/tests/database/test_service.py index f8d6fad7090f..ed007604d0fa 100644 --- a/tests/database/test_service.py +++ b/tests/database/test_service.py @@ -2,7 +2,6 @@ import json from json.decoder import JSONDecodeError from sqlalchemy_filters.exceptions import BadFilterFormat - from dispatch.database.service import ( Operator, Filter, From 990cdda774324a4f3f362b11946f2438c2c10634 Mon Sep 17 00:00:00 2001 From: Marc Vilanova Date: Thu, 8 May 2025 11:06:58 -0700 Subject: [PATCH 4/5] fixes --- .../tenant/versions/2022-10-19_3b0f5b81376f.py | 1 + .../tenant/versions/2022-10-26_4b65941d065a.py | 2 +- src/dispatch/entity/service.py | 2 +- src/dispatch/plugins/dispatch_aws/plugin.py | 1 + src/dispatch/plugins/dispatch_core/plugin.py | 2 +- src/dispatch/plugins/dispatch_duo/plugin.py | 1 + .../plugins/dispatch_google/calendar/plugin.py | 1 + .../plugins/dispatch_google/docs/plugin.py | 3 ++- .../plugins/dispatch_google/drive/drive.py | 1 + src/dispatch/plugins/dispatch_google/drive/task.py | 3 ++- .../plugins/dispatch_google/gmail/plugin.py | 4 ++-- .../plugins/dispatch_google/groups/plugin.py | 3 ++- src/dispatch/plugins/dispatch_jira/plugin.py | 1 + .../dispatch_microsoft_teams/conference/client.py | 1 + src/dispatch/plugins/dispatch_slack/bolt.py | 1 + src/dispatch/plugins/dispatch_slack/events.py | 4 ++-- src/dispatch/plugins/dispatch_slack/handler.py | 1 + .../plugins/dispatch_slack/incident/interactive.py | 1 + src/dispatch/plugins/dispatch_slack/messaging.py | 4 ++-- src/dispatch/plugins/dispatch_slack/middleware.py | 2 +- src/dispatch/plugins/dispatch_slack/plugin.py | 14 +++++++------- src/dispatch/plugins/dispatch_test/conversation.py | 4 +++- src/dispatch/route/service.py | 1 + src/dispatch/signal/service.py | 2 +- .../test_dispatch_google_docs.py | 1 - .../test_dispatch_slack_incident_interactive.py | 2 ++ tests/signal/test_signal_service.py | 1 + 27 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/dispatch/database/revisions/tenant/versions/2022-10-19_3b0f5b81376f.py b/src/dispatch/database/revisions/tenant/versions/2022-10-19_3b0f5b81376f.py index b50429555329..e255bb53c133 100644 --- a/src/dispatch/database/revisions/tenant/versions/2022-10-19_3b0f5b81376f.py +++ b/src/dispatch/database/revisions/tenant/versions/2022-10-19_3b0f5b81376f.py @@ -6,6 +6,7 @@ """ from alembic import op +from typing import Annotated from pydantic import Field, StringConstraints, ConfigDict, BaseModel diff --git a/src/dispatch/database/revisions/tenant/versions/2022-10-26_4b65941d065a.py b/src/dispatch/database/revisions/tenant/versions/2022-10-26_4b65941d065a.py index 41e1c74dfe9a..9890cc478259 100644 --- a/src/dispatch/database/revisions/tenant/versions/2022-10-26_4b65941d065a.py +++ b/src/dispatch/database/revisions/tenant/versions/2022-10-26_4b65941d065a.py @@ -13,7 +13,7 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship, Session from pydantic import Field, StringConstraints - +from typing import Annotated PrimaryKey = Annotated[int, Field(gt=0, lt=2147483647)] NameStr = Annotated[str, StringConstraints(pattern=r"^.*\S.*$", strip_whitespace=True, min_length=3)] diff --git a/src/dispatch/entity/service.py b/src/dispatch/entity/service.py index 6178d1d39d4e..fb6f37aa28b1 100644 --- a/src/dispatch/entity/service.py +++ b/src/dispatch/entity/service.py @@ -2,7 +2,7 @@ import logging import re from collections.abc import Generator, Sequence - +from typing import Any, NamedTuple import jsonpath_ng from pydantic import ValidationError from sqlalchemy import desc diff --git a/src/dispatch/plugins/dispatch_aws/plugin.py b/src/dispatch/plugins/dispatch_aws/plugin.py index a95666408e17..4f66bc358cb9 100644 --- a/src/dispatch/plugins/dispatch_aws/plugin.py +++ b/src/dispatch/plugins/dispatch_aws/plugin.py @@ -10,6 +10,7 @@ import json import logging import zlib +from typing import TypedDict import boto3 from psycopg2.errors import UniqueViolation diff --git a/src/dispatch/plugins/dispatch_core/plugin.py b/src/dispatch/plugins/dispatch_core/plugin.py index 85695b7cf4c5..11841a370837 100644 --- a/src/dispatch/plugins/dispatch_core/plugin.py +++ b/src/dispatch/plugins/dispatch_core/plugin.py @@ -10,7 +10,7 @@ import logging import time from uuid import UUID - +from typing import Literal import requests from cachetools import cached, TTLCache from fastapi import HTTPException diff --git a/src/dispatch/plugins/dispatch_duo/plugin.py b/src/dispatch/plugins/dispatch_duo/plugin.py index aba0718cdfde..cecd15fe1601 100644 --- a/src/dispatch/plugins/dispatch_duo/plugin.py +++ b/src/dispatch/plugins/dispatch_duo/plugin.py @@ -7,6 +7,7 @@ """ import logging +from typing import NewType from dispatch.decorators import apply, counter, timer from dispatch.plugins.bases import MultiFactorAuthenticationPlugin diff --git a/src/dispatch/plugins/dispatch_google/calendar/plugin.py b/src/dispatch/plugins/dispatch_google/calendar/plugin.py index 6b4ef50a3759..3d4e8f0e4d26 100644 --- a/src/dispatch/plugins/dispatch_google/calendar/plugin.py +++ b/src/dispatch/plugins/dispatch_google/calendar/plugin.py @@ -10,6 +10,7 @@ import time import uuid from datetime import datetime, timedelta +from typing import Any from googleapiclient.errors import HttpError from pytz import timezone diff --git a/src/dispatch/plugins/dispatch_google/docs/plugin.py b/src/dispatch/plugins/dispatch_google/docs/plugin.py index c4f5710a41be..b4121d098711 100644 --- a/src/dispatch/plugins/dispatch_google/docs/plugin.py +++ b/src/dispatch/plugins/dispatch_google/docs/plugin.py @@ -9,6 +9,7 @@ import logging from collections.abc import Generator import unicodedata +from typing import Any from googleapiclient.discovery import Resource from googleapiclient.errors import HttpError @@ -27,7 +28,7 @@ def remove_control_characters(s): return "".join(ch for ch in s if unicodedata.category(ch)[0] != "C") -def find_links(obj: dict, find_key: str) -> iter(list[Any]): +def find_links(obj: dict, find_key: str) -> Generator[list[Any], None, None]: """Enumerate all the links found. Returns a path of object, from leaf to parents to root. diff --git a/src/dispatch/plugins/dispatch_google/drive/drive.py b/src/dispatch/plugins/dispatch_google/drive/drive.py index 2570329775f7..17fb7c9cb723 100644 --- a/src/dispatch/plugins/dispatch_google/drive/drive.py +++ b/src/dispatch/plugins/dispatch_google/drive/drive.py @@ -11,6 +11,7 @@ import json import logging from datetime import datetime, timedelta, timezone +from typing import Any from googleapiclient.errors import HttpError from googleapiclient.http import MediaIoBaseDownload diff --git a/src/dispatch/plugins/dispatch_google/drive/task.py b/src/dispatch/plugins/dispatch_google/drive/task.py index 3cf2de2b4d76..cbb4401da71c 100644 --- a/src/dispatch/plugins/dispatch_google/drive/task.py +++ b/src/dispatch/plugins/dispatch_google/drive/task.py @@ -9,6 +9,7 @@ import re import logging +from typing import Any from dispatch.task.enums import TaskStatus from enum import Enum @@ -48,7 +49,7 @@ def find_urls(text: str) -> list[str]: """Finds a url in a text blob.""" # findall() has been used # with valid conditions for urls in string - regex = r"(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))" + regex = r"(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»""'']))" url = re.findall(regex, text) return [x[0] for x in url] diff --git a/src/dispatch/plugins/dispatch_google/gmail/plugin.py b/src/dispatch/plugins/dispatch_google/gmail/plugin.py index b71cba8ad3da..5cc53c41c8b7 100644 --- a/src/dispatch/plugins/dispatch_google/gmail/plugin.py +++ b/src/dispatch/plugins/dispatch_google/gmail/plugin.py @@ -51,7 +51,7 @@ def send_message(service, message: dict) -> bool: return True -def create_html_message(sender: str, recipient: str, cc: str, subject: str, body: str) -> Dict: +def create_html_message(sender: str, recipient: str, cc: str, subject: str, body: str) -> dict: """Creates a message for an email.""" message = MIMEText(body, "html") @@ -83,7 +83,7 @@ def send( notification_text: str, notification_template: dict, notification_type: MessageType, - items: List | None = None, + items: list | None = None, **kwargs, ): """Sends an html email based on the type.""" diff --git a/src/dispatch/plugins/dispatch_google/groups/plugin.py b/src/dispatch/plugins/dispatch_google/groups/plugin.py index 277093c1bf2a..aac6dedac399 100644 --- a/src/dispatch/plugins/dispatch_google/groups/plugin.py +++ b/src/dispatch/plugins/dispatch_google/groups/plugin.py @@ -7,6 +7,7 @@ import logging import time +from typing import Any from googleapiclient.errors import HttpError from tenacity import TryAgain, retry, retry_if_exception_type, stop_after_attempt, wait_exponential @@ -25,7 +26,7 @@ retry=retry_if_exception_type(TryAgain), wait=wait_exponential(multiplier=1, min=2, max=5), ) -def make_call(client: Any, func: Any, delay: int = None, propagate_errors: bool = False, **kwargs): +def make_call(client: Any, func: Any, delay: int | None = None, propagate_errors: bool = False, **kwargs): """Make an google client api call.""" try: data = getattr(client, func)(**kwargs).execute() diff --git a/src/dispatch/plugins/dispatch_jira/plugin.py b/src/dispatch/plugins/dispatch_jira/plugin.py index 81d099796305..73cd04aa7bb6 100644 --- a/src/dispatch/plugins/dispatch_jira/plugin.py +++ b/src/dispatch/plugins/dispatch_jira/plugin.py @@ -7,6 +7,7 @@ import json import logging +from typing import Any import requests from requests.auth import HTTPBasicAuth diff --git a/src/dispatch/plugins/dispatch_microsoft_teams/conference/client.py b/src/dispatch/plugins/dispatch_microsoft_teams/conference/client.py index edd2841e3db6..d22ce7e25f60 100644 --- a/src/dispatch/plugins/dispatch_microsoft_teams/conference/client.py +++ b/src/dispatch/plugins/dispatch_microsoft_teams/conference/client.py @@ -2,6 +2,7 @@ import logging import requests import json +from typing import Any logger = logging.getLogger(__name__) diff --git a/src/dispatch/plugins/dispatch_slack/bolt.py b/src/dispatch/plugins/dispatch_slack/bolt.py index a20852055292..12e1dfca313d 100644 --- a/src/dispatch/plugins/dispatch_slack/bolt.py +++ b/src/dispatch/plugins/dispatch_slack/bolt.py @@ -1,6 +1,7 @@ import logging import uuid from http import HTTPStatus +from typing import Any from blockkit import Context, MarkdownText, Modal from slack_bolt.app import App diff --git a/src/dispatch/plugins/dispatch_slack/events.py b/src/dispatch/plugins/dispatch_slack/events.py index 6ffc67c0ef38..4a16cc49d5a1 100644 --- a/src/dispatch/plugins/dispatch_slack/events.py +++ b/src/dispatch/plugins/dispatch_slack/events.py @@ -23,7 +23,7 @@ class ChannelActivityEvent(SlackPluginEvent): By periodically polling channel messages, this gathers insights into the \ activity and engagement levels of each participant." - def fetch_activity(client: WebClient, subject: None, oldest: str = "0") -> List: + def fetch_activity(self, client: WebClient, subject: None, oldest: str = "0") -> list: if not subject: log.warning("No subject provided. Cannot fetch channel activity.") elif not subject.conversation: @@ -48,7 +48,7 @@ class ThreadActivityEvent(SlackPluginEvent): By periodically polling thread replies, this gathers insights \ into the activity and engagement levels of each participant." - def fetch_activity(client: WebClient, subject: None, oldest: str = "0") -> List: + def fetch_activity(self, client: WebClient, subject: None, oldest: str = "0") -> list: if not subject: log.warning("No subject provided. Cannot fetch thread activity.") elif not subject.conversation: diff --git a/src/dispatch/plugins/dispatch_slack/handler.py b/src/dispatch/plugins/dispatch_slack/handler.py index 37c89be00c62..2bbcc5b272e7 100644 --- a/src/dispatch/plugins/dispatch_slack/handler.py +++ b/src/dispatch/plugins/dispatch_slack/handler.py @@ -5,6 +5,7 @@ """ from http import HTTPStatus +from typing import Any from starlette.requests import Request from starlette.responses import Response diff --git a/src/dispatch/plugins/dispatch_slack/incident/interactive.py b/src/dispatch/plugins/dispatch_slack/incident/interactive.py index be0130b60a0f..73f45eab1168 100644 --- a/src/dispatch/plugins/dispatch_slack/incident/interactive.py +++ b/src/dispatch/plugins/dispatch_slack/incident/interactive.py @@ -3,6 +3,7 @@ import uuid from functools import partial from datetime import datetime, timedelta +from typing import Any import pytz from blockkit import ( diff --git a/src/dispatch/plugins/dispatch_slack/messaging.py b/src/dispatch/plugins/dispatch_slack/messaging.py index c55a5375ed83..e11662b8ca50 100644 --- a/src/dispatch/plugins/dispatch_slack/messaging.py +++ b/src/dispatch/plugins/dispatch_slack/messaging.py @@ -6,7 +6,7 @@ """ import logging - +from typing import Any from blockkit import ( Actions, Button, @@ -264,7 +264,7 @@ def default_notification(items: list): def create_message_blocks( message_template: list[dict], message_type: MessageType, - items: List | None = None, + items: list | None = None, **kwargs, ): """Creates all required blocks for a given message type and template.""" diff --git a/src/dispatch/plugins/dispatch_slack/middleware.py b/src/dispatch/plugins/dispatch_slack/middleware.py index a464132c1d41..9623c2b6b99c 100644 --- a/src/dispatch/plugins/dispatch_slack/middleware.py +++ b/src/dispatch/plugins/dispatch_slack/middleware.py @@ -1,6 +1,6 @@ import logging import json - +from typing import Callable, NamedTuple from slack_bolt import BoltContext, BoltRequest from slack_sdk.web import WebClient from sqlalchemy.orm.session import Session diff --git a/src/dispatch/plugins/dispatch_slack/plugin.py b/src/dispatch/plugins/dispatch_slack/plugin.py index a57fa4734528..1a0decd97b89 100644 --- a/src/dispatch/plugins/dispatch_slack/plugin.py +++ b/src/dispatch/plugins/dispatch_slack/plugin.py @@ -9,7 +9,7 @@ import io import json import logging - +from typing import Any from blockkit import Message from blockkit.surfaces import Block from slack_sdk.errors import SlackApiError @@ -254,8 +254,8 @@ def send( text: str, message_template: list[dict], notification_type: str, - items: List | None = None, - blocks: List | None = None, + items: list | None = None, + blocks: list | None = None, ts: str | None = None, persist: bool = False, **kwargs, @@ -297,9 +297,9 @@ def send_direct( text: str, message_template: dict, notification_type: str, - items: List | None = None, + items: list | None = None, ts: str | None = None, - blocks: List | None = None, + blocks: list | None = None, **kwargs, ): """Sends a message directly to a user if the user exists.""" @@ -322,8 +322,8 @@ def send_ephemeral( text: str, message_template: dict = None, notification_type: str = None, - items: List | None = None, - blocks: List | None = None, + items: list | None = None, + blocks: list | None = None, **kwargs, ): """Sends an ephemeral message to a user in a channel if the user exists.""" diff --git a/src/dispatch/plugins/dispatch_test/conversation.py b/src/dispatch/plugins/dispatch_test/conversation.py index b35264ca6096..f3be3214d00f 100644 --- a/src/dispatch/plugins/dispatch_test/conversation.py +++ b/src/dispatch/plugins/dispatch_test/conversation.py @@ -1,4 +1,6 @@ from datetime import datetime +from typing import Any + from slack_sdk import WebClient from dispatch.plugins.bases import ConversationPlugin @@ -30,7 +32,7 @@ def send(self, items, **kwargs): def fetch_events(self, subject: Any, **kwargs): client = TestWebClient() for plugin_event in self.plugin_events: - plugin_event.fetch_activity(client=client, subject=subject) + plugin_event().fetch_activity(client=client, subject=subject) return [ (datetime.utcfromtimestamp(1512085950.000216), "0XDECAFBAD"), (datetime.utcfromtimestamp(1512104434.000490), "0XDECAFBAD"), diff --git a/src/dispatch/route/service.py b/src/dispatch/route/service.py index 1c1446fa470a..509a877192e6 100644 --- a/src/dispatch/route/service.py +++ b/src/dispatch/route/service.py @@ -1,5 +1,6 @@ import json import logging +from typing import Any from dispatch.database.core import Base from dispatch.route.models import Recommendation, RecommendationMatch diff --git a/src/dispatch/signal/service.py b/src/dispatch/signal/service.py index 9f5d9a8f6914..f99c0f5672f0 100644 --- a/src/dispatch/signal/service.py +++ b/src/dispatch/signal/service.py @@ -2,7 +2,7 @@ import logging import uuid from datetime import datetime, timedelta, timezone - +from collections import defaultdict from fastapi import HTTPException, status from pydantic import ValidationError from sqlalchemy import asc, desc, or_, func, and_, select, cast diff --git a/tests/dispatch_google_docs/test_dispatch_google_docs.py b/tests/dispatch_google_docs/test_dispatch_google_docs.py index 85917e0b7170..e5f8f8bd4cf1 100644 --- a/tests/dispatch_google_docs/test_dispatch_google_docs.py +++ b/tests/dispatch_google_docs/test_dispatch_google_docs.py @@ -1,7 +1,6 @@ # Representation of document in the Google Docs API. # See https://developers.google.com/docs/api/samples/output-json. - def test_find_links(): """Tests the find_links function returns the expected urls.""" from dispatch.plugins.dispatch_google.docs.plugin import find_links diff --git a/tests/plugins/test_dispatch_slack_incident_interactive.py b/tests/plugins/test_dispatch_slack_incident_interactive.py index 1d2cfd4a887a..7743a8ee9d24 100644 --- a/tests/plugins/test_dispatch_slack_incident_interactive.py +++ b/tests/plugins/test_dispatch_slack_incident_interactive.py @@ -1,3 +1,5 @@ +from typing import Any + def test_configure(): """Test that we can configure the plugin.""" from dispatch.plugins.dispatch_slack.incident.interactive import ( diff --git a/tests/signal/test_signal_service.py b/tests/signal/test_signal_service.py index 0c7804bdb8aa..230678190b7e 100644 --- a/tests/signal/test_signal_service.py +++ b/tests/signal/test_signal_service.py @@ -1,4 +1,5 @@ import json +from collections import defaultdict def test_get(session, signal): From 4cd64172ad0054b84de72728cd70f6bfd0914936 Mon Sep 17 00:00:00 2001 From: Marc Vilanova Date: Thu, 8 May 2025 11:12:18 -0700 Subject: [PATCH 5/5] ruff --- src/dispatch/case/views.py | 1 + src/dispatch/entity/service.py | 2 +- src/dispatch/evergreen/scheduled.py | 2 +- src/dispatch/incident/views.py | 2 +- src/dispatch/main.py | 2 +- src/dispatch/plugin/models.py | 2 +- src/dispatch/plugins/dispatch_slack/case/messages.py | 2 +- src/dispatch/search/models.py | 2 +- src/dispatch/tag/recommender.py | 2 +- src/dispatch/tag/scheduled.py | 2 +- tests/plugins/test_dispatch_slack_incident_interactive.py | 1 - tests/signal/test_signal_service.py | 1 - 12 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/dispatch/case/views.py b/src/dispatch/case/views.py index 211124b63833..3dd85650838d 100644 --- a/src/dispatch/case/views.py +++ b/src/dispatch/case/views.py @@ -1,4 +1,5 @@ import logging +from typing import Annotated import json diff --git a/src/dispatch/entity/service.py b/src/dispatch/entity/service.py index fb6f37aa28b1..885a25a0a11b 100644 --- a/src/dispatch/entity/service.py +++ b/src/dispatch/entity/service.py @@ -2,7 +2,7 @@ import logging import re from collections.abc import Generator, Sequence -from typing import Any, NamedTuple +from typing import NamedTuple import jsonpath_ng from pydantic import ValidationError from sqlalchemy import desc diff --git a/src/dispatch/evergreen/scheduled.py b/src/dispatch/evergreen/scheduled.py index 3b1ae4255309..e5774a7fc3e0 100644 --- a/src/dispatch/evergreen/scheduled.py +++ b/src/dispatch/evergreen/scheduled.py @@ -6,7 +6,7 @@ """ import logging - +from typing import Any from collections import defaultdict from datetime import datetime from schedule import every diff --git a/src/dispatch/incident/views.py b/src/dispatch/incident/views.py index 2499342d3580..1d3045bce940 100644 --- a/src/dispatch/incident/views.py +++ b/src/dispatch/incident/views.py @@ -2,7 +2,7 @@ import json import logging from datetime import date, datetime - +from typing import Annotated from dateutil.relativedelta import relativedelta from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, status from sqlalchemy.exc import IntegrityError diff --git a/src/dispatch/main.py b/src/dispatch/main.py index 08e4cf5c6ac3..0b7428e6e40b 100644 --- a/src/dispatch/main.py +++ b/src/dispatch/main.py @@ -4,7 +4,7 @@ from os import path from uuid import uuid1 import warnings - +from typing import Final from fastapi import FastAPI, status from fastapi.responses import JSONResponse from pydantic import ValidationError diff --git a/src/dispatch/plugin/models.py b/src/dispatch/plugin/models.py index 166684e1496a..3bacb4cddc35 100644 --- a/src/dispatch/plugin/models.py +++ b/src/dispatch/plugin/models.py @@ -1,6 +1,6 @@ import logging -from pydantic import Field, SecretStr +from pydantic import SecretStr from pydantic.json import pydantic_encoder from sqlalchemy import Column, Integer, String, Boolean, ForeignKey diff --git a/src/dispatch/plugins/dispatch_slack/case/messages.py b/src/dispatch/plugins/dispatch_slack/case/messages.py index f617a6ddddbd..12d5cbdb0f93 100644 --- a/src/dispatch/plugins/dispatch_slack/case/messages.py +++ b/src/dispatch/plugins/dispatch_slack/case/messages.py @@ -1,5 +1,5 @@ import logging -from typing import Any, NamedTuple +from typing import NamedTuple from blockkit import ( diff --git a/src/dispatch/search/models.py b/src/dispatch/search/models.py index a18ab78fa972..7cb40670f16a 100644 --- a/src/dispatch/search/models.py +++ b/src/dispatch/search/models.py @@ -1,7 +1,7 @@ """Models for search functionality in the Dispatch application.""" from pydantic import ConfigDict, Field - +from typing import ClassVar from dispatch.case.models import CaseRead from dispatch.data.query.models import QueryRead from dispatch.data.source.models import SourceRead diff --git a/src/dispatch/tag/recommender.py b/src/dispatch/tag/recommender.py index 0e1105627d75..7e161f716fe4 100644 --- a/src/dispatch/tag/recommender.py +++ b/src/dispatch/tag/recommender.py @@ -7,7 +7,7 @@ import logging from collections import defaultdict - +from typing import Any import tempfile import pandas as pd from pandas.core.frame import DataFrame diff --git a/src/dispatch/tag/scheduled.py b/src/dispatch/tag/scheduled.py index 2bc6aba3aee6..1926ededd603 100644 --- a/src/dispatch/tag/scheduled.py +++ b/src/dispatch/tag/scheduled.py @@ -7,7 +7,7 @@ import logging from schedule import every - +from typing import NoReturn from sqlalchemy.orm import Session from dispatch.decorators import scheduled_project_task, timer diff --git a/tests/plugins/test_dispatch_slack_incident_interactive.py b/tests/plugins/test_dispatch_slack_incident_interactive.py index 7743a8ee9d24..4cac09479204 100644 --- a/tests/plugins/test_dispatch_slack_incident_interactive.py +++ b/tests/plugins/test_dispatch_slack_incident_interactive.py @@ -1,4 +1,3 @@ -from typing import Any def test_configure(): """Test that we can configure the plugin.""" diff --git a/tests/signal/test_signal_service.py b/tests/signal/test_signal_service.py index 230678190b7e..0c7804bdb8aa 100644 --- a/tests/signal/test_signal_service.py +++ b/tests/signal/test_signal_service.py @@ -1,5 +1,4 @@ import json -from collections import defaultdict def test_get(session, signal):