api.tracking: basic scaffolding for routers and views (fastapi models)

This commit is contained in:
Helmut Merz 2026-10-29 19:40:28 +01:00
parent 43921da820
commit 8ee3c8d015
7 changed files with 53 additions and 41 deletions

11
scopes/api/deps.py Normal file
View file

@ -0,0 +1,11 @@
# scopes.api.deps
"""Common API dependencies"""
import config
def storage():
stf = config.StorageFactory(config)
return stf(config.dbschema)

View file

@ -4,25 +4,15 @@ import sys
if '' not in sys.path: if '' not in sys.path:
sys.path = [''] + sys.path sys.path = [''] + sys.path
import config from fastapi import FastAPI
from scopes.storage import tracking
from scopes.storage.common import Storage
import transaction
from fastapi import Depends, FastAPI
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse
from typing import Annotated
# dependencies from scopes.api import tracking
def storage():
stf = config.StorageFactory(config)
return stf(config.dbschema)
# app and routes # app and routes
app = FastAPI() app = FastAPI()
app.include_router(tracking.router)
@app.get('/') @app.get('/')
async def read_root(): async def read_root():
@ -36,10 +26,3 @@ async def read_demo():
async def read_person(name: str, q: str | None = None): async def read_person(name: str, q: str | None = None):
return {'name': name, 'query': q} return {'name': name, 'query': q}
@app.get('/tracks')
async def get_tracks(storage: Annotated[Storage, Depends(storage)]):
tracks = storage.create(tracking.Container)
result = [tr.asDict() for tr in tracks.query()]
transaction.commit()
return result

View file

@ -1,5 +0,0 @@
# scopes.api.message
"""routes and views for Message objects"""

23
scopes/api/tracking.py Normal file
View file

@ -0,0 +1,23 @@
# scopes.api.tracking
"""basic (generic) routes and views for tracks (records)"""
from fastapi import APIRouter, Depends
from fastapi.responses import HTMLResponse
import transaction
from typing import Annotated
from scopes.api import deps
from scopes.storage import tracking
from scopes.storage.common import Storage
router = APIRouter()
@router.get('/tracks')
async def get_tracks(storage: Annotated[Storage, Depends(deps.storage)]):
tracks = storage.create(tracking.Container)
result = [tr.asDict() for tr in tracks.query()]
#result = [Track(tr) for tr in tracks.query()]
transaction.commit()
return result

View file

@ -3,6 +3,8 @@
import logging import logging
from pydantic_settings import BaseSettings, SettingsConfigDict from pydantic_settings import BaseSettings, SettingsConfigDict
from scopes.storage.db.postgres import StorageFactory
class Settings(BaseSettings): class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file='.env') model_config = SettingsConfigDict(env_file='.env')
@ -13,12 +15,11 @@ class Settings(BaseSettings):
log_format: str = '%(asctime)s %(levelname)s %(name)s %(message)s' log_format: str = '%(asctime)s %(levelname)s %(name)s %(message)s'
log_dateformat: str = '%Y-%m-%dT%H:%M:%S' log_dateformat: str = '%Y-%m-%dT%H:%M:%S'
dbengine: str = 'postgresql+psycopg'
dbengine: str = 'sqlite' dbname: str = 'testdb'
dbname: str = 'var/test.db' dbuser: str = 'testuser'
dbuser: str | None = None dbpassword: str = 'secret'
dbpassword: str | None = None dbschema: str = 'testing'
dbschema: str | None = None
settings = Settings() settings = Settings()
@ -30,7 +31,7 @@ base_url = settings.base_url
logging.basicConfig(filename=settings.log_file, level=settings.log_level, logging.basicConfig(filename=settings.log_file, level=settings.log_level,
format=settings.log_format, datefmt=settings.log_dateformat) format=settings.log_format, datefmt=settings.log_dateformat)
# SQLite storage settings # storage settings
dbengine = settings.dbengine dbengine = settings.dbengine
dbname = settings.dbname dbname = settings.dbname
dbuser = settings.dbuser dbuser = settings.dbuser

View file

@ -18,13 +18,8 @@ from scopes.api.main import app
@pytest.fixture(scope='module') @pytest.fixture(scope='module')
def storage(): def storage():
#storage = config.StorageFactory(config)(config.dbschema) storage = config.StorageFactory(config)(config.dbschema)
storage = main.storage()
storage.dropTable('tracks') storage.dropTable('tracks')
tracks = storage.create(tracking.Container)
tr01 = tracking.Track('t01', 'john')
tr01.update(dict(activity='testing'))
trid01 = tracks.save(tr01)
storage.commit() storage.commit()
return storage return storage
@ -43,6 +38,11 @@ def test_root():
assert response.json() == {'Hello': 'World'} assert response.json() == {'Hello': 'World'}
def test_tracking(storage, caplog): def test_tracking(storage, caplog):
tracks = storage.create(tracking.Container)
tr01 = tracking.Track('t01', 'john')
tr01.update(dict(activity='testing'))
trid01 = tracks.save(tr01)
storage.commit()
with TestClient(app) as clt: with TestClient(app) as clt:
caplog.set_level(config.settings.log_level) caplog.set_level(config.settings.log_level)
tracks = clt.get('/tracks').json() tracks = clt.get('/tracks').json()
@ -51,5 +51,5 @@ def test_tracking(storage, caplog):
tr['timeStamp'] = '...' tr['timeStamp'] = '...'
assert tr == {'uid': 'rec-1', 'head': {'taskId': 't01', 'userName': 'john'}, assert tr == {'uid': 'rec-1', 'head': {'taskId': 't01', 'userName': 'john'},
'data': {'activity': 'testing'}, 'timeStamp': '...'} 'data': {'activity': 'testing'}, 'timeStamp': '...'}
#print('\nLogs: ', caplog.text) #print('\n*** Logs: ', caplog.text)

View file

@ -17,8 +17,7 @@ k('session system')
@pytest.fixture(scope='module') @pytest.fixture(scope='module')
def storage(): def storage():
#storage = config.StorageFactory(config)(config.dbschema) storage = config.StorageFactory(config)(config.dbschema)
storage = main.storage()
storage.dropTable('tracks') storage.dropTable('tracks')
storage.dropTable('folders') storage.dropTable('folders')
storage.dropTable('types') storage.dropTable('types')