Skip to content

Add types to infobase db/server modules#277

Open
cdrini wants to merge 1 commit intomasterfrom
add-some-db-types
Open

Add types to infobase db/server modules#277
cdrini wants to merge 1 commit intomasterfrom
add-some-db-types

Conversation

@cdrini
Copy link
Collaborator

@cdrini cdrini commented Mar 19, 2026

Some types I added while debugging database connection creation.

@cdrini cdrini force-pushed the add-some-db-types branch 4 times, most recently from ae2a31c to fa9ffcc Compare March 20, 2026 23:57
@cdrini cdrini force-pushed the add-some-db-types branch from fa9ffcc to 7467243 Compare March 21, 2026 00:12
@cdrini cdrini marked this pull request as ready for review March 21, 2026 00:14
@RayBB
Copy link
Collaborator

RayBB commented Mar 23, 2026

@cdrini can you ask copilot to review this one?

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds/clarifies Python type annotations across Infobase server and DB store modules to improve static typing while debugging database connection creation.

Changes:

  • Added type hints to Infobase/Site and store interfaces (core.Store, dbstore.DBStore/DBSiteStore).
  • Introduced typing-only imports (TYPE_CHECKING) and refined internal attribute types (e.g., caches, listeners, triggers).
  • Added a typed return for create_database() and adjusted DB creation to use cast.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
infogami/infobase/server.py Types _infobase and get_site() return value
infogami/infobase/infobase.py Adds type annotations for Infobase and Site internals and method signatures
infogami/infobase/dbstore.py Adds types for DB store classes and create_database() return type
infogami/infobase/core.py Adds typed abstract method signatures for store interface
infogami/infobase/client.py Adds type annotations for auth-token accessors and site cache
Comments suppressed due to low confidence (2)

infogami/infobase/server.py:199

  • get_site is annotated as returning infobase.Site | None, but most handlers assume it is non-optional (e.g. write.POST calls site.write(...), get_many.GET calls site.get_many(...), etc.). This is both a real runtime bug if an unknown/uninitialized site is requested (will raise AttributeError) and will introduce mypy errors now that the return type is optional. Either (a) make get_site return a non-optional Site and raise common.NotFound when the site/store doesn't exist, or (b) keep the optional return type and add explicit if site is None: raise common.NotFound(...) handling (or assert site is not None) at each call site that requires an existing site.
def get_site(sitename: str) -> infobase.Site | None:
    global _infobase
    if not _infobase:
        schema = dbstore.default_schema or dbstore.Schema()
        store = dbstore.DBStore(schema)
        _infobase = infobase.Infobase(store, config.secret_key)
    return _infobase.get(sitename)

infogami/infobase/server.py:198

  • _infobase is typed as Infobase | None, but the initialization guard uses if not _infobase:. For typing and correctness, prefer if _infobase is None: so type narrowing is unambiguous and you don't rely on truthiness semantics. This will also help mypy understand that _infobase is initialized after this block (e.g. when calling _infobase.create(...)).
_infobase: infobase.Infobase | None = None


def get_site(sitename: str) -> infobase.Site | None:
    global _infobase
    if not _infobase:
        schema = dbstore.default_schema or dbstore.Schema()
        store = dbstore.DBStore(schema)
        _infobase = infobase.Infobase(store, config.secret_key)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +72 to 73
def set_auth_token(self, token: str) -> None:
self.auth_token = token
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Connection.set_auth_token only accepts str, but self.auth_token is initialized to None and several call sites pass values that can be None (e.g. cookie lookups). For consistency and to avoid mypy mismatches, the parameter type should allow None (e.g. str | None) or the method should defensively normalize/raise when passed None.

Copilot uses AI. Check for mistakes.
Comment on lines +32 to 47
def __init__(self, db: web.DB, schema: Schema):
self.db = db
self.schema = schema
self.sitename = None
self.indexer = Indexer()
self.store = store.Store(self.db)
self.seq = sequence.SequenceImpl(self.db)

self.cache = None
self.cache: "Cache | None" = None
self.property_manager = PropertyManager(self.db)

def get_store(self):
return self.store

def set_cache(self, cache):
def set_cache(self, cache: "Cache"):
self.cache = cache
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DBSiteStore.cache is typed as optional (Cache | None) and initialized to None, but DBSiteStore.delete() later calls self.cache.clear() unconditionally. This can be triggered via DBStore.delete()/MultiDBStore.delete() paths that operate on a DBSiteStore without ever calling set_cache, leading to an AttributeError. Consider making cache non-optional by initializing it in __init__, or guarding usages (and/or ensuring set_cache is always called before any method that uses the cache).

Copilot uses AI. Check for mistakes.
Comment on lines 682 to 683
self.sitestore.initialize()
return self.sitestore
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DBStore.sitestore is now typed as DBSiteStore | None, but methods like create() return self.sitestore and call self.sitestore.initialize() after a conditional assignment. Mypy generally does not narrow attribute types across assignments, so this pattern will still be seen as optional and can cause type errors. A common fix is to assign to a local variable (e.g. sitestore = self.sitestore), initialize it if needed, then use/return the local variable (or add an assert self.sitestore is not None after initialization).

Suggested change
self.sitestore.initialize()
return self.sitestore
sitestore = self.sitestore
assert sitestore is not None
sitestore.initialize()
return sitestore

Copilot uses AI. Check for mistakes.
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.

3 participants