diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6d26e977b..c5e3d7318 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -51,7 +51,7 @@ repos: - id: pyupgrade args: ['--keep-runtime-typing', '--py311-plus'] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.9 + rev: v0.1.11 hooks: - id: ruff args: ['--fix', '--exit-non-zero-on-fix'] @@ -100,32 +100,31 @@ repos: rev: 23.12.1 hooks: - id: black - # Mypy is temporarily disabled until the SQLAlchemy 2.0 migration is complete - # - repo: https://github.com/pre-commit/mirrors-mypy - # rev: v1.8.0 - # hooks: - # - id: mypy - # # warn-unused-ignores is unsafe with pre-commit, see - # # https://github.com/python/mypy/issues/2960 - # args: - # [ - # '--no-warn-unused-ignores', - # '--no-warn-redundant-casts', - # '--ignore-missing-imports', - # ] - # additional_dependencies: - # - flask - # - lxml-stubs - # - sqlalchemy - # - toml - # - types-chevron - # - types-geoip2 - # - types-python-dateutil - # - types-pytz - # - types-requests - # - typing-extensions + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.8.0 + hooks: + - id: mypy + # warn-unused-ignores is unsafe with pre-commit, see + # https://github.com/python/mypy/issues/2960 + args: + [ + '--no-warn-unused-ignores', + '--no-warn-redundant-casts', + '--ignore-missing-imports', + ] + additional_dependencies: + - flask + - lxml-stubs + - sqlalchemy + - toml + - types-chevron + - types-geoip2 + - types-python-dateutil + - types-pytz + - types-requests + - typing-extensions - repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 + rev: 7.0.0 hooks: - id: flake8 additional_dependencies: *flake8deps diff --git a/funnel/models/auth_client.py b/funnel/models/auth_client.py index 82bb7bf90..4ee91d212 100644 --- a/funnel/models/auth_client.py +++ b/funnel/models/auth_client.py @@ -266,7 +266,7 @@ def all_for(cls, account: Account | None) -> Query[Self]: return cls.query.order_by(cls.title) return cls.query.filter( sa.or_( - cls.account == account, + cls.account == account, # type: ignore[arg-type] cls.account_id.in_(account.organizations_as_owner_ids()), ) ).order_by(cls.title) diff --git a/funnel/models/contact_exchange.py b/funnel/models/contact_exchange.py index d6f17de2d..f6c7e77b2 100644 --- a/funnel/models/contact_exchange.py +++ b/funnel/models/contact_exchange.py @@ -139,7 +139,7 @@ def grouped_counts_for( ).filter( cls.ticket_participant_id == TicketParticipant.id, TicketParticipant.project_id == Project.id, - cls.account == account, + cls.account == account, # type: ignore[arg-type] ) if not archived: diff --git a/funnel/models/email_address.py b/funnel/models/email_address.py index 2a14e0d2e..1922723ac 100644 --- a/funnel/models/email_address.py +++ b/funnel/models/email_address.py @@ -860,7 +860,10 @@ def _validate_email( if old_value == value: # Old value is new value. Do nothing. Return without validating return - if old_value is NO_VALUE and inspect(target).has_identity is False: + if ( + old_value is NO_VALUE + and inspect(target).has_identity is False # type: ignore[attr-defined] + ): # Old value is unknown and target is a transient object. Continue pass elif value is None: diff --git a/funnel/models/label.py b/funnel/models/label.py index 83ecae347..15a29a1fd 100644 --- a/funnel/models/label.py +++ b/funnel/models/label.py @@ -276,7 +276,7 @@ def icon(self) -> str: result = ''.join(w[0] for w in self.title.strip().title().split(None, 2)) if len(result) <= 1: result = self.title.strip()[:3] - return result + return result # type: ignore[return-value] def __repr__(self) -> str: """Represent :class:`Label` as a string.""" diff --git a/funnel/models/phone_number.py b/funnel/models/phone_number.py index 619faa288..557d6466d 100644 --- a/funnel/models/phone_number.py +++ b/funnel/models/phone_number.py @@ -888,7 +888,10 @@ def _validate_number( if old_value == value: # Old value is new value. Do nothing. Return without validating return value - if old_value is NO_VALUE and inspect(target).has_identity is False: + if ( + old_value is NO_VALUE + and inspect(target).has_identity is False # type: ignore[attr-defined] + ): # Old value is unknown and target is a transient object. Continue pass elif value is None: diff --git a/funnel/models/update.py b/funnel/models/update.py index 7aca005c5..6889e5e96 100644 --- a/funnel/models/update.py +++ b/funnel/models/update.py @@ -284,7 +284,7 @@ def publish(self, actor: Account) -> bool: if self.number is None: self.number = ( sa.select(sa.func.coalesce(sa.func.max(Update.number), 0) + 1) - .where(Update.project == self.project) + .where(Update.project == self.project) # type: ignore[arg-type] .scalar_subquery() ) return first_publishing diff --git a/funnel/views/session.py b/funnel/views/session.py index 4e561b52e..7b352e819 100644 --- a/funnel/views/session.py +++ b/funnel/views/session.py @@ -2,6 +2,8 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from flask import render_template, request from baseframe import _ @@ -90,6 +92,8 @@ def session_edit( else: db.session.add(session) db.session.commit() + if TYPE_CHECKING: # FIXME: Needed for Mypy in pre-commit only, unclear why + assert session is not None # nosec B101 session.project.update_schedule_timestamps() db.session.commit() if request_wants.html_in_json: diff --git a/runfrontendtests.sh b/runfrontendtests.sh index 71097f22a..753da125f 100755 --- a/runfrontendtests.sh +++ b/runfrontendtests.sh @@ -3,8 +3,11 @@ # Load config into environment variables set -o allexport source .flaskenv +# shellcheck disable=SC1091 source .env +# shellcheck disable=SC1091 source .testenv +# shellcheck disable=SC1091 source .env.testing set +o allexport diff --git a/tests/unit/models/proposal_test.py b/tests/unit/models/proposal_test.py index 9cab9872c..908b9827f 100644 --- a/tests/unit/models/proposal_test.py +++ b/tests/unit/models/proposal_test.py @@ -35,7 +35,7 @@ def test_reorder(db_session, user_twoflower, project_expo2010) -> None: assert proposal3.url_id == 3 assert proposal1.title == "Test Proposal 1" - assert proposal1.url_id < proposal2.url_id < proposal3.url_id + assert proposal1.url_id < proposal2.url_id < proposal3.url_id # type: ignore[operator] proposal1.reorder_after(proposal2) db_session.commit()