diff --git a/setup.cfg b/setup.cfg index 8963bce0f6..f414d38a22 100644 --- a/setup.cfg +++ b/setup.cfg @@ -73,6 +73,7 @@ install_requires = click-params cssmin cssutils + dectate@git+https://github.com/morepath/dectate.git#egg=dectate dicttoxml docxtpl dogpile.cache @@ -88,6 +89,7 @@ install_requires = html5lib humanize icalendar + importscan@git+https://github.com/morepath/importscan.git#egg=importscan isodate itsdangerous kerberos @@ -99,11 +101,11 @@ install_requires = lxml markupsafe mistletoe>=1.2.0 - more.content_security - more.transaction - more.webassets + more.content_security@git+https://github.com/morepath/more.content_security.git#egg=more.content_security + more.transaction@git+https://github.com/morepath/more.transaction.git#egg=more.transaction + more.webassets@git+https://github.com/morepath/more.webassets.git#egg=more.webassets more_itertools - morepath + morepath@git+https://github.com/morepath/morepath.git#egg=morepath msal niquests[speedups] oauthlib @@ -139,6 +141,7 @@ install_requires = rapidfuzz rcssmin redis + reg@git+https://github.com/morepath/reg.git#egg=reg reportlab # FIXME: It may be worth to create a fork for niquests or manually # make use of oauthlib, for the features we need. For now diff --git a/src/onegov/agency/app.py b/src/onegov/agency/app.py index d786aff62f..95286ac1dc 100644 --- a/src/onegov/agency/app.py +++ b/src/onegov/agency/app.py @@ -20,6 +20,7 @@ from typing import Any +from typing import Self from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -36,7 +37,7 @@ class AgencyApp(TownApp): - request_class = AgencyRequest + request_class: type[AgencyRequest[Self]] = AgencyRequest if TYPE_CHECKING: # FIXME: Maybe we should consider just raising an exception diff --git a/src/onegov/agency/request.py b/src/onegov/agency/request.py index 1115e2e712..dbb5fbb662 100644 --- a/src/onegov/agency/request.py +++ b/src/onegov/agency/request.py @@ -4,15 +4,16 @@ from onegov.town6.request import TownRequest +from typing import TypeVar from typing import TYPE_CHECKING - if TYPE_CHECKING: from onegov.agency.app import AgencyApp -class AgencyRequest(TownRequest): +AppT = TypeVar('AppT', bound='AgencyApp', default='AgencyApp', covariant=True) + - app: AgencyApp +class AgencyRequest(TownRequest[AppT]): @cached_property def current_role(self) -> str | None: diff --git a/src/onegov/agency/security.py b/src/onegov/agency/security.py index 9c8414de4c..c66a52d7f9 100644 --- a/src/onegov/agency/security.py +++ b/src/onegov/agency/security.py @@ -22,8 +22,8 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from morepath.authentication import Identity from morepath.authentication import NoIdentity + from onegov.core import Identity from onegov.core.security.roles import Intent from sqlalchemy.orm import Session diff --git a/src/onegov/core/__init__.py b/src/onegov/core/__init__.py index 12864bda22..f2604e8d58 100644 --- a/src/onegov/core/__init__.py +++ b/src/onegov/core/__init__.py @@ -96,8 +96,9 @@ from onegov.core.framework import Framework from onegov.core.filestorage import get_filestorage_file # noqa: F401 +from onegov.core.identity import OneGovIdentity as Identity # include the filters module so they get picked up by webassets from onegov.core import filters # noqa: F401 -__all__ = ['Framework', 'log'] +__all__ = ['Framework', 'Identity', 'log'] diff --git a/src/onegov/core/directives.py b/src/onegov/core/directives.py index 680dc96c6d..c69a5e7e18 100644 --- a/src/onegov/core/directives.py +++ b/src/onegov/core/directives.py @@ -2,7 +2,7 @@ import os.path -from dectate import Action, Query, convert_dotted_name # type:ignore[attr-defined] +from dectate import Action, Query, convert_dotted_name from itertools import count from morepath import render_json, Request @@ -18,7 +18,6 @@ from typing import Any, ClassVar, TYPE_CHECKING if TYPE_CHECKING: - from _typeshed import StrOrBytesPath, StrPath from collections.abc import Callable, Mapping from webob import Response from wtforms import Form @@ -60,12 +59,12 @@ def handle_form(self, request, form): """ def __init__[RequestT: CoreRequest]( self, - model: type | str, + model: type, form: type[Form] | Callable[[Any, RequestT], type[Form]], - render: Callable[[Any, RequestT], Response] | str | None = None, - template: StrOrBytesPath | None = None, - load: Callable[[RequestT], Any] | str | None = None, - permission: object | str | None = None, + render: Callable[[Any, RequestT], Response] | None = None, + template: str | None = None, + load: Callable[[RequestT], Any] | None = None, + permission: object | None = None, internal: bool = False, pass_model: bool = False, **predicates: Any @@ -208,7 +207,7 @@ def __init__( def identifier(self, **kw: Any) -> int: return self.name - def perform( # type:ignore[override] + def perform( self, func: Callable[[CoreRequest], Any], cronjob_registry: Bunch @@ -235,13 +234,13 @@ def __init__(self, name: str, title: str) -> None: self.name = name self.title = title - def identifier( # type:ignore[override] + def identifier( self, analytics_provider_registry: dict[str, AnalyticsProvider] ) -> str: return self.name - def perform( # type:ignore[override] + def perform( self, func: type[AnalyticsProvider], analytics_provider_registry: dict[str, type[AnalyticsProvider]] @@ -267,13 +266,13 @@ class StaticDirectoryAction(Action): def __init__(self) -> None: self.name = next(self.counter) - def identifier( # type:ignore[override] + def identifier( self, staticdirectory_registry: Bunch ) -> int: return self.name - def perform( # type:ignore[override] + def perform( self, func: Callable[..., Any], staticdirectory_registry: Bunch @@ -317,13 +316,13 @@ def get_template_variables(request): def __init__(self) -> None: self.section = 'templatevariables' - def identifier( # type:ignore[override] + def identifier( self, setting_registry: SettingRegistry ) -> str: return self.section - def perform( # type:ignore[override] + def perform( self, func: Callable[[CoreRequest], dict[str, Any]], setting_registry: SettingRegistry @@ -351,7 +350,7 @@ def __init__(self, section: str) -> None: def identifier(self, **kw: Any) -> str: return self.section - def perform( # type: ignore[override] + def perform( self, obj: Callable[[], Mapping[str, Any]], setting_registry: SettingRegistry @@ -388,13 +387,13 @@ class Layout(Action): def __init__(self, model: type) -> None: self.model = model - def identifier( # type:ignore[override] + def identifier( self, app_class: type[Framework] ) -> str: return str(self.model) - def perform( # type:ignore[override] + def perform( self, obj: type[CoreLayout], app_class: type[Framework] @@ -402,7 +401,7 @@ def perform( # type:ignore[override] layout_class = obj # `lambda self, obj, request` is required to match the signature - app_class.get_layout.register( # type:ignore[attr-defined] + app_class.get_layout.register( lambda self, obj, request: layout_class(obj, request), model=self.model) @@ -431,10 +430,10 @@ class ExtendedJsonAction(JsonAction): def __init__( self, - model: type | str, - render: Callable[[Any, Any], Response] | str | None = None, - template: StrPath | None = None, - load: Callable[[Any], Any] | str | None = None, + model: type, + render: Callable[[Any, Any], Response] | None = None, + template: str | None = None, + load: Callable[[Any], Any] | None = None, permission: object = None, internal: bool = False, open_data: bool = False, diff --git a/src/onegov/core/framework.py b/src/onegov/core/framework.py index 047b4bdbfc..7dffd00785 100644 --- a/src/onegov/core/framework.py +++ b/src/onegov/core/framework.py @@ -59,6 +59,7 @@ class MyApplication(Framework): from onegov.core.orm.cache import OrmCacheApp from onegov.core.orm.observer import ScopedPropertyObserver from onegov.core.request import CoreRequest +from onegov.core.identity import OneGovIdentity as Identity from onegov.core.utils import batched, PostThread from onegov.server import Application as ServerApplication from onegov.server.utils import load_class @@ -70,7 +71,7 @@ class MyApplication(Framework): from webob.exc import HTTPConflict, HTTPServiceUnavailable -from typing import overload, Any, Literal, TYPE_CHECKING +from typing import overload, Any, Literal, Self, TYPE_CHECKING if TYPE_CHECKING: from _typeshed import StrPath from _typeshed.wsgi import WSGIApplication, WSGIEnvironment, StartResponse @@ -78,7 +79,6 @@ class MyApplication(Framework): from email.headerregistry import Address from fs.base import FS, SubFS from gettext import GNUTranslations - from morepath.request import Request from morepath.settings import SettingRegistry from sqlalchemy.orm import Session from translationstring import _ChameleonTranslate @@ -96,7 +96,7 @@ class MyApplication(Framework): # This should be in more.webassets: # https://github.com/morepath/more.webassets/blob/master/more/webassets/core.py#L55 if not WebassetsApp.dectate._directives[0][0].kw: - from morepath.core import excview_tween_factory # type:ignore + from morepath.core import excview_tween_factory WebassetsApp.dectate._directives[0][0].kw['over'] = excview_tween_factory @@ -109,7 +109,7 @@ class Framework( ): """ Baseclass for Morepath OneGov applications. """ - request_class: type[Request] = CoreRequest + request_class: type[CoreRequest[Self]] = CoreRequest #: holds the database connection string, *if* there is a database connected dsn: str | None = None @@ -129,7 +129,7 @@ class Framework( replace_setting = directive(directives.ReplaceSettingAction) replace_setting_section = directive(directives.ReplaceSettingSectionAction) layout = directive(directives.Layout) - json = directive(directives.ExtendedJsonAction) # type: ignore[assignment] + json = directive(directives.ExtendedJsonAction) #: sets the same-site cookie directive, (may need removal inside iframes) same_site_cookie_policy: str | None = 'Lax' @@ -798,7 +798,7 @@ def object_by_path( 'SERVER_NAME': '', 'SERVER_PORT': '', 'SERVER_PROTOCOL': 'https' - }, app=self) + }, app=self) # type: ignore[arg-type] obj = resolve_model(request) @@ -834,12 +834,13 @@ def permission_by_view( ) try: - action, _handler = next(query(self.__class__)) + action, _handler = next(iter(query(self.__class__))) except (StopIteration, RuntimeError) as exception: raise KeyError( '{!r} has no view named {}'.format(model, view_name) ) from exception + assert hasattr(action, 'permission') return action.permission @cached_property @@ -1348,12 +1349,12 @@ def application_bound_identity( uid: str, groupids: frozenset[str], role: str - ) -> morepath.authentication.Identity: + ) -> Identity: """ Returns a new morepath identity for the given userid, group and role, bound to this application. """ - return morepath.authentication.Identity( + return Identity( userid, uid=uid, groupids=groupids, role=role, application_id=self.application_id_hash ) diff --git a/src/onegov/core/identity.py b/src/onegov/core/identity.py new file mode 100644 index 0000000000..676a597854 --- /dev/null +++ b/src/onegov/core/identity.py @@ -0,0 +1,36 @@ +from __future__ import annotations + +from morepath import Identity + + +from typing import TYPE_CHECKING + + +class OneGovIdentity(Identity): + + userid: str # email + uid: str # actual user id + groupids: frozenset[str] + role: str + application_id: str + + def __init__( + self, + userid: str, + *, + uid: str, + groupids: frozenset[str], + role: str, + application_id: str + ) -> None: + super().__init__( + userid, + uid=uid, + groupids=groupids, + role=role, + application_id=application_id + ) + + # NOTE: Pretend arbitrary attribute access is disabled + if TYPE_CHECKING: + __getattr__ = None # type: ignore diff --git a/src/onegov/core/request.py b/src/onegov/core/request.py index a5c742baed..24d24829b2 100644 --- a/src/onegov/core/request.py +++ b/src/onegov/core/request.py @@ -26,15 +26,15 @@ from wtforms.csrf.session import SessionCSRF -from typing import cast, overload, Any, NamedTuple, TYPE_CHECKING +from typing import cast, overload, Any, NamedTuple, TypeVar, TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Callable, Iterable, Iterator, Sequence from dectate import Sentinel from gettext import GNUTranslations from markupsafe import Markup - from morepath import App - from morepath.authentication import Identity, NoIdentity - from onegov.core import Framework + from morepath import reify + from morepath.authentication import NoIdentity + from onegov.core import Framework, Identity from onegov.core.browser_session import BrowserSession from onegov.core.i18n.translation_string import TranslationMarkup from onegov.core.security.permissions import Intent @@ -43,7 +43,7 @@ from translationstring import _ChameleonTranslate from typing import Literal, Protocol, TypeGuard from webob import Response - from webob.multidict import MultiDict + from webob.multidict import GetDict, MultiDict from webob.request import _FieldStorageWithFile from wtforms import Form from uuid import UUID @@ -82,13 +82,16 @@ def items(self) -> Iterable[tuple[str, str]]: ... _BaseRequest = object +AppT = TypeVar('AppT', bound='Framework', default='Framework', covariant=True) + + @msgpack.make_serializable(tag=11) class Message(NamedTuple): text: str type: MessageType -class ReturnToMixin(_BaseRequest): +class ReturnToMixin: """ Provides a safe and convenient way of using return-to links. Return-to links are links with an added 'return-to' query parameter @@ -119,6 +122,13 @@ class ReturnToMixin(_BaseRequest): """ + if TYPE_CHECKING: + # forward declare required attributes + @property + def url(self) -> str: ... + @property + def GET(self) -> GetDict: ... # noqa: N802 + @property def identity_secret(self) -> str: raise NotImplementedError @@ -152,7 +162,11 @@ def is_logged_in(identity: Identity | NoIdentity) -> TypeGuard[Identity]: return identity is not NO_IDENTITY -class CoreRequest(IncludeRequest, ContentSecurityRequest, ReturnToMixin): +class CoreRequest( + IncludeRequest[AppT], + ContentSecurityRequest[AppT], + ReturnToMixin +): """ Extends the default Morepath request with virtual host support and other useful methods. @@ -161,7 +175,9 @@ class CoreRequest(IncludeRequest, ContentSecurityRequest, ReturnToMixin): """ - app: Framework + if TYPE_CHECKING: + @reify + def identity(self) -> Identity | NoIdentity: ... @cached_property def identity_secret(self) -> str: @@ -912,7 +928,7 @@ def require_unsafe_eval(self) -> None: def resolve_path( self, path: str, - app: App | Sentinel = SAME_APP + app: Framework | Sentinel = SAME_APP # type: ignore[override] ) -> Any | None: """Resolve a path to a model instance. @@ -937,7 +953,7 @@ def resolve_path( environ.pop('webob._parsed_post_vars', None) request = self.__class__( environ, - cast('App', app), + cast('AppT', app), method='GET', path_info=path_info, query_string=query_string, diff --git a/src/onegov/core/security/identity_policy.py b/src/onegov/core/security/identity_policy.py index 19bf12156f..ebb92ad8e9 100644 --- a/src/onegov/core/security/identity_policy.py +++ b/src/onegov/core/security/identity_policy.py @@ -1,8 +1,8 @@ from __future__ import annotations -from morepath import Identity from onegov.core.browser_session import BrowserSession from onegov.core.framework import Framework +from onegov.core.identity import OneGovIdentity as Identity from typing import TYPE_CHECKING diff --git a/src/onegov/election_day/app.py b/src/onegov/election_day/app.py index 6225b9c73e..6ab96c135e 100644 --- a/src/onegov/election_day/app.py +++ b/src/onegov/election_day/app.py @@ -28,6 +28,7 @@ from typing import Any +from typing import Self from typing import TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Callable @@ -44,7 +45,7 @@ class ElectionDayApp(Framework, FormApp, UserApp, DepotApp): """ serve_static_files = True - request_class = ElectionDayRequest + request_class: type[ElectionDayRequest[Self]] = ElectionDayRequest csv_file = directive(CsvFileAction) json_file = directive(JsonFileAction) diff --git a/src/onegov/election_day/directives.py b/src/onegov/election_day/directives.py index 8a60bbd339..6da9d97e6c 100644 --- a/src/onegov/election_day/directives.py +++ b/src/onegov/election_day/directives.py @@ -18,7 +18,6 @@ from typing import Any from typing import TYPE_CHECKING if TYPE_CHECKING: - from _typeshed import StrOrBytesPath from collections.abc import Callable from collections.abc import Iterable from onegov.core.request import CoreRequest @@ -47,11 +46,11 @@ class ManageHtmlAction(HtmlAction): def __init__[RequestT: CoreRequest]( self, - model: type | str, - render: Callable[[Any, RequestT], BaseResponse] | str | None = None, - template: StrOrBytesPath | None = None, - load: Callable[[RequestT], Any] | str | None = None, - permission: object | str | None = None, + model: type, + render: Callable[[Any, RequestT], BaseResponse] | None = None, + template: str | None = None, + load: Callable[[RequestT], Any] | None = None, + permission: object | None = None, internal: bool = False, **predicates: Any, ) -> None: @@ -76,12 +75,12 @@ class ManageFormAction(HtmlHandleFormAction): def __init__[RequestT: CoreRequest]( self, - model: type | str, + model: type, form: type[Form] | Callable[[Any, RequestT], type[Form]] = EmptyForm, - render: Callable[[Any, RequestT], BaseResponse] | str | None = None, - template: StrOrBytesPath = 'form.pt', - load: Callable[[RequestT], Any] | str | None = None, - permission: object | str | None = None, + render: Callable[[Any, RequestT], BaseResponse] | None = None, + template: str = 'form.pt', + load: Callable[[RequestT], Any] | None = None, + permission: object | None = None, internal: bool = False, **predicates: Any, ) -> None: @@ -171,9 +170,9 @@ class SvgFileViewAction(ViewAction): def __init__[RequestT: CoreRequest]( self, - model: type | str, - load: Callable[[RequestT], Any] | str | None = None, - permission: object | str = Public, + model: type, + load: Callable[[RequestT], Any] | None = None, + permission: object = Public, internal: bool = False, **predicates: Any, ) -> None: @@ -196,9 +195,9 @@ class PdfFileViewAction(ViewAction): def __init__[RequestT: CoreRequest]( self, - model: type | str, - load: Callable[[RequestT], Any] | str | None = None, - permission: object | str = Public, + model: type, + load: Callable[[RequestT], Any] | None = None, + permission: object = Public, internal: bool = False, **predicates: Any, ) -> None: @@ -220,9 +219,9 @@ class JsonFileAction(ViewAction): def __init__[RequestT: CoreRequest]( self, - model: type | str, - load: Callable[[RequestT], Any] | str | None = None, - permission: object | str = Public, + model: type, + load: Callable[[RequestT], Any] | None = None, + permission: object = Public, internal: bool = False, **predicates: Any, ) -> None: @@ -244,9 +243,9 @@ class CsvFileAction(ViewAction): def __init__[RequestT: CoreRequest]( self, - model: type | str, - load: Callable[[RequestT], Any] | str | None = None, - permission: object | str = Public, + model: type, + load: Callable[[RequestT], Any] | None = None, + permission: object = Public, internal: bool = False, **predicates: Any, ) -> None: @@ -286,13 +285,13 @@ def __init__(self, tag: str, category: str): self.tag = tag self.category = category - def identifier( # type:ignore[override] + def identifier( self, screen_widget_registry: ScreenWidgetRegistry ) -> str: return self.tag - def perform( # type:ignore[override] + def perform( self, func: Callable[[], InputScreenWidget], screen_widget_registry: ScreenWidgetRegistry diff --git a/src/onegov/election_day/request.py b/src/onegov/election_day/request.py index ab5e19280f..f70792c413 100644 --- a/src/onegov/election_day/request.py +++ b/src/onegov/election_day/request.py @@ -3,13 +3,21 @@ from onegov.core.request import CoreRequest +from typing import TypeVar from typing import TYPE_CHECKING if TYPE_CHECKING: from onegov.election_day.app import ElectionDayApp +AppT = TypeVar( + 'AppT', + bound='ElectionDayApp', + default='ElectionDayApp', + covariant=True +) + + # NOTE: Currently this is purely for type checking, so we know the requests # in our election day app have the election day app available -class ElectionDayRequest(CoreRequest): - if TYPE_CHECKING: - app: ElectionDayApp +class ElectionDayRequest(CoreRequest[AppT]): + pass diff --git a/src/onegov/election_day/security.py b/src/onegov/election_day/security.py index 8225071702..9489e042fa 100644 --- a/src/onegov/election_day/security.py +++ b/src/onegov/election_day/security.py @@ -9,7 +9,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from morepath.authentication import Identity + from onegov.core import Identity class MaybePublic(Intent): diff --git a/src/onegov/feriennet/app.py b/src/onegov/feriennet/app.py index d57018a0ac..ba23b4458c 100644 --- a/src/onegov/feriennet/app.py +++ b/src/onegov/feriennet/app.py @@ -22,7 +22,7 @@ from onegov.user import User, UserCollection -from typing import Any, TYPE_CHECKING +from typing import Any, Self, TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Callable, Iterator, Sequence from onegov.feriennet.sponsors import Sponsor @@ -34,7 +34,7 @@ class FeriennetApp(TownApp): - request_class = FeriennetRequest + request_class: type[FeriennetRequest[Self]] = FeriennetRequest def fts_may_use_private_search( self, diff --git a/src/onegov/feriennet/collections/activity.py b/src/onegov/feriennet/collections/activity.py index 3ce95712a6..7b48ae3aae 100644 --- a/src/onegov/feriennet/collections/activity.py +++ b/src/onegov/feriennet/collections/activity.py @@ -7,8 +7,9 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from morepath.authentication import Identity, NoIdentity + from morepath.authentication import NoIdentity from onegov.activity.collections.activity import ActivityFilter + from onegov.core import Identity from onegov.feriennet.models import VacationActivity from sqlalchemy.orm import Query, Session from typing import Self diff --git a/src/onegov/feriennet/policy.py b/src/onegov/feriennet/policy.py index 420bd9e12a..aa91158354 100644 --- a/src/onegov/feriennet/policy.py +++ b/src/onegov/feriennet/policy.py @@ -8,7 +8,8 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from morepath.authentication import Identity, NoIdentity + from morepath.authentication import NoIdentity + from onegov.core import Identity from sqlalchemy.orm import Query from typing import Self diff --git a/src/onegov/feriennet/request.py b/src/onegov/feriennet/request.py index 71343fb42d..76d21f3d44 100644 --- a/src/onegov/feriennet/request.py +++ b/src/onegov/feriennet/request.py @@ -4,14 +4,20 @@ from onegov.town6.request import TownRequest -from typing import TYPE_CHECKING +from typing import TypeVar, TYPE_CHECKING if TYPE_CHECKING: from onegov.feriennet.app import FeriennetApp -class FeriennetRequest(TownRequest): +AppT = TypeVar( + 'AppT', + bound='FeriennetApp', + default='FeriennetApp', + covariant=True +) - app: FeriennetApp + +class FeriennetRequest(TownRequest[AppT]): @cached_property def is_organiser(self) -> bool: diff --git a/src/onegov/feriennet/security.py b/src/onegov/feriennet/security.py index abf3d6af6f..c35cf68b70 100644 --- a/src/onegov/feriennet/security.py +++ b/src/onegov/feriennet/security.py @@ -18,7 +18,8 @@ from typing import Any, TYPE_CHECKING if TYPE_CHECKING: - from morepath.authentication import Identity, NoIdentity + from morepath.authentication import NoIdentity + from onegov.core import Identity from onegov.core.security.roles import Intent diff --git a/src/onegov/fsi/app.py b/src/onegov/fsi/app.py index d174452dd5..0a41da4729 100644 --- a/src/onegov/fsi/app.py +++ b/src/onegov/fsi/app.py @@ -10,7 +10,7 @@ from onegov.town6.app import get_i18n_localedirs as get_town6_i18n_localedirs -from typing import Any, TYPE_CHECKING +from typing import Any, Self, TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Callable, Iterator from onegov.core.request import CoreRequest @@ -20,7 +20,7 @@ class FsiApp(TownApp): - request_class = FsiRequest + request_class: type[FsiRequest[Self]] = FsiRequest # FSI doesn't really deal with tickets much, so no reason to send the # ticket statistics. diff --git a/src/onegov/fsi/request.py b/src/onegov/fsi/request.py index 4d8b48d5c8..daa2f0d6cc 100644 --- a/src/onegov/fsi/request.py +++ b/src/onegov/fsi/request.py @@ -4,13 +4,17 @@ from onegov.town6.request import TownRequest -from typing import TYPE_CHECKING +from typing import TypeVar, TYPE_CHECKING if TYPE_CHECKING: + from onegov.fsi.app import FsiApp from onegov.fsi.models import CourseAttendee from uuid import UUID -class FsiRequest(TownRequest): +AppT = TypeVar('AppT', bound='FsiApp', default='FsiApp', covariant=True) + + +class FsiRequest(TownRequest[AppT]): @cached_property def attendee(self) -> CourseAttendee | None: diff --git a/src/onegov/fsi/security.py b/src/onegov/fsi/security.py index c8035cc822..729e7683ec 100644 --- a/src/onegov/fsi/security.py +++ b/src/onegov/fsi/security.py @@ -10,7 +10,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from morepath.authentication import Identity + from onegov.core import Identity from onegov.core.security.roles import Intent """ diff --git a/src/onegov/landsgemeinde/request.py b/src/onegov/landsgemeinde/request.py index 5832b36ca1..c5d03ee1bb 100644 --- a/src/onegov/landsgemeinde/request.py +++ b/src/onegov/landsgemeinde/request.py @@ -3,13 +3,20 @@ from onegov.town6.request import TownRequest -from typing import TYPE_CHECKING +from typing import TypeVar, TYPE_CHECKING if TYPE_CHECKING: from onegov.landsgemeinde.app import LandsgemeindeApp +AppT = TypeVar( + 'AppT', + bound='LandsgemeindeApp', + default='LandsgemeindeApp', + covariant=True +) + + # NOTE: Currently this is purely for type checking # so we get the correct app on the request -class LandsgemeindeRequest(TownRequest): - if TYPE_CHECKING: - app: LandsgemeindeApp +class LandsgemeindeRequest(TownRequest[AppT]): + pass diff --git a/src/onegov/org/app.py b/src/onegov/org/app.py index a4bce1a959..1cb41b5450 100644 --- a/src/onegov/org/app.py +++ b/src/onegov/org/app.py @@ -38,31 +38,31 @@ from onegov.user import UserApp from onegov.websockets import WebsocketsApp from purl import URL -from types import MethodType from webob import Response from webob.exc import WSGIHTTPException -from typing import Any, Literal, TYPE_CHECKING +from typing import Any, Literal, Self, TYPE_CHECKING if TYPE_CHECKING: from _typeshed import StrPath from collections.abc import ( Callable, Collection, Iterable, Iterator, Sequence) from more.content_security import ContentSecurityPolicy - from morepath.authentication import Identity, NoIdentity + from morepath.authentication import NoIdentity + from onegov.core import Identity from onegov.core.mail import Attachment from onegov.core.types import EmailJsonDict, SequenceOrScalar from onegov.pay import Price from onegov.ticket import Ticket from onegov.ticket.collection import TicketCount - from reg.dispatch import _KeyLookup + from reg.types import KeyLookup class OrgApp(Framework, LibresIntegration, SearchApp, MapboxApp, DepotApp, PayApp, FormApp, UserApp, WebsocketsApp, ApiApp): serve_static_files = True - request_class = OrgRequest + request_class: type[OrgRequest[Self]] = OrgRequest #: org directives homepage_widget = directive(directives.HomepageWidgetAction) @@ -175,9 +175,7 @@ def configure_mtan_hook(self, **cfg: Any) -> None: # it on the instance, this should be a unique instance of the method # per instance, and an unique instance of the function per class get_view_meth = self.get_view - assert isinstance(get_view_meth, MethodType) get_view = get_view_meth.__func__ - assert hasattr(get_view, 'key_lookup') key_lookup = get_view.key_lookup if not isinstance(key_lookup, KeyLookupWithMTANHook): get_view.key_lookup = KeyLookupWithMTANHook(key_lookup) @@ -193,7 +191,7 @@ def configure_mtan_hook(self, **cfg: Any) -> None: # this should be safe, since each class gets its own dispatch # but it is ugly that we have to access the dispatch using the # __self__ on one of the methods - assert hasattr(get_view, 'clean') + assert hasattr(get_view.clean, '__self__') dispatch = get_view.clean.__self__ if not getattr(dispatch, '_mtan_hook_configured', False): orig_get_key_lookup = dispatch.get_key_lookup @@ -1025,7 +1023,7 @@ def wrapped(self: OrgApp, obj: Any, request: OrgRequest) -> Any: class KeyLookupWithMTANHook: - def __init__(self, key_lookup: _KeyLookup): + def __init__(self, key_lookup: KeyLookup): self.key_lookup = key_lookup def component( @@ -1051,5 +1049,5 @@ def fallback( def all( self, key: Sequence[Any] - ) -> Iterator[Callable[..., Any]]: + ) -> Iterable[Callable[..., Any]]: return self.key_lookup.all(key) diff --git a/src/onegov/org/converters.py b/src/onegov/org/converters.py index 7efe6efde8..7aa2d9bb5b 100644 --- a/src/onegov/org/converters.py +++ b/src/onegov/org/converters.py @@ -75,5 +75,5 @@ def keywords_decode(text: str) -> dict[str, list[str]] | None: keywords_converter = morepath.Converter( decode=keywords_decode, - encode=keywords_encode # type: ignore[arg-type] + encode=keywords_encode ) diff --git a/src/onegov/org/directives.py b/src/onegov/org/directives.py index 8954edb408..14e3773397 100644 --- a/src/onegov/org/directives.py +++ b/src/onegov/org/directives.py @@ -84,13 +84,13 @@ class HomepageWidgetAction(Action): def __init__(self, tag: str) -> None: self.tag = tag - def identifier( # type:ignore[override] + def identifier( self, homepage_widget_registry: dict[str, RegisteredHomepageWidget] ) -> str: return self.tag - def perform( # type:ignore[override] + def perform( self, func: Callable[[], HomepageWidget], homepage_widget_registry: dict[str, RegisteredHomepageWidget] @@ -113,13 +113,13 @@ def __init__(self, id: str, **kwargs: Any) -> None: self.kwargs = kwargs self.kwargs['id'] = id - def identifier( # type:ignore[override] + def identifier( self, export_registry: dict[str, Any] ) -> str: return self.id - def perform( # type:ignore[override] + def perform( self, cls: Callable[..., Any], export_registry: dict[str, Any] @@ -139,13 +139,13 @@ class UserlinkAction(Action): def __init__(self) -> None: self.name = next(self.counter) - def identifier( # type:ignore[override] + def identifier( self, linkgroup_registry: list[LinkGroupFactory] ) -> int: return self.name - def perform( # type:ignore[override] + def perform( self, func: LinkGroupFactory, linkgroup_registry: list[LinkGroupFactory] @@ -163,13 +163,13 @@ class DirectorySearchWidgetAction(Action): def __init__(self, name: str) -> None: self.name = name - def identifier( # type:ignore[override] + def identifier( self, directory_search_widget_registry: DirectorySearchWidgetRegistry ) -> str: return self.name - def perform( # type:ignore[override] + def perform( self, cls: type[DirectorySearchWidget[Any]], directory_search_widget_registry: DirectorySearchWidgetRegistry @@ -194,13 +194,13 @@ class EventSearchWidgetAction(Action): def __init__(self, name: str) -> None: self.name = name - def identifier( # type:ignore[override] + def identifier( self, event_search_widget_registry: EventSearchWidgetRegistry ) -> str: return self.name - def perform( # type:ignore[override] + def perform( self, cls: type[EventSearchWidget], event_search_widget_registry: EventSearchWidgetRegistry @@ -236,23 +236,23 @@ def __init__( """ self.name = name - self.order = order + self.boardlet_order = order self.icon = icon self.kind = kind - def identifier( # type:ignore[override] + def identifier( self, boardlets_registry: dict[BoardletKind, dict[str, BoardletConfig]] ) -> str: return f'{self.kind}-{self.name}' - def perform( # type:ignore[override] + def perform( self, func: type[_Boardlet], boardlets_registry: dict[BoardletKind, dict[str, BoardletConfig]] ) -> None: boardlets_registry[self.kind][self.name] = { 'cls': func, - 'order': self.order, + 'order': self.boardlet_order, 'icon': self.icon, } diff --git a/src/onegov/org/forms/resource.py b/src/onegov/org/forms/resource.py index 189ccb1b8a..fd53bbcc59 100644 --- a/src/onegov/org/forms/resource.py +++ b/src/onegov/org/forms/resource.py @@ -389,9 +389,9 @@ def on_request(self) -> None: self.delete_field('kaba_components') return else: - if not self.request.view_name.endswith('new-room'): + if not (self.request.view_name or '').endswith('new-room'): self.delete_field('parent_id') - if self.request.view_name.endswith('new-daypass'): + if (self.request.view_name or '').endswith('new-daypass'): self.delete_field('default_view') self.delete_field('kaba_components') return diff --git a/src/onegov/org/request.py b/src/onegov/org/request.py index f94526acb8..c7cd48f513 100644 --- a/src/onegov/org/request.py +++ b/src/onegov/org/request.py @@ -15,7 +15,7 @@ from sqlalchemy.orm import noload -from typing import Any, NamedTuple, TYPE_CHECKING +from typing import Any, NamedTuple, TypeVar, TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Generator, Iterable from onegov.core.analytics import AnalyticsProvider @@ -25,6 +25,9 @@ from onegov.ticket import Ticket +AppT = TypeVar('AppT', bound='OrgApp', default='OrgApp', covariant=True) + + @msgpack.make_serializable(tag=20) class PageMeta(NamedTuple): id: int @@ -53,10 +56,7 @@ def link( ) -class OrgRequest(CoreRequest): - - if TYPE_CHECKING: - app: OrgApp +class OrgRequest(CoreRequest[AppT]): @cached_property def is_manager(self) -> bool: diff --git a/src/onegov/org/security.py b/src/onegov/org/security.py index b3d4352f4c..bd292c425a 100644 --- a/src/onegov/org/security.py +++ b/src/onegov/org/security.py @@ -14,7 +14,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from morepath.authentication import Identity + from onegov.core import Identity from onegov.core.security.roles import Intent diff --git a/src/onegov/org/views/settings.py b/src/onegov/org/views/settings.py index 066c984809..ddd1806989 100644 --- a/src/onegov/org/views/settings.py +++ b/src/onegov/org/views/settings.py @@ -74,6 +74,7 @@ def query_settings() -> Iterator[dict[str, Any]]: q = Query('view').filter(model=Organisation) for action, fn in q(request.app): + assert hasattr(action, 'predicates') if 'setting' in action.predicates: setting = copy(action.predicates) # exclude this setting view if it's disabled for the app diff --git a/src/onegov/pas/app.py b/src/onegov/pas/app.py index c7736aeb39..16858cf491 100644 --- a/src/onegov/pas/app.py +++ b/src/onegov/pas/app.py @@ -15,12 +15,12 @@ from purl import URL -from typing import Any, Literal, TYPE_CHECKING +from typing import Any, Literal, Self, TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Callable, Iterator - from onegov.core.types import RenderData from morepath.authentication import NoIdentity - from morepath.authentication import Identity + from onegov.core import Identity + from onegov.core.types import RenderData from onegov.user import User from onegov.user.integration import EnsureUserCallback @@ -28,7 +28,7 @@ class PasApp(TownApp): - request_class = PasRequest + request_class: type[PasRequest[Self]] = PasRequest def configure_organisation( self, @@ -79,7 +79,7 @@ def redirect_after_login( @PasApp.setting(section='org', name='create_new_organisation') def get_create_new_organisation_factory( -) -> Callable[[TownApp, str], Organisation]: +) -> Callable[[PasApp, str], Organisation]: return create_new_organisation diff --git a/src/onegov/pas/cronjobs.py b/src/onegov/pas/cronjobs.py index e80d001e45..ea4a03b25d 100644 --- a/src/onegov/pas/cronjobs.py +++ b/src/onegov/pas/cronjobs.py @@ -12,9 +12,8 @@ from onegov.pas.models import ImportLog from sqlalchemy.orm.attributes import flag_modified -from typing import Any, TYPE_CHECKING, cast +from typing import Any, TYPE_CHECKING if TYPE_CHECKING: - from onegov.pas.app import PasApp as PasAppType from onegov.pas.request import PasRequest log = logging.getLogger('onegov.pas.cronjobs') @@ -66,7 +65,7 @@ def trigger_kub_data_import( kub_token, kub_base_url, output_handler, cert=cert ) as importer: combined_results, import_log_id = importer.run_full_sync( - request, cast('PasAppType', app), import_type + request, app, import_type ) # Sync user accounts right after import diff --git a/src/onegov/pas/request.py b/src/onegov/pas/request.py index e8d339b917..6c3f3857f7 100644 --- a/src/onegov/pas/request.py +++ b/src/onegov/pas/request.py @@ -5,12 +5,16 @@ from functools import cached_property from onegov.town6.request import TownRequest -from typing import TYPE_CHECKING +from typing import TypeVar, TYPE_CHECKING if TYPE_CHECKING: + from onegov.pas.app import PasApp from onegov.pas.models import PASParliamentarian -class PasRequest(TownRequest): +AppT = TypeVar('AppT', bound='PasApp', default='PasApp', covariant=True) + + +class PasRequest(TownRequest[AppT]): @cached_property def is_parliamentarian(self) -> bool: diff --git a/src/onegov/pas/security.py b/src/onegov/pas/security.py index 685664953f..e095df216e 100644 --- a/src/onegov/pas/security.py +++ b/src/onegov/pas/security.py @@ -21,8 +21,8 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: from typing import Any + from onegov.core import Identity from onegov.core.security.roles import Intent - from morepath import Identity """ diff --git a/src/onegov/server/utils.py b/src/onegov/server/utils.py index c5b4fcd738..e81e9e5177 100644 --- a/src/onegov/server/utils.py +++ b/src/onegov/server/utils.py @@ -35,13 +35,13 @@ def patch_morepath() -> None: if hasattr(morepath.autosetup, '_onegov_patch'): return - _get_module_name = morepath.autosetup.get_module_name # type: ignore[attr-defined] + _get_module_name = morepath.autosetup.get_module_name - def get_module_name(distribution: object) -> str: + def get_module_name(distribution: importlib.metadata.Distribution) -> str: name = _get_module_name(distribution) if name.startswith('more_'): return 'more.' + name[5:] return name - morepath.autosetup.get_module_name = get_module_name # type: ignore[attr-defined] + morepath.autosetup.get_module_name = get_module_name morepath.autosetup._onegov_patch = True # type: ignore[attr-defined] diff --git a/src/onegov/town6/request.py b/src/onegov/town6/request.py index 161b07a101..3f51e29759 100644 --- a/src/onegov/town6/request.py +++ b/src/onegov/town6/request.py @@ -3,13 +3,15 @@ from onegov.org.request import OrgRequest -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, TypeVar if TYPE_CHECKING: from onegov.town6.app import TownApp +AppT = TypeVar('AppT', bound='TownApp', default='TownApp', covariant=True) + + # NOTE: Currently this is purely for type checking, so we know the requests -# in our election day app have the election day app available -class TownRequest(OrgRequest): - if TYPE_CHECKING: - app: TownApp +# in our town app have the town app available +class TownRequest(OrgRequest[AppT]): + pass diff --git a/src/onegov/translator_directory/app.py b/src/onegov/translator_directory/app.py index 835ed35d1e..e1808d8fa3 100644 --- a/src/onegov/translator_directory/app.py +++ b/src/onegov/translator_directory/app.py @@ -17,17 +17,18 @@ from sqlalchemy import and_ -from typing import Any, TYPE_CHECKING +from typing import Any, Self, TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Callable, Iterator - from morepath.authentication import Identity, NoIdentity + from morepath.authentication import NoIdentity + from onegov.core import Identity from onegov.gis.models.coordinates import AnyCoordinates class TranslatorDirectoryApp(TownApp): send_ticket_statistics = False - request_class = TranslatorAppRequest + request_class: type[TranslatorAppRequest[Self]] = TranslatorAppRequest def fts_may_use_private_search( self, diff --git a/src/onegov/translator_directory/request.py b/src/onegov/translator_directory/request.py index 85e6096743..8fbc1ab180 100644 --- a/src/onegov/translator_directory/request.py +++ b/src/onegov/translator_directory/request.py @@ -5,14 +5,21 @@ from onegov.user import UserGroup +from typing import TypeVar from typing import TYPE_CHECKING if TYPE_CHECKING: from onegov.translator_directory.app import TranslatorDirectoryApp -class TranslatorAppRequest(TownRequest): +AppT = TypeVar( + 'AppT', + bound='TranslatorDirectoryApp', + default='TranslatorDirectoryApp', + covariant=True +) - app: TranslatorDirectoryApp + +class TranslatorAppRequest(TownRequest[AppT]): @cached_property def is_member(self) -> bool: diff --git a/src/onegov/translator_directory/security.py b/src/onegov/translator_directory/security.py index 2655057ee3..8438debe19 100644 --- a/src/onegov/translator_directory/security.py +++ b/src/onegov/translator_directory/security.py @@ -20,7 +20,8 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from morepath.authentication import Identity, NoIdentity + from morepath.authentication import NoIdentity + from onegov.core import Identity from onegov.core.security.roles import Intent """ diff --git a/src/onegov/user/integration.py b/src/onegov/user/integration.py index d36aeb4ab7..bab4e676dd 100644 --- a/src/onegov/user/integration.py +++ b/src/onegov/user/integration.py @@ -17,6 +17,8 @@ if TYPE_CHECKING: from collections.abc import Callable, Collection, Iterator, Mapping from functools import cached_property + from morepath.authentication import NoIdentity + from onegov.core import Identity from onegov.core.cache import RedisCacheRegion from onegov.core.request import CoreRequest from onegov.user import User @@ -105,7 +107,7 @@ def on_login(self, request: CoreRequest, user: User) -> None: def redirect_after_login( self, - identity: morepath.Identity, + identity: Identity | NoIdentity, request: CoreRequest, default: str ) -> str | None: diff --git a/stubs/dectate/__init__.pyi b/stubs/dectate/__init__.pyi deleted file mode 100644 index c1fdb3c1cc..0000000000 --- a/stubs/dectate/__init__.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from .app import App as App, directive as directive -from .config import Action as Action, CodeInfo as CodeInfo, Composite as Composite, commit as commit -from .error import ( - ConfigError as ConfigError, - ConflictError as ConflictError, - DirectiveError as DirectiveError, - DirectiveReportError as DirectiveReportError, - QueryError as QueryError, - TopologicalSortError as TopologicalSortError, -) -from .query import Query as Query -from .sentinel import NOT_FOUND as NOT_FOUND, Sentinel as Sentinel -# from .tool import ( -# convert_bool as convert_bool, -# convert_dotted_name as convert_dotted_name, -# query_app as query_app, -# query_tool as query_tool, -# ) -# from .toposort import topological_sort as topological_sort diff --git a/stubs/dectate/app.pyi b/stubs/dectate/app.pyi deleted file mode 100644 index 0831a126fa..0000000000 --- a/stubs/dectate/app.pyi +++ /dev/null @@ -1,42 +0,0 @@ -import _typeshed -from collections.abc import Callable, Collection, Iterator -from typing import Any, Protocol, TypeVar, overload -from typing_extensions import ParamSpec, Self - -from dectate.config import Action, Composite, Configurable, Directive - -_ActionT = TypeVar('_ActionT', bound=Action | Composite) -_AppT = TypeVar('_AppT', bound=App) -_P = ParamSpec('_P') - -class _DirectiveCallable(Protocol[_P]): - action_factory: type[Action | Composite] - def __call__(self, *args: _P.args, **kwargs: _P.kwargs) -> Directive: ... - -class _DirectiveMethod(classmethod[_AppT, _P, Directive]): - action_factory: type[Action | Composite] - @overload - def __get__(self, instance: _AppT, owner: type[_AppT] | None = None, /) -> _DirectiveCallable[_P]: ... - @overload - def __get__(self, instance: None, owner: type[_AppT], /) -> _DirectiveCallable[_P]: ... - -class Config: - def __getattr__(self, name: str) -> Any: ... - -class AppMeta(type): - def __new__(cls: type[_typeshed.Self], name: str, bases: tuple[type[Any], ...], d: dict[str, Any]) -> _typeshed.Self: ... - -class App(metaclass=AppMeta): - logger_name: str - dectate: Configurable - config: Config - @classmethod - def get_directive_methods(cls) -> Iterator[tuple[str, _DirectiveMethod[Self, ...]]]: ... - @classmethod - def commit(cls) -> Collection[type[App]]: ... - @classmethod - def is_committed(cls) -> bool: ... - @classmethod - def clean(cls) -> None: ... - -def directive(action_factory: Callable[_P, _ActionT]) -> _DirectiveMethod[Any, _P]: ... diff --git a/stubs/dectate/config.pyi b/stubs/dectate/config.pyi deleted file mode 100644 index 7067bb6217..0000000000 --- a/stubs/dectate/config.pyi +++ /dev/null @@ -1,112 +0,0 @@ -import abc -from collections.abc import Callable, Iterable, Iterator -from types import FrameType, TracebackType -from typing import Any, ClassVar, TypeVar - -from .app import App, Config -from .sentinel import Sentinel - -_T = TypeVar('_T') -_F = TypeVar('_F', bound=Callable[..., Any]) - -order_count: int - -class Configurable: - _directives: list[tuple[Directive, object]] - app_class: type[App] | None - extends: list[Configurable] - config: Config - committed: bool - def __init__(self, extends: list[Configurable], config: Config): ... - def register_directive(self, directive: Directive, obj: Any) -> None: ... - def get_action_classes(self) -> dict[type[Action], str]: ... - def setup(self) -> None: ... - def setup_config(self, action_class: type[Action]) -> None: ... - def delete_config(self, action_class: type[Action]) -> None: ... - def group_actions(self) -> None: ... - def get_action_group(self, action_class: type[Action]) -> ActionGroup | None: ... - def action_extends(self, action_class: type[Action]) -> list[ActionGroup]: ... - def execute(self) -> None: ... - -class ActionGroup: - action_class: type[Action] - extends: list[ActionGroup] - def __init__(self, action_class: type[Action], extends: list[ActionGroup]) -> None: ... - def add(self, action: Action, obj: Any) -> None: ... - def prepare(self, configurable: Configurable) -> None: ... - def get_actions(self) -> list[Action]: ... - def combine(self, actions: list[ActionGroup]) -> None: ... - def execute(self, configurable: Configurable) -> None: ... - -class Action(metaclass=abc.ABCMeta): - config: ClassVar[dict[str, Callable[..., Any]]] - app_class_arg: bool - depends: list[type[Action]] - group_class: type[Action] | None - filter_name: dict[str, str] - def filter_get_value(self, name: str) -> Any | Sentinel: ... - filter_compare: dict[str, Callable[[Any, Any], bool]] - filter_convert: dict[str, Callable[[str], Any]] - directive: Directive | None - def __init__(self) -> None: ... - @property - def code_info(self) -> CodeInfo | None: ... - def get_value_for_filter(self, name: str) -> Any | Sentinel: ... - @abc.abstractmethod - def identifier(self, **kw: Any) -> Any: ... - def discriminators(self, **kw: Any) -> Iterable[Any]: ... - @abc.abstractmethod - def perform(self, obj: Any, **kw: Any) -> None: ... - @staticmethod - def before(**kw: Any) -> None: ... - @staticmethod - def after(**kw: Any) -> None: ... - -class Composite(metaclass=abc.ABCMeta): - query_classes: list[type[Action]] - filter_convert: dict[str, Callable[[str], Any]] - def __init__(self) -> None: ... - @property - def code_info(self) -> CodeInfo | None: ... - @abc.abstractmethod - def actions(self, obj: Any) -> Iterable[tuple[Action, Any]]: ... - -class Directive: - action_factory: Callable[..., Action] - code_info: CodeInfo - app_class: type[App] - configurable: Configurable - args: tuple[Any, ...] - kw: dict[str, Any] - argument_info: tuple[tuple[Any, ...], dict[str, Any]] - def __init__(self, action_factory: Callable[..., Action], code_info: CodeInfo, app_class: type[App], args: tuple[Any, ...], kw: dict[str, Any]) -> None: ... - @property - def directive_name(self) -> str: ... - def action(self) -> Action: ... - def __enter__(self) -> DirectiveAbbreviation: ... - def __exit__(self, type: type[BaseException] | None, value: BaseException | None, tb: TracebackType | None) -> None: ... - def __call__(self, wrapped: _T) -> _T: ... - def log(self, configurable: Configurable, obj: Any) -> None: ... - -class DirectiveAbbreviation: - directive: Directive - def __init__(self, directive: Directive) -> None: ... - def __call__(self, *args: Any, **kw: Any) -> Directive: ... - -def commit(*apps: type[App]) -> None: ... -def sort_configurables(configurables: Iterable[Configurable]) -> list[Configurable]: ... -def sort_action_classes(action_classes: Iterable[type[Action]]) -> list[type[Action]]: ... -def group_action_classes(action_classes: Iterable[type[Action]]) -> set[type[Action]]: ... -def expand_actions(actions: Iterable[Action | Composite]) -> Iterator[Action]: ... - -class CodeInfo: - path: str - lineno: int - sourceline: str - def __init__(self, path: str, lineno: int, sourceline: str) -> None: ... - def filelineno(self) -> str: ... - -def create_code_info(frame: FrameType) -> CodeInfo: ... -def factory_key(item: tuple[str, _F]) -> Iterable[tuple[str, _F]]: ... -def get_factory_arguments(action_class: type[Action], config: Config, factory: Callable[..., Any], app_class: type[App]) -> dict[str, Any]: ... -def dotted_name(cls: type) -> str: ... diff --git a/stubs/dectate/error.pyi b/stubs/dectate/error.pyi deleted file mode 100644 index 5207a11e51..0000000000 --- a/stubs/dectate/error.pyi +++ /dev/null @@ -1,16 +0,0 @@ -from dectate.config import Action, CodeInfo - -class ConfigError(Exception): ... - -def conflict_keyfunc(action: Action) -> tuple[str, int]: ... - -class ConflictError(ConfigError): - actions: list[Action] - def __init__(self, actions: list[Action]) -> None: ... - -class DirectiveReportError(ConfigError): - def __init__(self, message: str, code_info: CodeInfo) -> None: ... - -class DirectiveError(ConfigError): ... -class TopologicalSortError(ValueError): ... -class QueryError(Exception): ... diff --git a/stubs/dectate/query.pyi b/stubs/dectate/query.pyi deleted file mode 100644 index 8ab0b513dc..0000000000 --- a/stubs/dectate/query.pyi +++ /dev/null @@ -1,48 +0,0 @@ -from collections.abc import Iterable, Iterator, Sequence -from typing import Any, Generic, TypeVar, overload - -from dectate.app import App -from dectate.config import Action, Composite, Configurable - -_ActionT = TypeVar('_ActionT', bound=Action) - -class Callable(Generic[_ActionT]): - def __call__(self, app_class: type[App] | App) -> Iterator[Any]: ... - -class Base(Callable[_ActionT]): - def filter(self, **kw: object) -> Filter[_ActionT]: ... - def attrs(self, *names: str) -> Attrs: ... - def obj(self) -> Obj: ... - -class Query(Base[_ActionT]): - action_classes: tuple[type[_ActionT | Composite] | str, ...] - @overload - def __init__(self: Query[_ActionT], *action_classes: type[_ActionT]) -> None: ... - @overload - def __init__(self: Query[Any], *action_classes: type[Action | Composite] | str) -> None: ... - def execute(self, configurable: Configurable) -> Iterator[tuple[Action, Any]]: ... - def __call__(self, app_class: type[App] | App) -> Iterator[tuple[_ActionT, Any]]: ... - -def expand_action_classes(action_classes: Iterable[type[Action | Composite]]) -> set[type[Action]]: ... -def query_action_classes(configurable: Configurable, action_classes: Iterable[type[Action | Composite]]) -> Iterator[tuple[Action, Any]]: ... -def get_action_class(app_class: type[App] | App, directive_name: str) -> type[Action | Composite]: ... -def compare_equality(compared: object, value: object) -> bool: ... - -class Filter(Base[_ActionT]): - query: Query[_ActionT] - kw: dict[str, Any] - def __init__(self, query: Query[_ActionT], **kw: Any) -> None: ... - def execute(self, configurable: Configurable) -> Iterator[tuple[_ActionT, Any]]: ... - def __call__(self, app_class: type[App] | App) -> Iterator[tuple[_ActionT, Any]]: ... - -class Attrs(Callable[Any]): - query: Query[Any] - names: Sequence[str] - def __init__(self, query: Query[Any], names: Sequence[str]) -> None: ... - def execute(self, configurable: Configurable) -> Iterator[dict[str, Any]]: ... - def __call__(self, app_class: type[App] | App) -> Iterator[dict[str, Any]]: ... - -class Obj(Callable[Any]): - query: Query[Any] - def __init__(self, query: Query[Any]) -> None: ... - def execute(self, configurable: Configurable) -> Iterator[Any]: ... diff --git a/stubs/dectate/sentinel.pyi b/stubs/dectate/sentinel.pyi deleted file mode 100644 index aad09e7382..0000000000 --- a/stubs/dectate/sentinel.pyi +++ /dev/null @@ -1,5 +0,0 @@ -class Sentinel: - name: str - def __init__(self, name: str) -> None: ... - -NOT_FOUND: Sentinel diff --git a/stubs/dectate/tool.pyi b/stubs/dectate/tool.pyi deleted file mode 100644 index 87987d73d6..0000000000 --- a/stubs/dectate/tool.pyi +++ /dev/null @@ -1,4 +0,0 @@ -from types import ModuleType -from typing import Any - -def resolve_dotted_name(name: str, module: ModuleType | None = None) -> Any: ... diff --git a/stubs/more/content_security/__init__.pyi b/stubs/more/content_security/__init__.pyi deleted file mode 100644 index e7291be311..0000000000 --- a/stubs/more/content_security/__init__.pyi +++ /dev/null @@ -1,20 +0,0 @@ -from more.content_security.core import ContentSecurityApp as ContentSecurityApp, ContentSecurityRequest as ContentSecurityRequest -from more.content_security.policy import ( - NONE as NONE, - SELF as SELF, - STRICT_DYNAMIC as STRICT_DYNAMIC, - UNSAFE_EVAL as UNSAFE_EVAL, - UNSAFE_INLINE as UNSAFE_INLINE, - ContentSecurityPolicy as ContentSecurityPolicy, -) - -__all__ = ( - "ContentSecurityApp", - "ContentSecurityPolicy", - "ContentSecurityRequest", - "NONE", - "SELF", - "STRICT_DYNAMIC", - "UNSAFE_INLINE", - "UNSAFE_EVAL", -) diff --git a/stubs/more/content_security/core.pyi b/stubs/more/content_security/core.pyi deleted file mode 100644 index 51a41cffa0..0000000000 --- a/stubs/more/content_security/core.pyi +++ /dev/null @@ -1,25 +0,0 @@ -from collections.abc import Callable -from typing import Literal - -from morepath import App -from morepath.request import Request, Response -from more.content_security.policy import ContentSecurityPolicy - -NONCE_LENGTH: int - -def random_nonce() -> str: ... - -class ContentSecurityRequest(Request): - @property - def content_security_policy(self) -> ContentSecurityPolicy: ... - @content_security_policy.setter - def content_security_policy(self, value: ContentSecurityPolicy) -> None: ... - def content_security_policy_nonce(self, target: Literal["script", "style"]) -> str: ... - @property - def content_security_policy_nonce_value(self) -> str: ... - -class ContentSecurityApp(App): ... - -def default_policy() -> ContentSecurityPolicy: ... -def default_policy_apply_factory() -> Callable[[ContentSecurityPolicy, Request, Response], None]: ... -def content_security_policy_tween_factory(app: ContentSecurityApp, handler: Callable[[Request], Response]) -> Callable[[Request], Response]: ... diff --git a/stubs/more/content_security/policy.pyi b/stubs/more/content_security/policy.pyi deleted file mode 100644 index 58e1890ddc..0000000000 --- a/stubs/more/content_security/policy.pyi +++ /dev/null @@ -1,103 +0,0 @@ -from collections.abc import Callable, Iterator -from typing import Any, Generic, TypeVar, overload -from typing_extensions import Self, TypeAlias, TypeGuard - -from webob.response import Response - -_T = TypeVar('_T') -_Type: TypeAlias = type[_T] - -SELF: str -UNSAFE_INLINE: str -UNSAFE_EVAL: str -NONE: str -STRICT_DYNAMIC: str - -class Directive(Generic[_T]): - name: str - type: _Type[_T] - default: Callable[[], _T] - renderer: Callable[[_T], str | None] - def __init__(self, name: str, type: _Type[_T], default: Callable[[], _T], render: Callable[[_T], str]) -> None: ... - def render(self, instance: ContentSecurityPolicy) -> str | None: ... - @overload - def __get__(self, instance: None, cls: _Type[ContentSecurityPolicy]) -> Self: ... - @overload - def __get__(self, instance: ContentSecurityPolicy, cls: _Type[ContentSecurityPolicy]) -> _T: ... - def __set__(self, instance: ContentSecurityPolicy, value: _T) -> None: ... - -class SetDirective(Directive[set[str]]): - def __init__(self, name: str) -> None: ... - -class SingleValueDirective(Directive[str]): - def __init__(self, name: str) -> None: ... - -class BooleanDirective(Directive[bool]): - def __init__(self, name: str) -> None: ... - -def is_directive(obj: object) -> TypeGuard[Directive[Any]]: ... -def render_set(value: set[str]) -> str: ... -def render_bool(value: bool) -> str | None: ... - -class ContentSecurityPolicy: - child_src: SetDirective - connect_src: SetDirective - default_src: SetDirective - font_src: SetDirective - frame_src: SetDirective - img_src: SetDirective - manifest_src: SetDirective - media_src: SetDirective - object_src: SetDirective - script_src: SetDirective - style_src: SetDirective - worker_src: SetDirective - base_uri: SetDirective - plugin_types: SetDirective - sandbox: SingleValueDirective - disown_opener: BooleanDirective - form_action: SetDirective - frame_ancestors: SetDirective - report_uri: SingleValueDirective - report_to: SingleValueDirective - block_all_mixed_content: BooleanDirective - require_sri_for: SingleValueDirective - upgrade_insecure_requeists: BooleanDirective - report_only: bool - def __init__( - self, - report_only: bool = False, - *, - child_src: set[str] = ..., - connect_src: set[str] = ..., - default_src: set[str] = ..., - font_src: set[str] = ..., - frame_src: set[str] = ..., - img_src: set[str] = ..., - manifest_src: set[str] = ..., - media_src: set[str] = ..., - object_src: set[str] = ..., - script_src: set[str] = ..., - style_src: set[str] = ..., - worker_src: set[str] = ..., - base_uri: set[str] = ..., - plugin_types: set[str] = ..., - sandbox: str = ..., - disown_opener: bool = False, - form_action: set[str] = ..., - frame_ancestors: set[str] = ..., - report_uri: str = ..., - report_to: str = ..., - block_all_mixed_content: bool = False, - require_sri_for: str = ..., - upgrade_insecure_requeists: bool = False, - **directives: set[str] | str | bool - ) -> None: ... - def copy(self) -> Self: ... - @property - def directives(self) -> Iterator[SetDirective | SingleValueDirective | BooleanDirective]: ... - @property - def text(self) -> str: ... - @property - def header_name(self) -> str: ... - def apply(self, response: Response) -> None: ... diff --git a/stubs/more/transaction/__init__.pyi b/stubs/more/transaction/__init__.pyi deleted file mode 100644 index 32f75697c1..0000000000 --- a/stubs/more/transaction/__init__.pyi +++ /dev/null @@ -1 +0,0 @@ -from .main import TransactionApp as TransactionApp, default_commit_veto as default_commit_veto diff --git a/stubs/more/transaction/main.pyi b/stubs/more/transaction/main.pyi deleted file mode 100644 index 7978523b09..0000000000 --- a/stubs/more/transaction/main.pyi +++ /dev/null @@ -1,16 +0,0 @@ -from collections.abc import Callable -from typing import Any - -from morepath import App -from morepath.request import Request, Response - -class TransactionApp(App): ... - -def default_commit_veto(request: Request, response: Response) -> bool: ... - -class AbortResponse(Exception): - response: Response - def __init__(self, response: Response) -> None: ... - -def get_transaction_settings() -> dict[str, Any]: ... -def transaction_tween_factory(app: TransactionApp, handler: Callable[[Request], Response]) -> Callable[[Request], Response]: ... diff --git a/stubs/more/webassets/__init__.pyi b/stubs/more/webassets/__init__.pyi deleted file mode 100644 index de5a2606f3..0000000000 --- a/stubs/more/webassets/__init__.pyi +++ /dev/null @@ -1 +0,0 @@ -from more.webassets.core import WebassetsApp as WebassetsApp diff --git a/stubs/more/webassets/core.pyi b/stubs/more/webassets/core.pyi deleted file mode 100644 index a46a59b16d..0000000000 --- a/stubs/more/webassets/core.pyi +++ /dev/null @@ -1,20 +0,0 @@ -from collections.abc import Callable - -from dectate import directive -from more.webassets import directives -from morepath.app import App -from morepath.request import Request, Response - -class IncludeRequest(Request): - included_assets: set[str] - def include(self, resource: str) -> None: ... - -class WebassetsApp(App): - webasset_path = directive(directives.WebassetPath) - webasset_output = directive(directives.WebassetOutput) - webasset_filter = directive(directives.WebassetFilter) - webasset_mapping = directive(directives.WebassetMapping) - webasset_url = directive(directives.WebassetUrl) - webasset = directive(directives.Webasset) - -def webassets_injector_tween(app: WebassetsApp, handler: Callable[[Request], Response]) -> Callable[[Request], Response]: ... diff --git a/stubs/more/webassets/directives.pyi b/stubs/more/webassets/directives.pyi deleted file mode 100644 index 16cebd153b..0000000000 --- a/stubs/more/webassets/directives.pyi +++ /dev/null @@ -1,82 +0,0 @@ -from _typeshed import StrOrBytesPath -from collections.abc import Callable, Collection, Iterator, Mapping, Sequence -from typing_extensions import Self, TypeAlias - -from dectate import Action -from webassets import Bundle, Environment - -_Filter: TypeAlias = str | Collection[str] | None - -class Asset: - name: str - assets: Sequence[str] - filters: Mapping[str, _Filter] | None - def __init__(self, name: str, assets: Sequence[str], filters: Mapping[str, _Filter]) -> None: ... - def __eq__(self, other: object) -> bool: ... - @property - def is_pure(self) -> bool: ... - @property - def is_single_file(self) -> bool: ... - @property - def path(self) -> str: ... - @property - def extension(self) -> str | None: ... - -class WebassetRegistry: - paths: list[str | bytes] - filters: dict[str, _Filter] - filter_product: dict[str, str] - assets: dict[str, Asset] - output_path: str - cached_bundles: dict[str, Bundle] # this appears to be unused - url: str - mapping: dict[str, str] - def __init__(self) -> None: ... - def register_path(self, path: StrOrBytesPath) -> None: ... - def register_filter(self, name: str, filter: _Filter, produces: str | None = None) -> None: ... - def register_asset(self, name: str, assets: Sequence[str], filters: Mapping[str, _Filter] | None = None) -> None: ... - def find_file(self, name: str) -> str: ... - def merge_filters(self, *filters: Mapping[str, _Filter]) -> dict[str, _Filter]: ... - def get_bundles(self, name: str, filters: dict[str, str | None] | None = None) -> Iterator[Bundle]: ... - def get_asset_filters(self, asset: Asset, filters: Mapping[str, _Filter]) -> list[str]: ... - def get_environment(self) -> Environment: ... - -class PathMixin: - def absolute_path(self, path: str) -> str: ... - -class WebassetPath(Action, PathMixin): - def identifier(self, webasset_registry: WebassetRegistry) -> object: ... # type:ignore[override] - def perform(self, obj: Callable[[], str], webasset_registry: WebassetRegistry) -> None: ... # type:ignore[override] - -class WebassetOutput(Action, PathMixin): - group_class = WebassetPath - def identifier(self, webasset_registry: WebassetRegistry) -> type[Self]: ... # type: ignore[override] - def perform(self, obj: Callable[[], str], webasset_registry: WebassetRegistry) -> None: ... # type: ignore[override] - -class WebassetFilter(Action): - group_class = WebassetPath - name: str - produces: str | None - def __init__(self, name: str, produces: str | None = None) -> None: ... - def identifier(self, webasset_registry: WebassetRegistry) -> str: ... # type: ignore[override] - def perform(self, obj: Callable[[], _Filter], webasset_registry: WebassetRegistry) -> None: ... # type: ignore[override] - -class WebassetMapping(Action): - group_class = WebassetPath - name: str - def __init__(self, name: str) -> None: ... - def identifier(self, webasset_registry: WebassetRegistry) -> str: ... # type: ignore[override] - def perform(self, obj: Callable[[], str], webasset_registry: WebassetRegistry) -> None: ... # type: ignore[override] - -class WebassetUrl(Action): - group_class = WebassetPath - def identifier(self, webasset_registry: WebassetRegistry) -> type[Self]: ... # type: ignore[override] - def perform(self, obj: Callable[[], str], webasset_registry: WebassetRegistry) -> None: ... # type: ignore[override] - -class Webasset(Action): - group_class = WebassetPath - name: str - filters: Mapping[str, _Filter] | None - def __init__(self, name: str, filters: Mapping[str, _Filter] | None = None) -> None: ... - def identifier(self, webasset_registry: WebassetRegistry) -> str: ... # type: ignore[override] - def perform(self, obj: Callable[[], Iterator[str]], webasset_registry: WebassetRegistry) -> None: ... # type: ignore[override] diff --git a/stubs/more/webassets/tweens.pyi b/stubs/more/webassets/tweens.pyi deleted file mode 100644 index b410673edd..0000000000 --- a/stubs/more/webassets/tweens.pyi +++ /dev/null @@ -1,28 +0,0 @@ -from _typeshed import StrOrBytesPath -from collections.abc import Callable, Iterator -from urllib.parse import unquote as unquote - -from more.webassets.core import IncludeRequest -from morepath.request import Request, Response -from webassets import Environment - -CONTENT_TYPES: set[str] -METHODS: set[str] -FOREVER: float - -def is_subpath(directory: StrOrBytesPath, path: StrOrBytesPath) -> bool: ... -def has_insecure_path_element(path: str) -> bool: ... - -class InjectorTween: - environment: Environment - handler: Callable[[Request], Response] - def __init__(self, environment: Environment, handler: Callable[[Request], Response]) -> None: ... - def urls_by_resource(self, resource: str) -> list[str]: ... - def urls_to_inject(self, request: IncludeRequest, suffix: str | None = None) -> Iterator[str]: ... - def __call__(self, request: IncludeRequest) -> Response: ... - -class PublisherTween: - environment: Environment - handler: Callable[[Request], Response] - def __init__(self, environment: Environment, handler: Callable[[Request], Response]) -> None: ... - def __call__(self, request: Request) -> Response: ... diff --git a/stubs/morepath/__init__.pyi b/stubs/morepath/__init__.pyi deleted file mode 100644 index fe1f43fd6b..0000000000 --- a/stubs/morepath/__init__.pyi +++ /dev/null @@ -1,33 +0,0 @@ -from collections.abc import Callable -from typing import overload, Generic, TypeVar -from typing_extensions import Self - -from dectate import commit as commit - -from .app import App as App, dispatch_method as dispatch_method -from .authentication import NO_IDENTITY as NO_IDENTITY, Identity as Identity, IdentityPolicy as IdentityPolicy -from .autosetup import autoscan as autoscan, scan as scan -from .converter import Converter as Converter -# from .core import ( -# model_predicate as model_predicate, -# name_predicate as name_predicate, -# request_method_predicate as request_method_predicate, -# ) -from .request import Request as Request, Response as Response -# from .run import run as run -from .view import redirect as redirect, render_html as render_html, render_json as render_json - -_T = TypeVar('_T') -_RT = TypeVar('_RT') - -# this is technically defined in a module, but since the module is called the -# same as the class and the class gets imported into the global module, mypy -# will get confused and shadow the class with the module or vice versa, so -# it is easier to just define the class here -class reify(Generic[_T, _RT]): - wrapped: Callable[[_T], _RT] - def __init__(self: reify[_T, _RT], wrapped: Callable[[_T], _RT]) -> None: ... - @overload - def __get__(self, inst: None, objtype: type[_T] | None = None) -> Self: ... - @overload - def __get__(self, inst: _T, objtype: type[_T] | None = None) -> _RT: ... diff --git a/stubs/morepath/app.pyi b/stubs/morepath/app.pyi deleted file mode 100644 index 892ee15718..0000000000 --- a/stubs/morepath/app.pyi +++ /dev/null @@ -1,84 +0,0 @@ -from _typeshed.wsgi import StartResponse, WSGIEnvironment -from collections.abc import Callable, Iterable, Iterator -from typing import Any, TypeVar, overload - -from dectate.app import App as DectateApp, directive -from morepath import directive as action, reify -from morepath.authentication import Identity, NoIdentity -from morepath.request import Request, Response -from morepath.settings import SettingRegistry -from reg.cache import DictCachingKeyLookup -from reg.context import dispatch_method as _dispatch_method -from reg.dispatch import _GetKeyLookup, _KeyLookup -from reg.predicate import Predicate -from webob.response import Response as BaseResponse - -_AppT = TypeVar('_AppT', bound=App) - -def cached_key_lookup(key_lookup: _KeyLookup) -> DictCachingKeyLookup: ... -def commit_if_needed(app: App) -> None: ... -def dispatch_method(*predicates: str | Predicate, get_key_lookup: _GetKeyLookup = ..., first_invocation_hook: Callable[[Any], object] = ...) -> _dispatch_method[Any, Any, Any]: ... - -class App(DectateApp): - parent: App | None - request_class: type[Request] - logger_name: str - setting = directive(action.SettingAction) - setting_section = directive(action.SettingSectionAction) - predicate_fallback = directive(action.PredicateFallbackAction) - predicate = directive(action.PredicateAction) - method = directive(action.MethodAction) - converter = directive(action.ConverterAction) - _path = directive(action.PathAction) - path = directive(action.PathCompositeAction) - permission_rule = directive(action.PermissionRuleAction) - template_directory = directive(action.TemplateDirectoryAction) - template_loader = directive(action.TemplateLoaderAction) - template_render = directive(action.TemplateRenderAction) - view = directive(action.ViewAction) - json = directive(action.JsonAction) - html = directive(action.HtmlAction) - mount = directive(action.MountAction) - defer_links = directive(action.DeferLinksAction) - defer_class_links = directive(action.DeferClassLinksAction) - tween_factory = directive(action.TweenFactoryAction) - identity_policy = directive(action.IdentityPolicyAction) - verify_identity = directive(action.VerifyIdentityAction) - dump_json = directive(action.DumpJsonAction) - link_prefix = directive(action.LinkPrefixAction) - def __init__(self) -> None: ... - def request(self, environ: WSGIEnvironment) -> Request: ... - def __call__(self, environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: ... - @reify - def publish(self) -> Callable[[Request], Response]: ... - def ancestors(self) -> Iterator[App]: ... - @reify - def root(self) -> App: ... - @overload - def child(self, app: _AppT) -> _AppT | None: ... - @overload - def child(self, app: type[_AppT], **variables: Any) -> _AppT | None: ... - @overload - def child(self, app: str, **variables: Any) -> App: ... - @overload - def sibling(self, app: _AppT) -> _AppT | None: ... - @overload - def sibling(self, app: type[_AppT], **variables: Any) -> _AppT | None: ... - @overload - def sibling(self, app: str, **variables: Any) -> App: ... - @property - def settings(self) -> SettingRegistry: ... - @classmethod - def mounted_app_classes(cls, callback: Callable[..., Any] | None = None) -> set[type[App]]: ... - @classmethod - def commit(cls) -> set[type[App]]: ... - @classmethod - def init_settings(cls, settings: dict[str, dict[str, Any]]) -> None: ... - @dispatch_method() - def get_view(self, obj: object, request: Request) -> BaseResponse: ... - @dispatch_method() - def _permits(self, identity: Identity | NoIdentity, obj: object, permission: object) -> bool: ... - @classmethod - def clean(cls) -> None: ... - def remember_identity(self, response: BaseResponse, request: Request, identity: Identity) -> None: ... - def forget_identity(self, response: BaseResponse, request: Request) -> None: ... diff --git a/stubs/morepath/authentication.pyi b/stubs/morepath/authentication.pyi deleted file mode 100644 index 829d5f6b84..0000000000 --- a/stubs/morepath/authentication.pyi +++ /dev/null @@ -1,31 +0,0 @@ -import abc - -from .request import Request, Response - -class NoIdentity: - userid: None - -NO_IDENTITY: NoIdentity - -# NOTE: Technically the actual Identity class is more generic and generates -# attributes based on what's passed to __init__, but for simplicity we -# assume the arguments we will pass in so we can type check them. If -# we wanted to ship these type stubs we would need to make this more -# generic again. -class Identity: - userid: str # email - uid: str # actual user id - groupids: frozenset[str] - role: str - application_id: str - verified: bool | None - def __init__(self, userid: str, *, uid: str, groupids: frozenset[str], role: str, application_id: str) -> None: ... - def as_dict(self) -> dict[str, str]: ... - -class IdentityPolicy(metaclass=abc.ABCMeta): - @abc.abstractmethod - def identify(self, request: Request) -> Identity | NoIdentity: ... - @abc.abstractmethod - def remember(self, response: Response, request: Request, identity: Identity) -> None: ... - @abc.abstractmethod - def forget(self, response: Response, request: Request) -> None: ... diff --git a/stubs/morepath/autosetup.pyi b/stubs/morepath/autosetup.pyi deleted file mode 100644 index af2e3fc6ea..0000000000 --- a/stubs/morepath/autosetup.pyi +++ /dev/null @@ -1,5 +0,0 @@ -from collections.abc import Callable, Sequence -from types import ModuleType - -def scan(package: ModuleType | None = None, ignore: Sequence[Callable[[str], bool] | str] | None = None, handle_error: Callable[[str, Exception], object] | None = None) -> None: ... -def autoscan(ignore: Sequence[Callable[[str], bool] | str] | None = None) -> None: ... diff --git a/stubs/morepath/converter.pyi b/stubs/morepath/converter.pyi deleted file mode 100644 index 0d5e0937f0..0000000000 --- a/stubs/morepath/converter.pyi +++ /dev/null @@ -1,41 +0,0 @@ -from collections.abc import Callable, Mapping -from typing import Any, Generic, TypeVar, overload - -_T = TypeVar('_T') - -class Converter(Generic[_T]): - single_decode: Callable[[str], _T | None] - single_encode: Callable[[_T | None], str] - def __init__(self: Converter[_T], decode: Callable[[str], _T | None], encode: Callable[[_T | None], str] | None = None) -> None: ... - def decode(self, strings: list[str]) -> _T | None: ... - def encode(self, value: _T | None) -> list[str]: ... - def is_missing(self, value: object) -> bool: ... - def __hash__(self) -> int: ... - def __eq__(self, other: object) -> bool: ... - def __ne__(self, other: object) -> bool: ... - -class ListConverter(Generic[_T]): - converter: Converter[_T] - def __init__(self: ListConverter[_T], converter: Converter[_T]) -> None: ... - def decode(self, strings: list[str]) -> list[_T | None]: ... - def encode(self, values: list[_T | None]) -> list[str]: ... - def is_missing(self, value: object) -> bool: ... - def __eq__(self, other: object) -> bool: ... - def __ne__(self, other: object) -> bool: ... - -IDENTITY_CONVERTER: Converter[str] - -def get_converter(type: type[_T]) -> Converter[_T]: ... - -class ConverterRegistry: - get_converter: Callable[[type[_T]], Converter[_T]] - def __init__(self) -> None: ... - def register_converter(self, type: type[_T], converter: Converter[_T]) -> None: ... - @overload - def actual_converter(self, spec: list[type[_T]]) -> ListConverter[_T]: ... - @overload - def actual_converter(self, spec: type[_T] | Converter[_T]) -> Converter[_T]: ... - # this is for the empty list case, pretty icky but nothing we can do - @overload - def actual_converter(self, spec: list[Any]) -> Converter[str]: ... - def argument_and_explicit_converters(self, arguments: Mapping[str, Any], converters: Mapping[str, Converter[Any] | list[Any] | type[Any]]) -> dict[str, Converter[Any] | ListConverter[Any]]: ... diff --git a/stubs/morepath/directive.pyi b/stubs/morepath/directive.pyi deleted file mode 100644 index 6dd89f22c0..0000000000 --- a/stubs/morepath/directive.pyi +++ /dev/null @@ -1,253 +0,0 @@ -from _typeshed import StrOrBytesPath -from collections.abc import Callable, Collection, Iterator, Mapping -from reg import KeyIndex -from reg.dispatch import Dispatch -from typing import Any, Literal, TypeVar -from typing_extensions import TypeAlias -from webob import Response as BaseResponse - -import dectate -from morepath.authentication import Identity, NoIdentity -from morepath.converter import ConverterRegistry -from morepath.path import PathRegistry # type:ignore[import-untyped] -from morepath.predicate import PredicateRegistry # type:ignore[import-untyped] -from morepath.request import Request -from morepath.settings import SettingRegistry -from morepath.template import TemplateEngineRegistry # type:ignore[import-untyped] -from morepath.tween import TweenRegistry # type:ignore[import-untyped] - -_T = TypeVar('_T') -_RequestT = TypeVar('_RequestT', bound=Request, contravariant=True) -_Type: TypeAlias = type -_AnyCallable: TypeAlias = Callable[..., Any] - -def isbaseclass(a: type, b: type) -> bool: ... - -class SettingAction(dectate.Action): - section: str - name: str - def __init__(self, section: str, name: str) -> None: ... - def identifier(self, setting_registry: SettingRegistry) -> tuple[str, str]: ... # type:ignore[override] - def perform(self, obj: Any, setting_registry: SettingRegistry) -> None: ... # type:ignore[override] - -class SettingValue: - value: Any - def __init__(self, value: Any) -> None: ... - def __call__(self) -> Any: ... - -class SettingSectionAction(dectate.Composite): - section: str - def __init__(self, section: str) -> None: ... - def actions(self, obj: Callable[[], Mapping[str, Any]]) -> Iterator[tuple[SettingAction, SettingValue]]: ... - -class PredicateFallbackAction(dectate.Action): - dispatch: _AnyCallable | str - func: _AnyCallable | str - def __init__(self, dispatch: _AnyCallable | str, func: _AnyCallable | str) -> None: ... - def identifier(self, predicate_registry: PredicateRegistry) -> tuple[_AnyCallable, _AnyCallable]: ... # type:ignore[override] - def perform(self, obj: Any, predicate_registry: PredicateRegistry) -> None: ... # type:ignore[override] - -class PredicateAction(dectate.Action): - dispatch: _AnyCallable | str - name: str - default: Any - index: KeyIndex | str - _after: _AnyCallable | str - _before: _AnyCallable | str - def __init__( - self, dispatch: _AnyCallable | str, name: str, default: Any, index: type[KeyIndex] | str, before: _AnyCallable | str | None = None, after: _AnyCallable | str | None = None - ) -> None: ... - def identifier(self, predicate_registry: PredicateRegistry) -> tuple[_AnyCallable, _AnyCallable, _AnyCallable]: ... # type:ignore[override] - def perform(self, obj: Any, predicate_registry: PredicateRegistry) -> None: ... # type:ignore[override] - @staticmethod - def after(predicate_registry: PredicateRegistry) -> None: ... # type:ignore[override] - -class MethodAction(dectate.Action): - dispatch_method: Dispatch[..., Any] | str - key_dict: dict[str, Any] - def __init__(self, dispatch_method: Dispatch[..., Any] | str, **kw: Any) -> None: ... - def identifier(self, app_class: type[dectate.App]) -> tuple[Dispatch[..., Any], tuple[Any, ...]]: ... # type:ignore[override] - def perform(self, obj: _AnyCallable, app_class: type[dectate.App]) -> None: ... # type:ignore[override] - -class ConverterAction(dectate.Action): - type: _Type | str - def __init__(self, type: _Type | str) -> None: ... - def identifier(self, converter_registry: ConverterRegistry) -> tuple[Literal['converter'], _Type]: ... # type:ignore[override] - def perform(self, obj: _AnyCallable, converter_registry: ConverterRegistry) -> None: ... # type:ignore[override] - -class PathAction(dectate.Action): - model: type | None - path: StrOrBytesPath - variables: Callable[[Any], dict[str, Any]] | None - converters: dict[str, Any] | None - required: Collection[str] | None - get_converters: Callable[[], dict[str, Any]] | None - absorb: bool - def __init__( - self, - path: StrOrBytesPath, - model: type[_T] | None = None, - variables: Callable[[_T], dict[str, Any]] | None = None, - converters: dict[str, Any] | None = None, - required: Collection[str] | None = None, - get_converters: Callable[[], dict[str, Any]] | None = None, - absorb: bool = False, - ) -> None: ... - def identifier(self, path_registry: PathRegistry) -> tuple[Literal['path'], type]: ... # type:ignore[override] - def discriminators(self, path_registry: PathRegistry) -> list[tuple[Literal['path'], type]]: ... # type:ignore[override] - def perform(self, obj: _AnyCallable, path_registry: PathRegistry) -> None: ... # type:ignore[override] - -class PathCompositeAction(dectate.Composite): - model: type | str | None - path: StrOrBytesPath - variables: Callable[[Any], dict[str, Any]] | str | None - converters: dict[str, Any] | None - required: Collection[str] | None - get_converters: Callable[[], dict[str, Any]] | str | None - absorb: bool | str - def __init__( - self, - path: StrOrBytesPath, - model: type | None = None, - variables: Callable[[Any], dict[str, Any]] | str | None = None, - converters: dict[str, Any] | None = None, - required: Collection[str] | None = None, - get_converters: Callable[[], dict[str, Any]] | str | None = None, - absorb: bool | str = False, - ) -> None: ... - def actions(self, obj: _T) -> Iterator[tuple[PathAction, _T]]: ... - -class PermissionRuleAction(dectate.Action): - model: type | str - permission: object | str - identity: type[Identity | NoIdentity] - def __init__(self, model: type | str, permission: object | str, identity: type[Identity | NoIdentity] | None = ...) -> None: ... - def identifier(self, app_class: type[dectate.App]) -> tuple[type | str, object | str, type[Identity | NoIdentity]]: ... # type:ignore[override] - def perform(self, obj: _AnyCallable, app_class: type[dectate.App]) -> None: ... # type:ignore[override] - -template_directory_id: int - -class TemplateDirectoryAction(dectate.Action): - name: str - def __init__( - self, after: _AnyCallable | str | None = None, before: _AnyCallable | str | None = None, name: str | None = None - ) -> None: ... - def identifier(self, template_engine_registry: TemplateEngineRegistry) -> str: ... # type:ignore[override] - def perform(self, obj: Callable[[], StrOrBytesPath], template_engine_registry: TemplateEngineRegistry) -> None: ... # type:ignore[override] - -class TemplateLoaderAction(dectate.Action): - extension: str - def __init__(self, extension: str) -> None: ... - def identifier(self, template_engine_registry: TemplateEngineRegistry) -> str: ... # type:ignore[override] - def perform(self, obj: _AnyCallable, template_engine_registry: TemplateEngineRegistry) -> None: ... # type:ignore[override] - -class TemplateRenderAction(dectate.Action): - extension: str - def __init__(self, extension: str) -> None: ... - def identifier(self, template_engine_registry: TemplateEngineRegistry) -> str: ... # type:ignore[override] - def perform(self, obj: _AnyCallable, template_engine_registry: TemplateEngineRegistry) -> None: ... # type:ignore[override] - -def issubclass_or_none(a: type | None, b: type | None) -> bool: ... - -class ViewAction(dectate.Action): - model: type | str - render: Callable[[Any, _RequestT], BaseResponse] | str - load: Callable[[Request], Any] | str | None - template: StrOrBytesPath | None - permission: object | str | None - internal: bool - predicates: dict[str, Any] - def __init__( - self, - model: type | str, - render: Callable[[Any, _RequestT], BaseResponse] | str | None = None, - template: StrOrBytesPath | None = None, - load: Callable[[_RequestT], Any] | str | None = None, - permission: object | str | None = None, - internal: bool = False, - **predicates: Any, - ) -> None: ... - def key_dict(self) -> dict[str, Any]: ... - def identifier(self, template_engine_registry: TemplateEngineRegistry, app_class: type[dectate.App]) -> tuple[Any, ...]: ... # type:ignore[override] - def perform(self, obj: _AnyCallable, template_engine_registry: TemplateEngineRegistry, app_class: type[dectate.App]) -> None: ... # type:ignore[override] - -class JsonAction(ViewAction): - group_class = ViewAction - -class HtmlAction(ViewAction): - group_class = ViewAction - -class DummyModel: ... - -class MountAction(PathAction): - group_class: type[PathAction] - name: str - model: type[DummyModel] - app: dectate.App - variables: Callable[[Any], dict[str, Any]] | str | None # type:ignore[assignment] - converters: dict[str, Any] | None - required: Collection[str] | None - get_converters: Callable[[], dict[str, Any]] | str | None # type:ignore[assignment] - def __init__( - self, - path: StrOrBytesPath, - app: type[dectate.App], - variables: Callable[[Any], dict[str, Any]] | str | None = None, - converters: dict[str, Any] | None = None, - required: Collection[str] | None = None, - get_converters: Callable[[], dict[str, Any]] | str | None = None, - name: str | None = None, - ) -> None: ... - def discriminators(self, path_registry: PathRegistry) -> list[tuple[Literal['mount'], dectate.App]]: ... # type:ignore[override] - def perform(self, obj: _AnyCallable, path_registry: PathRegistry) -> None: ... # type:ignore[override] - -class DeferLinksAction(dectate.Action): - group_class: type[PathAction] - model: type | str - def __init__(self, model: type | str) -> None: ... - def identifier(self, path_registry: PathRegistry) -> tuple[Literal['defer_links'], type | str]: ... # type:ignore[override] - def discriminators(self, path_registry: PathRegistry) -> list[tuple[Literal['model'], type | str]]: ... # type:ignore[override] - def perform(self, obj: Any, path_registry: PathRegistry) -> None: ... # type:ignore[override] - -class DeferClassLinksAction(dectate.Action): - group_class: type[PathAction] - model: type | str - variables: Callable[[Any], dict[str, Any]] | str - def __init__(self, model: type | str, variables: Callable[[Any], dict[str, Any]] | str) -> None: ... - def identifier(self, path_registry: PathRegistry) -> tuple[Literal['defer_links'], type | str]: ... # type:ignore[override] - def discriminators(self, path_registry: PathRegistry) -> list[tuple[Literal['model'], type | str]]: ... # type:ignore[override] - def perform(self, obj: Any, path_registry: PathRegistry) -> None: ... # type:ignore[override] - -tween_factory_id: int - -class TweenFactoryAction(dectate.Action): - under: _AnyCallable | str - over: _AnyCallable | str - name: str - def __init__( - self, under: _AnyCallable | None = None, over: _AnyCallable | None = None, name: str | None = None - ) -> None: ... - def identifier(self, tween_registry: TweenRegistry) -> str: ... # type:ignore[override] - def perform(self, obj: _AnyCallable, tween_registry: TweenRegistry) -> None: ... # type:ignore[override] - -class IdentityPolicyAction(dectate.Action): - def __init__(self) -> None: ... - def identifier(self, setting_registry: SettingRegistry, app_class: type[dectate.App]) -> tuple[()]: ... # type:ignore[override] - def perform(self, obj: _AnyCallable, setting_registry: SettingRegistry, app_class: type[dectate.App]) -> None: ... # type:ignore[override] - -class VerifyIdentityAction(dectate.Action): - identity: type | str - def __init__(self, identity: type | str = ...) -> None: ... - def identifier(self, app_class: type[dectate.App]) -> object | str: ... # type:ignore[override] - def perform(self, obj: _AnyCallable, app_class: type[dectate.App]) -> None: ... # type:ignore[override] - -class DumpJsonAction(dectate.Action): - model: type | str - def __init__(self, model: type | str = ...) -> None: ... - def identifier(self, app_class: type[dectate.App]) -> type | str: ... # type:ignore[override] - def perform(self, obj: _AnyCallable, app_class: type[dectate.App]) -> None: ... # type:ignore[override] - -class LinkPrefixAction(dectate.Action): - def __init__(self) -> None: ... - def identifier(self, app_class: type[dectate.App]) -> tuple[()]: ... # type:ignore[override] - def perform(self, obj: _AnyCallable, app_class: type[dectate.App]) -> None: ... # type:ignore[override] diff --git a/stubs/morepath/error.pyi b/stubs/morepath/error.pyi deleted file mode 100644 index fca6a07863..0000000000 --- a/stubs/morepath/error.pyi +++ /dev/null @@ -1,13 +0,0 @@ -from dectate import ( - ConfigError, - ConflictError as ConflictError, - DirectiveError as DirectiveError, - DirectiveReportError as DirectiveReportError, - TopologicalSortError as TopologicalSortError, -) - -class AutoImportError(ConfigError): - def __init__(self, module_name: str) -> None: ... - -class TrajectError(Exception): ... -class LinkError(Exception): ... diff --git a/stubs/morepath/publish.pyi b/stubs/morepath/publish.pyi deleted file mode 100644 index bed63a771f..0000000000 --- a/stubs/morepath/publish.pyi +++ /dev/null @@ -1,12 +0,0 @@ -from collections.abc import Sequence -from typing import Any - -from morepath.request import Request -from webob.response import Response - -DEFAULT_NAME: str - -def publish(request: Request) -> Response: ... -def resolve_model(request: Request) -> Any | None: ... -def resolve_response(obj: object, request: Request) -> Response: ... -def get_view_name(stack: Sequence[str]) -> str | None: ... diff --git a/stubs/morepath/request.pyi b/stubs/morepath/request.pyi deleted file mode 100644 index 4761d1f331..0000000000 --- a/stubs/morepath/request.pyi +++ /dev/null @@ -1,44 +0,0 @@ -from _typeshed.wsgi import WSGIEnvironment -from collections.abc import Callable -from dectate import Sentinel -from webob.request import BaseRequest -from webob.response import Response as BaseResponse -from typing import overload, Any, TypeVar - -from morepath import reify -from morepath.app import App -from morepath.authentication import Identity, NoIdentity - -_T = TypeVar('_T') -_AfterF = TypeVar('_AfterF', bound=Callable[[Response], Any]) - -SAME_APP: Sentinel - -class Request(BaseRequest): - # FIXME: These two attributes look like internal API of morepath, so - # if we don't use them it's easier to just pretend, they don't - # exist, but just in case we do use them, I will leave this - # comment - # path_code_info: Incomplete - # view_code_info: Incomplete - unconsumed: list[str] - app: App - view_name: str # this technically only exists after resolve_response - def __init__(self, environ: WSGIEnvironment, app: App, **kw: Any) -> None: ... - def reset(self) -> None: ... - @reify - def identity(self) -> Identity | NoIdentity: ... - def link_prefix(self, app: App | None = None) -> str: ... - def view(self, obj: object, default: _T | None = None, app: App | Sentinel = ..., **predicates: Any) -> Any | _T | None: ... - @overload - def link(self, obj: None, name: str = '', default: None = None, app: App | Sentinel = ...) -> None: ... - @overload - def link(self, obj: None, name: str, default: _T, app: App | Sentinel = ...) -> _T: ... - @overload - def link(self, obj: object, name: str = '', default: Any = None, app: App | Sentinel = ...) -> str: ... - def class_link(self, model: type, variables: dict[str, Any] | None = None, name: str = '', app: App | Sentinel = ...) -> str: ... - def resolve_path(self, path: str, app: App | Sentinel = ...) -> Any | None: ... - def after(self, func: _AfterF) -> _AfterF: ... - def clear_after(self) -> None: ... - -class Response(BaseResponse): ... diff --git a/stubs/morepath/settings.pyi b/stubs/morepath/settings.pyi deleted file mode 100644 index c5f5a856a9..0000000000 --- a/stubs/morepath/settings.pyi +++ /dev/null @@ -1,10 +0,0 @@ -from collections.abc import Callable -from typing import Any - -class SettingRegistry: - def register_setting(self, section_name: str, setting_name: str, func: Callable[[], object]) -> None: ... - def __getattr__(self, name: str) -> SettingSection: ... - -class SettingSection: - def __getattr__(self, name: str) -> Any: ... - def __setattr__(self, name: str, value: Any) -> None: ... diff --git a/stubs/morepath/view.pyi b/stubs/morepath/view.pyi deleted file mode 100644 index ffd9029ef7..0000000000 --- a/stubs/morepath/view.pyi +++ /dev/null @@ -1,78 +0,0 @@ -from collections.abc import Callable -from typing import Any, TypeVar, overload - -from dectate.config import CodeInfo -from morepath.app import App -from morepath.request import Request, Response -from webob import Response as BaseResponse -from webob.exc import HTTPFound - -_T = TypeVar('_T') -_L = TypeVar('_L') -_RequestT = TypeVar('_RequestT', bound=Request, contravariant=True) - -class View: - func: Callable[..., Any] - render: Callable[[Any], BaseResponse] | None - load: Callable[[_RequestT], Any] | None - permission: Any | None - internal: bool - code_info: CodeInfo | None - @overload - def __init__( - self, - # we are lax and allow views that depend on subclasses of Request - func: Callable[[Any, _RequestT], BaseResponse], - render: None = None, - load: None = None, - permission: object | None = None, - internal: bool = False, - code_info: CodeInfo | None = None, - ) -> None: ... - @overload - def __init__( - self, - func: Callable[[Any, _RequestT], _T], - render: Callable[[_T], BaseResponse], - load: None = None, - permission: object | None = None, - internal: bool = False, - code_info: CodeInfo | None = None, - ) -> None: ... - @overload - def __init__( - self, - func: Callable[[Any, _RequestT, _L], _T], - render: Callable[[_T], BaseResponse], - load: Callable[[], _L], - permission: object | None = None, - internal: bool = False, - code_info: CodeInfo | None = None, - ) -> None: ... - @overload - def __init__( - self, - func: Callable[[Any, _RequestT, _L], BaseResponse], - render: None, - load: Callable[[], _L], - permission: object | None = None, - internal: bool = False, - code_info: CodeInfo | None = None, - ) -> None: ... - @overload - def __init__( - self, - func: Callable[[Any, _RequestT, _L], BaseResponse], - render: None = None, - *, - load: Callable[[], _L], - permission: object | None = None, - internal: bool = False, - code_info: CodeInfo | None = None, - ) -> None: ... - def __call__(self, app: App, obj: object, request: Request) -> BaseResponse: ... - -def render_view(content: str, request: Request) -> Response: ... -def render_json(content: Any, request: Request) -> Response: ... -def render_html(content: str, request: Request) -> Response: ... -def redirect(location: str) -> HTTPFound: ... diff --git a/stubs/reg/__init__.pyi b/stubs/reg/__init__.pyi deleted file mode 100644 index d0b4e13fda..0000000000 --- a/stubs/reg/__init__.pyi +++ /dev/null @@ -1,18 +0,0 @@ -from .arginfo import arginfo as arginfo -from .cache import DictCachingKeyLookup as DictCachingKeyLookup, LruCachingKeyLookup as LruCachingKeyLookup -from .context import ( - DispatchMethod as DispatchMethod, - clean_dispatch_methods as clean_dispatch_methods, - dispatch_method as dispatch_method, - methodify as methodify, -) -from .dispatch import Dispatch as Dispatch, LookupEntry as LookupEntry, dispatch as dispatch -from .error import RegistrationError as RegistrationError -from .predicate import ( - ClassIndex as ClassIndex, - KeyIndex as KeyIndex, - Predicate as Predicate, - match_class as match_class, - match_instance as match_instance, - match_key as match_key, -) diff --git a/stubs/reg/arginfo.pyi b/stubs/reg/arginfo.pyi deleted file mode 100644 index 7da8ace8e4..0000000000 --- a/stubs/reg/arginfo.pyi +++ /dev/null @@ -1,18 +0,0 @@ -from collections.abc import Callable -from inspect import FullArgSpec -from typing import Any, TypeVar -from typing_extensions import ParamSpec - -_T = TypeVar('_T') -_P = ParamSpec('_P') - -def arginfo(callable: Callable[..., Any]) -> FullArgSpec: ... -def is_cached(callable: Callable[..., Any]) -> bool: ... -def get_callable_info(callable: Callable[_P, _T]) -> tuple[Callable[_P, _T], object, bool]: ... -def fake_empty_init() -> None: ... - -class Dummy: ... - -WRAPPER_DESCRIPTOR: object - -def get_class_init(class_: type[Any]) -> Callable[..., _T]: ... diff --git a/stubs/reg/cache.pyi b/stubs/reg/cache.pyi deleted file mode 100644 index d36bfa2e31..0000000000 --- a/stubs/reg/cache.pyi +++ /dev/null @@ -1,26 +0,0 @@ -from collections.abc import Callable, Iterator, Sequence -from typing import Any, TypeVar - -from reg.dispatch import _KeyLookup - -_KT = TypeVar('_KT') -_VT = TypeVar('_VT') - -class Cache(dict[_KT, _VT]): - func: Callable[[_KT], _VT] - def __init__(self: Cache[_KT, _VT], func: Callable[[_KT], _VT]) -> None: ... - def __missing__(self, key: _KT) -> _VT: ... - -class DictCachingKeyLookup(_KeyLookup): - key_lookup: _KeyLookup - component: Callable[[Sequence[Any]], Callable[..., Any] | None] - fallback: Callable[[Sequence[Any]], Callable[..., Any] | None] - all: Callable[[Sequence[Any]], Iterator[Callable[..., Any]]] - def __init__(self, key_lookup: _KeyLookup) -> None: ... - -class LruCachingKeyLookup(_KeyLookup): - key_lookup: _KeyLookup - component: Callable[[Sequence[Any]], Callable[..., Any] | None] - fallback: Callable[[Sequence[Any]], Callable[..., Any] | None] - all: Callable[[Sequence[Any]], Iterator[Callable[..., Any]]] - def __init__(self, key_lookup: _KeyLookup, component_cache_size: int, all_cache_size: int, fallback_cache_size: int) -> None: ... diff --git a/stubs/reg/context.pyi b/stubs/reg/context.pyi deleted file mode 100644 index e627baf3a2..0000000000 --- a/stubs/reg/context.pyi +++ /dev/null @@ -1,29 +0,0 @@ -from collections.abc import Callable -from typing import Any, Generic, TypeVar, overload -from typing_extensions import Concatenate, ParamSpec - -from reg.dispatch import Dispatch, dispatch, _GetKeyLookup -from reg.predicate import Predicate - -_T = TypeVar('_T') -_T1 = TypeVar('_T1') -_R_co = TypeVar('_R_co', covariant=True) -_R_co1 = TypeVar('_R_co1', covariant=True) -_P = ParamSpec('_P') -_P1 = ParamSpec('_P1') - -class dispatch_method(dispatch, Generic[_P, _T, _R_co]): - callable: Callable[Concatenate[_T, _P], _R_co] - first_invocation_hook: Callable[[Any], object] - def __init__(self: dispatch_method[Any, Any, Any], *predicates: str | Predicate, get_key_lookup: _GetKeyLookup = ..., first_invocation_hook: Callable[[Any], object] = ...) -> None: ... - # this needs to be able to override the bound type vars - def __call__(self, callable: Callable[Concatenate[_T1, _P1], _R_co1]) -> dispatch_method[_P1, _T1, _R_co1]: ... # type:ignore[override] - @overload - def __get__(self, obj: _T, type: type[_T] | None = None) -> Callable[_P, _R_co]: ... - @overload - def __get__(self, obj: None, type: type[_T] | None = None) -> Callable[Concatenate[_T, _P], _R_co]: ... - -class DispatchMethod(Dispatch[_P, _T]): ... - -def methodify(func: Callable[_P, _T], selfname: str | None = ...) -> Callable[Concatenate[Any, _P], _T]: ... -def clean_dispatch_methods(cls: type[object]) -> None: ... diff --git a/stubs/reg/dispatch.pyi b/stubs/reg/dispatch.pyi deleted file mode 100644 index 9ac3e3ec67..0000000000 --- a/stubs/reg/dispatch.pyi +++ /dev/null @@ -1,54 +0,0 @@ -from collections.abc import Callable, Iterator, Sequence -from inspect import FullArgSpec -from typing import Any, Generic, NamedTuple, TypeVar -from typing_extensions import ParamSpec, TypeAlias - -from reg.predicate import Predicate, PredicateRegistry - -_T = TypeVar('_T') -_F = TypeVar('_F', bound=Callable[..., Any]) -_P = ParamSpec('_P') -_GetKeyLookup: TypeAlias = Callable[[PredicateRegistry], _KeyLookup] - -class _KeyLookup: - def component(self, key: Sequence[Any], /) -> Callable[..., Any] | None: ... - def fallback(self, key: Sequence[Any], /) -> Callable[..., Any] | None: ... - def all(self, key: Sequence[Any], /) -> Iterator[Callable[..., Any]]: ... - -class dispatch: - predicates: list[Predicate] - get_key_lookup: _GetKeyLookup - def __init__(self, *predicates: str | Predicate, get_key_lookup: _GetKeyLookup = ...) -> None: ... - def __call__(self, callable: Callable[_P, _T]) -> Callable[_P, _T]: ... - -def identity(registry: PredicateRegistry) -> PredicateRegistry: ... - -class LookupEntry(NamedTuple, Generic[_F]): - lookup: _GetKeyLookup - key: tuple[Any, ...] - - @property - def component(self) -> _F | None: ... - @property - def fallback(self) -> _F | None: ... - @property - def matches(self) -> Iterator[_F]: ... - @property - def all_matches(self) -> list[_F]: ... - -class Dispatch(Generic[_P, _T]): - wrapped_func: Callable[_P, _T] - get_key_lookup: _GetKeyLookup - def __init__(self: Dispatch[_P, _T], predicates: list[Predicate], callable: Callable[_P, _T], get_key_lookup: _GetKeyLookup) -> None: ... - def clean(self) -> None: ... - def add_predicates(self, predicates: list[Predicate]) -> None: ... - def register(self, func: Callable[_P, _T] | None = ..., **key_dict: dict[str, Any]) -> Callable[_P, _T]: ... - def by_args(self, *args: _P.args, **kw: _P.kwargs) -> LookupEntry[Callable[_P, _T]]: ... - def by_predicates(self, **predicate_values: Any) -> LookupEntry[Callable[_P, _T]]: ... - # auto-generated by _define_call in the constructor - def call(self, *args: _P.args, **kwargs: _P.kwargs) -> _T: ... - -def validate_signature(f: Callable[..., Any], dispatch: Dispatch[..., Any]) -> None: ... -def format_signature(args: FullArgSpec) -> str: ... -def same_signature(a: FullArgSpec, b: FullArgSpec) -> bool: ... -def execute(code_source: str, **namespace: Any) -> dict[str, Any]: ... diff --git a/stubs/reg/error.pyi b/stubs/reg/error.pyi deleted file mode 100644 index 46ddac1357..0000000000 --- a/stubs/reg/error.pyi +++ /dev/null @@ -1 +0,0 @@ -class RegistrationError(Exception): ... diff --git a/stubs/reg/predicate.pyi b/stubs/reg/predicate.pyi deleted file mode 100644 index e477b205d1..0000000000 --- a/stubs/reg/predicate.pyi +++ /dev/null @@ -1,42 +0,0 @@ -from collections.abc import Callable, Iterator, Sequence -from typing import Any - -class Predicate: - name: str - index: Callable[[Any], KeyIndex] - fallback: Callable[..., Any] | None - get_key: Callable[[dict[str, Any]], Any] | None - default: Any | None - def __init__( - self, name: str, index: Callable[[Any], KeyIndex], get_key: Callable[[dict[str, Any]], Any] | None = ..., fallback: Callable[..., Any] | None = ..., default: Any | None = ... - ) -> None: ... - def create_index(self) -> KeyIndex: ... - def key_by_predicate_name(self, d: dict[str, Any]) -> Any | None: ... - -def match_key(name: str, func: Callable[..., Any] | None = ..., fallback: Callable[..., Any] | None = ..., default: Any | None = ...) -> Predicate: ... -def match_instance(name: str, func: Callable[..., Any] | None = ..., fallback: Callable[..., Any] | None = ..., default: Any | None = ...) -> Predicate: ... -def match_class(name: str, func: Callable[..., Any] | None = ..., fallback: Callable[..., Any] | None = ..., default: Any | None = ...) -> Predicate: ... - -class KeyIndex(dict[Any, Callable[..., Any]]): - fallback: Callable[..., Any] | None - def __init__(self, fallback: Callable[..., Any] | None = ...) -> None: ... - def __missing__(self, key: Any) -> frozenset[Any]: ... - def permutations(self, key: Any) -> Iterator[Any]: ... - -class ClassIndex(KeyIndex): - def permutations(self, key: type) -> Iterator[type]: ... - -class PredicateRegistry: - known_keys: set[Any] - known_values: set[Callable[..., Any]] - predicates: tuple[Predicate, ...] - indexes: list[KeyIndex] - def __init__(self, *predicates: Predicate) -> None: ... - def register(self, key: Any, value: Callable[..., Any]) -> None: ... - def get(self, keys: Sequence[Any]) -> set[Callable[..., Any]]: ... - def permutations(self, keys: Sequence[Any]) -> Iterator[tuple[Any, ...]]: ... - def key(self, **kw: Any) -> tuple[Any, ...]: ... - def key_dict_to_predicate_key(self, d: dict[str, Any]) -> tuple[Any, ...]: ... - def component(self, keys: Sequence[Any]) -> Callable[..., Any] | None: ... - def fallback(self, keys: Sequence[Any]) -> Callable[..., Any] | None: ... - def all(self, key: Sequence[Any]) -> Iterator[Callable[..., Any]]: ... diff --git a/stubtest.sh b/stubtest.sh index 736bbfd9c1..7981857783 100755 --- a/stubtest.sh +++ b/stubtest.sh @@ -16,38 +16,12 @@ stubtest cgi \ --mypy-config-file pyproject.toml \ --allowlist tests/stubtest/cgi_allowlist.txt -echo "Running stubtest on dectate" -stubtest dectate \ - --mypy-config-file pyproject.toml \ - --allowlist tests/stubtest/dectate_allowlist.txt \ - --ignore-missing-stub - echo "Running stubtest on depot" stubtest depot \ --mypy-config-file pyproject.toml \ --allowlist tests/stubtest/depot_allowlist.txt \ --ignore-missing-stub -echo "Running stubtest on morepath" -stubtest morepath \ - --mypy-config-file pyproject.toml \ - --allowlist tests/stubtest/morepath_allowlist.txt \ - --ignore-missing-stub - -echo "Running stubtest on more.content_security" -stubtest more.content_security \ - --mypy-config-file pyproject.toml - -echo "Running stubtest on more.transaction" -stubtest more.transaction \ - --mypy-config-file pyproject.toml \ - --allowlist tests/stubtest/more.transaction_allowlist.txt - -echo "Running stubtest on more.webassets" -stubtest more.webassets \ - --mypy-config-file pyproject.toml \ - --allowlist tests/stubtest/more.webassets_allowlist.txt - echo "Running stubtest on pdfdocument" stubtest pdfdocument \ --mypy-config-file pyproject.toml \ @@ -57,11 +31,6 @@ echo "Running stubtest on purl" stubtest purl \ --mypy-config-file pyproject.toml -echo "Running stubtest on reg" -stubtest reg \ - --mypy-config-file pyproject.toml \ - --allowlist tests/stubtest/reg_allowlist.txt - echo "Running stubtest on sqlalchemy_utils" stubtest sqlalchemy_utils \ --mypy-config-file pyproject.toml \ diff --git a/tests/onegov/agency/test_security.py b/tests/onegov/agency/test_security.py index d91f9fc079..efb0a5ef27 100644 --- a/tests/onegov/agency/test_security.py +++ b/tests/onegov/agency/test_security.py @@ -1,6 +1,5 @@ from __future__ import annotations -from morepath import Identity from morepath.authentication import NO_IDENTITY from onegov.agency.collections import ExtendedAgencyCollection from onegov.agency.models import AgencyMembershipMoveWithinAgency @@ -11,6 +10,7 @@ from onegov.agency.models.ticket import AgencyMutationTicket from onegov.agency.models.ticket import PersonMutationTicket from onegov.agency.security import get_current_role +from onegov.core import Identity from onegov.core.security import Personal from onegov.core.security import Private from onegov.core.security import Public diff --git a/tests/onegov/core/test_converters.py b/tests/onegov/core/test_converters.py index 4b3b7778f1..be801b0ff4 100644 --- a/tests/onegov/core/test_converters.py +++ b/tests/onegov/core/test_converters.py @@ -13,7 +13,7 @@ def test_date_converter() -> None: converter = extended_date_converter - assert converter.encode(None) == [''] + assert converter.encode(None) == [''] # type: ignore[arg-type] assert converter.encode('') == [''] # type: ignore[arg-type] assert converter.encode(date(2008, 12, 30)) == ['2008-12-30'] @@ -25,7 +25,7 @@ def test_date_converter() -> None: def test_datetime_converter() -> None: converter = datetime_converter - assert converter.encode(None) == [''] + assert converter.encode(None) == [''] # type: ignore[arg-type] assert converter.encode('') == [''] # type: ignore[arg-type] assert converter.encode(datetime(2008, 12, 30)) == ['2008-12-30T00:00:00'] @@ -38,7 +38,7 @@ def test_datetime_converter() -> None: def test_uuid_converter() -> None: converter = uuid_converter - assert converter.encode(None) == [''] + assert converter.encode(None) == [''] # type: ignore[arg-type] assert converter.encode('') == [''] # type: ignore[arg-type] assert converter.encode(UUID('930a8bf4-e532-4b39-bf64-bd05e81acf01')) == [ '930a8bf4e5324b39bf64bd05e81acf01'] @@ -52,7 +52,7 @@ def test_uuid_converter() -> None: def test_literal_converter() -> None: converter = LiteralConverter(Literal['asc', 'desc']) assert converter.allowed_values == {'asc', 'desc'} - assert converter.encode(None) == [''] + assert converter.encode(None) == [''] # type: ignore[arg-type] # NOTE: we allow bogus values to be encoded so we can e.g. build # url patterns, we only filter values on decode assert converter.encode('bogus') == ['bogus'] diff --git a/tests/onegov/core/test_request.py b/tests/onegov/core/test_request.py index 36620dd844..93dc351aa1 100644 --- a/tests/onegov/core/test_request.py +++ b/tests/onegov/core/test_request.py @@ -26,7 +26,7 @@ def test_url_safe_token() -> None: 'SERVER_NAME': '', 'SERVER_PORT': '', 'SERVER_PROTOCOL': 'https' - }, app=Bunch(identity_secret='asdf', lookup=None)) # type: ignore[arg-type] + }, app=Bunch(identity_secret='asdf', lookup=None)) # type: ignore[type-var] token = request.new_url_safe_token({'foo': 'bar'}) @@ -55,7 +55,7 @@ def url(self) -> str: def param(url: str) -> str: return url.split('=')[1] - r = Request() # type: ignore[call-arg] + r = Request() assert r.return_to('https://example.org', '/').startswith( 'https://example.org?return-to=') @@ -89,7 +89,7 @@ def test_vhm_root_urls() -> None: 'SERVER_PROTOCOL': 'https', 'HTTP_HOST': 'example.com', 'HTTP_X_VHM_ROOT': '/town/example/', - }, app=Bunch()) # type: ignore[arg-type] + }, app=Bunch()) # type: ignore[type-var] assert request.x_vhm_root == '/town/example' assert request.application_url == 'https://example.com' diff --git a/tests/onegov/core/test_sentry.py b/tests/onegov/core/test_sentry.py index 7d97343e39..3d66948842 100644 --- a/tests/onegov/core/test_sentry.py +++ b/tests/onegov/core/test_sentry.py @@ -2,7 +2,7 @@ import pytest import sentry_sdk -from morepath import Identity +from onegov.core import Identity from onegov.core.framework import Framework from onegov.core.security import Public from onegov.core.sentry import OneGovCloudIntegration diff --git a/tests/onegov/file/test_integration.py b/tests/onegov/file/test_integration.py index e80cb2e4b6..a99f106709 100644 --- a/tests/onegov/file/test_integration.py +++ b/tests/onegov/file/test_integration.py @@ -75,7 +75,7 @@ def app( backend = request.param - class BypassCSRFRequest(CoreRequest): + class BypassCSRFRequest(CoreRequest['App']): def assert_valid_csrf_token( self, signed_value: str | bytes | None = None, diff --git a/tests/onegov/org/test_converters.py b/tests/onegov/org/test_converters.py index 381149eb46..94899bb849 100644 --- a/tests/onegov/org/test_converters.py +++ b/tests/onegov/org/test_converters.py @@ -6,7 +6,7 @@ def test_keywords_converter() -> None: converter = keywords_converter - assert converter.encode(None) == [''] + assert converter.encode(None) == [''] # type: ignore[arg-type] assert converter.encode('') == [''] # type: ignore[arg-type] assert converter.encode({}) == [''] assert converter.encode({'k': ['v']}) == ['k:v'] diff --git a/tests/onegov/pas/permissions/test_parliamentarian_permissions.py b/tests/onegov/pas/permissions/test_parliamentarian_permissions.py index bb69f78d9f..2718742f11 100644 --- a/tests/onegov/pas/permissions/test_parliamentarian_permissions.py +++ b/tests/onegov/pas/permissions/test_parliamentarian_permissions.py @@ -4,7 +4,7 @@ import transaction from datetime import date -from morepath import Identity +from onegov.core import Identity from onegov.core.security import Private from onegov.pas.collections import ( PASCommissionCollection, diff --git a/tests/shared/fixtures.py b/tests/shared/fixtures.py index eeec3853f1..e6d9f6f354 100644 --- a/tests/shared/fixtures.py +++ b/tests/shared/fixtures.py @@ -64,7 +64,7 @@ def monkeysession(request: pytest.FixtureRequest) -> Iterator[MonkeyPatch]: @pytest.fixture(scope='session', autouse=True) def scan_onegov() -> None: - import importscan # type: ignore[import-untyped] + import importscan import onegov importscan.scan(onegov, ignore=['.test', '.tests']) diff --git a/tests/shared/utils.py b/tests/shared/utils.py index d24122f11a..fe67dd8685 100644 --- a/tests/shared/utils.py +++ b/tests/shared/utils.py @@ -163,6 +163,7 @@ def assert_explicit_permissions( for action, fn in dectate.Query('view')(app_class): if fn.__module__.startswith('onegov'): + assert hasattr(action, 'permission') assert action.permission is not None, ( f'{fn.__module__}.{fn.__name__} has no permission' ) diff --git a/tests/stubtest/dectate_allowlist.txt b/tests/stubtest/dectate_allowlist.txt deleted file mode 100644 index d65df61a43..0000000000 --- a/tests/stubtest/dectate_allowlist.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Error: is not present at runtime -# ============================= -# Since Config can contain arbitrary values we added __getattr__ -# to let mypy know that arbitrary attribute access is possible -dectate.app.Config.__getattr__ diff --git a/tests/stubtest/more.transaction_allowlist.txt b/tests/stubtest/more.transaction_allowlist.txt deleted file mode 100644 index 03102b93c9..0000000000 --- a/tests/stubtest/more.transaction_allowlist.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Error: is inconsistent -# ====================== -# The extra argument transaction is internal use only, so we omit it -more.transaction.main.transaction_tween_factory -# Error: is not present in stub -# ====================== -# internal PY2 compatiblity module -more.transaction.compat \ No newline at end of file diff --git a/tests/stubtest/more.webassets_allowlist.txt b/tests/stubtest/more.webassets_allowlist.txt deleted file mode 100644 index 51021dc733..0000000000 --- a/tests/stubtest/more.webassets_allowlist.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Error: variable differs from runtime -# ====================== -# bound directives are very complex and can't be verified properly -more\.webassets\.(core\.)?WebassetsApp\.webasset_path -more\.webassets\.(core\.)?WebassetsApp\.webasset_output -more\.webassets\.(core\.)?WebassetsApp\.webasset_filter -more\.webassets\.(core\.)?WebassetsApp\.webasset_mapping -more\.webassets\.(core\.)?WebassetsApp\.webasset_url -more\.webassets\.(core\.)?WebassetsApp\.webasset diff --git a/tests/stubtest/morepath_allowlist.txt b/tests/stubtest/morepath_allowlist.txt deleted file mode 100644 index 2ccd3a8761..0000000000 --- a/tests/stubtest/morepath_allowlist.txt +++ /dev/null @@ -1,42 +0,0 @@ -# Error: variable differs from runtime -# ====================== -# bound directives are very complex and can't be verified properly -morepath\.(app\.)?App\.setting -morepath\.(app\.)?App\.setting_section -morepath\.(app\.)?App\.predicate_fallback -morepath\.(app\.)?App\.predicate -morepath\.(app\.)?App\.method -morepath\.(app\.)?App\.converter -morepath\.(app\.)?App\._path -morepath\.(app\.)?App\.path -morepath\.(app\.)?App\.permission_rule -morepath\.(app\.)?App\.template_directory -morepath\.(app\.)?App\.template_loader -morepath\.(app\.)?App\.template_render -morepath\.(app\.)?App\.view -morepath\.(app\.)?App\.json -morepath\.(app\.)?App\.html -morepath\.(app\.)?App\.mount -morepath\.(app\.)?App\.defer_links -morepath\.(app\.)?App\.defer_class_links -morepath\.(app\.)?App\.tween_factory -morepath\.(app\.)?App\.identity_policy -morepath\.(app\.)?App\.verify_identity -morepath\.(app\.)?App\.dump_json -morepath\.(app\.)?App\.link_prefix - -# Error: is inconsistent -# ====================== -# dispatch_methods generate custom code for efficiency, but we use -# a descriptor to simulate the semantics, which looks different than -# the generated function -morepath\.(app\.)?App\._permits -morepath\.(app\.)?App\.get_view - -# Error: is not present at runtime -# ====================== -# These __getattr__ need to be there so mypy is aware that these objects -# can contain arbitary attributes -morepath.settings.SettingRegistry.__getattr__ -morepath.settings.SettingSection.__getattr__ -morepath.settings.SettingSection.__setattr__ diff --git a/tests/stubtest/reg_allowlist.txt b/tests/stubtest/reg_allowlist.txt deleted file mode 100644 index ec4490bfe0..0000000000 --- a/tests/stubtest/reg_allowlist.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Error: is not present at runtime -# ====================== -# this method gets auto generated when the class is initalized -# as such stubtest can't know it's there -reg.dispatch.Dispatch.call -# Error: failed to find stubs -# ====================== -# tests should not be part of stubs -reg.tests -reg.tests.* \ No newline at end of file