Skip to content

fix(typing): make Provider.boot() pattern static-analysis clean - #197

Merged
tmgbedu merged 1 commit into
mainfrom
task/provider-boot-typing-1247
Jul 24, 2026
Merged

fix(typing): make Provider.boot() pattern static-analysis clean#197
tmgbedu merged 1 commit into
mainfrom
task/provider-boot-typing-1247

Conversation

@tmgbedu

@tmgbedu tmgbedu commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

What

Makes the standard provider boot() pattern pass basedpyright/pyright with no reportUnknownMemberType / Application[Unknown] diagnostics. Target snippet:

from typing import override
from fastapi_startkit.fastapi import FastAPIProvider as BaseFastAPIProvider
from fastapi.templating import Jinja2Templates

class FastapiProvider(BaseFastAPIProvider):
    @override
    def boot(self):
        templates_dir = self.app.use_base_path("resources/templates")
        self.app.bind("templates", Jinja2Templates(directory=str(templates_dir)))
        super().boot()
        from routes.api import api
        self.app.fastapi.include_router(api)

Root cause

Application is Generic[TConfig], but the Provider base class annotated its app attribute as the bare, unparameterized Application. Static analyzers resolved that to Application[Unknown], and the Unknown cascaded into every self.app.* access (.fastapi, .use_base_path, .include_router). Separately, Container.bind had no signature, so self.app.bind(...) and its result were reported as partially unknown.

Changes

  • Provider: type app (and the __init__ param) as Application[AppConfig] — the concrete base config bound to TConfig. self.app now resolves to Application[AppConfig], clearing the cascade. Import is under TYPE_CHECKING only, so no runtime/import-cost change.
  • Container.bind: explicit signature (name: str, class_obj: Any) -> None. Per direction, bind no longer returns self — nothing chained on it (verified across framework, application/ template, and example/), so callers can write self.app.bind(...) directly with no unused-result to capture.
  • Test: updated the container test to assert the new None contract.

Verification

  • basedpyright-equivalent (pyright --typeCheckingMode strict) on the target snippet: 0 errors, 0 warnings. reveal_type(self.app)Application[AppConfig]; self.app.bind(...)None.
  • pytest --ignore=tests/masoniteorm/postgres: 1981 passed, 7 skipped.
  • ruff check + ruff format --check: clean.

Coordination

Complements the related typing work rather than duplicating it:

  • #1086 (Router.include_router) — completed.
  • PR fix(typing): give Application.include_router a fully-known signature #181 / #1093 (Application.include_router signature) — untouched here; this PR fixes the receiver type (self.app), that PR fixes the method's own kwargs. They compose.
  • #1225 (self.app -> Application[Unknown]) — this PR delivers that root-cause fix as part of the broader boot() cleanup; flagging for the PM to dedupe/close #1225 against this.

No runtime behavior change beyond Container.bind no longer returning self (an intentional, requested API tweak).

Type Provider.app as Application[AppConfig] instead of the bare, generic
Application so basedpyright/pyright resolves self.app concretely instead of
Application[Unknown]. This stops the Unknown type from cascading into every
self.app.* access (fastapi, use_base_path, include_router) inside provider
boot()/register() methods.

Give Container.bind an explicit signature. It now returns None (it never
needs to be chained), so callers no longer see a partially-unknown member
and the example provider can call self.app.bind(...) directly without
capturing an unused result.

Update the container test to assert the new None contract.
@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@tmgbedu
tmgbedu merged commit 7767a5c into main Jul 24, 2026
6 checks passed
@tmgbedu
tmgbedu deleted the task/provider-boot-typing-1247 branch July 24, 2026 23:58
tmgbedu added a commit that referenced this pull request Jul 25, 2026
simple() binds a class object as the container key (mirroring make()'s
class-key support at 'elif inspect.isclass(name)'). The str-only signature
from #197 was too narrow, producing a pyright error at container.py:92:
'Argument of type type[object] | Unknown cannot be assigned to parameter
name of type str'. Widen name to str | type to match the keys make()
accepts. Typing-only change; bind still returns None.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant