Conversation
ae2a31c to
fa9ffcc
Compare
fa9ffcc to
7467243
Compare
|
@cdrini can you ask copilot to review this one? |
There was a problem hiding this comment.
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/Siteand 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 usecast.
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_siteis annotated as returninginfobase.Site | None, but most handlers assume it is non-optional (e.g.write.POSTcallssite.write(...),get_many.GETcallssite.get_many(...), etc.). This is both a real runtime bug if an unknown/uninitialized site is requested (will raiseAttributeError) and will introduce mypy errors now that the return type is optional. Either (a) makeget_sitereturn a non-optionalSiteand raisecommon.NotFoundwhen the site/store doesn't exist, or (b) keep the optional return type and add explicitif site is None: raise common.NotFound(...)handling (orassert 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
_infobaseis typed asInfobase | None, but the initialization guard usesif not _infobase:. For typing and correctness, preferif _infobase is None:so type narrowing is unambiguous and you don't rely on truthiness semantics. This will also help mypy understand that_infobaseis 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.
| def set_auth_token(self, token: str) -> None: | ||
| self.auth_token = token |
There was a problem hiding this comment.
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.
| 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 |
There was a problem hiding this comment.
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).
| self.sitestore.initialize() | ||
| return self.sitestore |
There was a problem hiding this comment.
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).
| self.sitestore.initialize() | |
| return self.sitestore | |
| sitestore = self.sitestore | |
| assert sitestore is not None | |
| sitestore.initialize() | |
| return sitestore |
Some types I added while debugging database connection creation.