From dbd40485ba57f4ff8831e2f4e922b8242729c454 Mon Sep 17 00:00:00 2001 From: M Dombaugh Date: Sun, 1 Mar 2026 21:48:15 +0000 Subject: [PATCH] feat: enhanced capture queue with multi-type conversion, and bottom menu bar for cell phones --- CLAUDE.md | 443 + project-docs/_liefos-dev-test_results1.txt | 8633 +++++++++++++++++ project-docs/life-os-server-config.docx | 349 + project-docs/lifeos-architecture.docx | 3425 +++++++ ...lifeos-conversation-context-convo-test1.md | 57 + .../lifeos-conversation-context-convo4.md | 42 + project-docs/lifeos-database-backup.md | 44 + .../lifeos-development-status-convo4.md | 329 + .../lifeos-development-status-test1.md | 261 + project-docs/lifeos-setup.sh | 263 + project-docs/lifeos-v2-migration-plan.docx | 667 ++ project-docs/lifeos_r0_to_r1_migration.sql | 263 + project-docs/lifeos_r1_full_schema.sql | 979 ++ project-docs/lifeos_schema_r1.sql | 358 + project-docs/setup_dev_database.sh | 122 + project-docs/setup_prod_database.sh | 118 + setup-claude-code.sh | 97 + 17 files changed, 16450 insertions(+) create mode 100644 CLAUDE.md create mode 100644 project-docs/_liefos-dev-test_results1.txt create mode 100644 project-docs/life-os-server-config.docx create mode 100644 project-docs/lifeos-architecture.docx create mode 100644 project-docs/lifeos-conversation-context-convo-test1.md create mode 100644 project-docs/lifeos-conversation-context-convo4.md create mode 100644 project-docs/lifeos-database-backup.md create mode 100644 project-docs/lifeos-development-status-convo4.md create mode 100644 project-docs/lifeos-development-status-test1.md create mode 100644 project-docs/lifeos-setup.sh create mode 100644 project-docs/lifeos-v2-migration-plan.docx create mode 100644 project-docs/lifeos_r0_to_r1_migration.sql create mode 100644 project-docs/lifeos_r1_full_schema.sql create mode 100644 project-docs/lifeos_schema_r1.sql create mode 100644 project-docs/setup_dev_database.sh create mode 100644 project-docs/setup_prod_database.sh create mode 100644 setup-claude-code.sh diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..e8d290b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,443 @@ +# CLAUDE.md + +## Project Identity + +Life OS is a single-user personal productivity web app. Server-rendered monolith. No SPA, no frontend framework, no build pipeline. You are working on the codebase directly on the production server via mounted Docker volume. + +**Live URL:** https://lifeos-dev.invixiom.com +**Server:** defiant-01, 46.225.166.142, Ubuntu 24.04 +**Repo:** github.com/mdombaugh/lifeos-dev (main branch) + +--- + +## Tech Stack - Do Not Deviate + +- **Python 3.12 / FastAPI** (async) / **SQLAlchemy 2.0 async** with raw SQL via `text()` - **NO ORM models** +- **PostgreSQL 16** in Docker container `lifeos-db`, full-text search via tsvector/tsquery +- **Jinja2** server-rendered HTML templates +- **Vanilla CSS/JS** only. No npm. No React. No Tailwind. No build tools. +- **asyncpg** driver +- CSS custom properties for dark/light theme (`[data-theme='dark']` / `[data-theme='light']`) + +**Hard rules:** +- No fetch/XHR from JavaScript. Forms use standard HTML POST with 303 redirect (PRG pattern). +- JavaScript handles ONLY UI state: sidebar collapse, search modal, timer display, theme toggle, drag-to-reorder. +- All data operations go through BaseRepository or raw SQL. Never introduce an ORM model layer. + +--- + +## Working Directory + +All application code lives at `/opt/lifeos/dev/` on the server, mounted into the Docker container as `/app`. The container runs `uvicorn main:app --host 0.0.0.0 --port 8003 --workers 1 --reload`, so any file change is picked up immediately. No container rebuild needed. + +``` +/opt/lifeos/dev/ + main.py # FastAPI app init, 18 router includes + .env # DB creds (never commit) + Dockerfile + requirements.txt + core/ + __init__.py + database.py # Async engine, session factory, get_db dependency + base_repository.py # Generic CRUD with soft deletes + sidebar.py # Domain > area > project nav tree + badge counts + routers/ + domains.py, areas.py, projects.py, tasks.py + notes.py, links.py, focus.py, capture.py, contacts.py + search.py, admin.py, lists.py + files.py, meetings.py, decisions.py, weblinks.py + appointments.py, time_tracking.py + templates/ + base.html # Shell: topbar, sidebar, JS includes + dashboard.html, search.html, trash.html + [entity].html, [entity]_form.html, [entity]_detail.html + (42 templates total - all extend base.html) + static/ + style.css # ~1040 lines + app.js # ~190 lines + tests/ + introspect.py # Route discovery engine + form_factory.py # Form data generation + registry.py # Route registry + seed mapping + conftest.py # Fixtures: DB, client, 15 seed entities + test_smoke_dynamic.py # Auto-parametrized GET tests + test_crud_dynamic.py # Auto-parametrized POST tests + test_business_logic.py # Hand-written behavioral tests + route_report.py # CLI route dump + run_tests.sh # Test runner +``` + +--- + +## How to Make Changes + +**Read before writing.** Before modifying any file, read it first. The codebase has consistent patterns. Match them exactly. + +**Do not create deploy scripts or heredoc wrappers.** You have direct filesystem access to `/opt/lifeos/dev/`. Edit files in place. Hot reload handles the rest. + +**After changes, verify:** +```bash +docker logs lifeos-dev --tail 10 # Check for import/syntax errors +curl -s -o /dev/null -w "%{http_code}" http://localhost:8003/ # Should be 200 +``` + +**Commit when asked:** +```bash +cd /opt/lifeos/dev && git add . && git commit -m "description" && git push origin main +``` +Push uses PAT (personal access token) as password. + +--- + +## Database Access + +```bash +# Query +docker exec lifeos-db psql -U postgres -d lifeos_dev -c "SQL HERE" + +# Inspect table schema (DO THIS before writing code that touches a table) +docker exec lifeos-db psql -U postgres -d lifeos_dev -c "\d table_name" + +# List all tables +docker exec lifeos-db psql -U postgres -d lifeos_dev -c "\dt" +``` + +**Connection string (in .env):** +``` +DATABASE_URL=postgresql+asyncpg://postgres:UCTOQDZiUhN8U@lifeos-db:5432/lifeos_dev +FILE_STORAGE_PATH=/opt/lifeos/files/dev +ENVIRONMENT=development +``` + +**Three databases exist in lifeos-db:** +- `lifeos_dev` - Active development (this is what you work with) +- `lifeos_prod` - Production data (DO NOT TOUCH) +- `lifeos_test` - Test suite database + +**Always verify table schemas against the live DB before writing code.** The .sql files in the project-docs folder may be stale. The database is the source of truth: +```bash +docker exec lifeos-db psql -U postgres -d lifeos_dev -c "\d tasks" +``` + +--- + +## Backup Before Risky Changes + +```bash +mkdir -p /opt/lifeos/backups +docker exec lifeos-db pg_dump -U postgres -d lifeos_dev -Fc -f /tmp/lifeos_dev_backup.dump +docker cp lifeos-db:/tmp/lifeos_dev_backup.dump /opt/lifeos/backups/lifeos_dev_$(date +%Y%m%d_%H%M%S).dump +``` + +**Restore:** +```bash +docker exec lifeos-db psql -U postgres -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'lifeos_dev' AND pid <> pg_backend_pid();" +docker exec lifeos-db psql -U postgres -c "DROP DATABASE lifeos_dev;" +docker exec lifeos-db psql -U postgres -c "CREATE DATABASE lifeos_dev;" +docker cp /opt/lifeos/backups/FILENAME.dump lifeos-db:/tmp/restore.dump +docker exec lifeos-db pg_restore -U postgres -d lifeos_dev /tmp/restore.dump +docker restart lifeos-dev +``` + +--- + +## BaseRepository Pattern - Use It + +All CRUD goes through `core/base_repository.py`. Read this file to understand the API. Key methods: + +- `list(filters={}, sort='sort_order')` - Auto-filters `is_deleted=false` +- `get(id)` - Single record by UUID +- `create(data)` - Auto-sets created_at, updated_at, is_deleted=false +- `update(id, data)` - Auto-sets updated_at +- `soft_delete(id)` - Sets is_deleted=true, deleted_at=now() +- `restore(id)` - Reverses soft_delete +- `permanent_delete(id)` - Actual SQL DELETE (admin only) +- `bulk_soft_delete(ids)`, `reorder(ids)`, `count(filters)`, `list_deleted()` + +**Usage:** +```python +repo = BaseRepository("tasks", db) +items = await repo.list(filters={"project_id": project_id}) +``` + +**Nullable fields gotcha:** When a form field should allow setting a value to empty/null, the field name MUST be in the `nullable_fields` set in `core/base_repository.py`. Otherwise `update()` silently skips null values. Check this set before adding new nullable form fields. + +--- + +## Router Pattern - Follow Exactly + +Every router follows this structure. Do not invent new patterns. + +```python +from fastapi import APIRouter, Request, Form, Depends +from fastapi.responses import RedirectResponse +from fastapi.templating import Jinja2Templates +from core.base_repository import BaseRepository +from core.database import get_db +from core.sidebar import get_sidebar_data + +router = APIRouter(prefix='/things', tags=['things']) +templates = Jinja2Templates(directory='templates') + +@router.get('/') +async def list_things(request: Request, db=Depends(get_db)): + repo = BaseRepository("things", db) + items = await repo.list() + sidebar = await get_sidebar_data(db) + return templates.TemplateResponse('things.html', { + 'request': request, 'items': items, 'sidebar': sidebar + }) + +@router.post('/create') +async def create_thing(request: Request, db=Depends(get_db), + title: str = Form(...), description: str = Form(None)): + repo = BaseRepository("things", db) + item = await repo.create({'title': title, 'description': description}) + return RedirectResponse(url=f'/things/{item["id"]}', status_code=303) +``` + +**Every route MUST call `get_sidebar_data(db)` and pass `sidebar` to the template.** The sidebar navigation breaks without this. + +--- + +## Adding a New Entity - Checklist + +1. Create `routers/entity_name.py` using the pattern above +2. Add import + `app.include_router(router)` in `main.py` +3. Create templates in `templates/`: list, form, detail (all extend `base.html`) +4. Add nav link in `templates/base.html` sidebar section +5. Add entity config to `SEARCH_ENTITIES` dict in `routers/search.py` +6. Add entity config to `TRASH_ENTITIES` dict in `routers/admin.py` +7. Add any new nullable fields to `nullable_fields` in `core/base_repository.py` +8. If entity has a new table, add seed fixture to `tests/conftest.py` and prefix mapping to `tests/registry.py` +9. Test: visit the list page, create an item, edit it, delete it, verify it appears in trash and search + +--- + +## Universal Column Conventions + +Every table follows this structure. When creating new tables, match it exactly: + +```sql +id UUID PRIMARY KEY DEFAULT gen_random_uuid(), +-- [foreign keys, nullable where optional] +-- [content fields] +tags TEXT[], +sort_order INT NOT NULL DEFAULT 0, +is_deleted BOOL NOT NULL DEFAULT false, +deleted_at TIMESTAMPTZ, +created_at TIMESTAMPTZ NOT NULL DEFAULT now(), +updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +-- searchable tables also get: +-- search_vector TSVECTOR (maintained by trigger) +-- CREATE INDEX idx_tablename_search ON tablename USING GIN(search_vector); +``` + +--- + +## Key Enums / Values + +**Task status:** `open | in_progress | blocked | done | cancelled` +**Task priority:** `1=critical, 2=high, 3=normal, 4=low` +**Project status:** `active | on_hold | completed | archived` +**Process type:** `workflow | checklist` + +--- + +## Known Traps + +1. **`time_entries` has no `updated_at` column.** BaseRepository.soft_delete() will fail on this table. Use direct SQL instead. Same for restore. + +2. **Junction tables use raw SQL, not BaseRepository.** + ```python + await db.execute(text("INSERT INTO contact_meetings (contact_id, meeting_id, role) VALUES (:c, :m, :r) ON CONFLICT DO NOTHING"), {...}) + ``` + +3. **Timer constraint:** Only one timer runs at a time. `get_running_task_id()` in `routers/tasks.py` queries `time_entries WHERE end_at IS NULL`. Starting a new timer auto-stops the running one. + +4. **SSL cert path** on Nginx uses `kasm.invixiom.com-0001` (not `kasm.invixiom.com`). + +5. **No pagination.** All list views load all rows. Fine at current data volume. + +6. **No CSRF protection.** Single-user system. + +7. **Schema SQL files may be stale.** Always verify against live DB, not the .sql files in project-docs. + +8. **Test suite not fully green.** Async event loop fixes and seed data corrections are in progress. + +--- + +## CSS Design Tokens + +When adding styles, use these existing CSS custom properties. Do not hardcode colors. + +```css +/* Dark theme */ +--bg: #0D0E13; --surface: #14161F; --surface2: #1A1D28; --border: #252836; +--text: #DDE1F5; --muted: #5A6080; +--accent: #4F6EF7; --accent-soft: rgba(79,110,247,.12); +--green: #22C98A; --amber: #F5A623; --red: #F05252; --purple: #9B7FF5; + +/* Light theme */ +--bg: #F0F2F8; --surface: #FFFFFF; --surface2: #F7F8FC; --border: #E3E6F0; +--text: #171926; --muted: #8892B0; +--accent: #4F6EF7; --accent-soft: rgba(79,110,247,.10); +--green: #10B981; --amber: #F59E0B; --red: #DC2626; +``` + +--- + +## Docker / Infrastructure + +### Containers +| Container | Image | Port | Purpose | +|-----------|-------|------|---------| +| lifeos-db | postgres:16-alpine | 5432 (internal) | PostgreSQL: lifeos_dev + lifeos_prod + lifeos_test | +| lifeos-dev | lifeos-app | 8003 | Dev application (hot reload) | +| lifeos-prod | lifeos-app | 8002 | Prod application (NOT YET DEPLOYED) | + +### How the Dev Container Runs +```bash +docker run -d \ + --name lifeos-dev \ + --network lifeos_network \ + --restart unless-stopped \ + --env-file .env \ + -p 8003:8003 \ + -v /opt/lifeos/dev/files:/opt/lifeos/files/dev \ + -v /opt/lifeos/dev:/app \ + lifeos-app \ + uvicorn main:app --host 0.0.0.0 --port 8003 --workers 1 --reload +``` + +### Nginx +Host-level (not containerized). Config at `/etc/nginx/sites-available/invixiom`. +- `lifeos-dev.invixiom.com` -> `localhost:8003` +- `lifeos.invixiom.com` -> `localhost:8002` (pending) +- SSL cert at `/etc/letsencrypt/live/kasm.invixiom.com-0001/` + +### Docker Network +`lifeos_network` (172.21.0.0/16) - bridges lifeos-db, lifeos-dev, lifeos-prod + +--- + +## Test Suite + +Tests use dynamic introspection. They discover routes from the live app at runtime. No hardcoded routes. + +```bash +docker exec lifeos-dev bash /app/tests/run_tests.sh # Full suite +docker exec lifeos-dev bash /app/tests/run_tests.sh report # Route introspection dump +docker exec lifeos-dev bash /app/tests/run_tests.sh smoke # All GET endpoints +docker exec lifeos-dev bash /app/tests/run_tests.sh crud # All POST create/edit/delete +docker exec lifeos-dev bash /app/tests/run_tests.sh logic # Business logic +docker exec lifeos-dev bash /app/tests/run_tests.sh fast # Smoke, stop on first fail +docker exec lifeos-dev bash /app/tests/run_tests.sh -k "timer" # Keyword filter +``` + +**After schema changes, reset the test DB:** +```bash +docker exec lifeos-db psql -U postgres -c "DROP DATABASE IF EXISTS lifeos_test;" +docker exec lifeos-db psql -U postgres -c "CREATE DATABASE lifeos_test;" +docker exec lifeos-db pg_dump -U postgres -d lifeos_dev --schema-only -f /tmp/s.sql +docker exec lifeos-db psql -U postgres -d lifeos_test -f /tmp/s.sql -q +``` + +--- + +## Current Build State (as of 2026-03-01) + +**Phase 1, Tier 3 in progress.** 2 of 6 Tier 3 features complete. + +### What's Built +18 routers, 42 templates. Core CRUD for: domains, areas, projects, tasks, notes, links, focus, capture, contacts, search, admin/trash, lists, files, meetings, decisions, weblinks, appointments, time_tracking. + +Working features: collapsible sidebar nav tree, task filtering/sorting/priority/status/context, daily focus, markdown notes with preview, file uploads with inline preview, global search (Cmd/K) via tsvector, admin trash with restore, time tracking with topbar timer pill, timer play/stop on task rows and detail pages. + +### What's NOT Built Yet + +**Tier 3 remaining (4 features, build in this order):** +1. **Processes / Process Runs** - Most complex. 4 tables: processes, process_steps, process_runs, process_run_steps. Template CRUD, run instantiation (copies steps as immutable snapshot), step completion, task generation (all_at_once vs step_by_step). +2. **Calendar view** - Unified `/calendar`: appointments (start_at) + meetings (meeting_date) + tasks (due_date). No new tables. Read-only. +3. **Time budgets** - Simple CRUD: domain_id + weekly_hours + effective_from. Dashboard overcommitment warnings. +4. **Eisenhower matrix** - Derived 2x2 grid. Priority 1-2 = Important, 3-4 = Not. Due <=7d = Urgent. Clickable quadrants. + +**Tier 4 (later):** Releases/milestones, dependencies (DAG with cycle detection), task templates, note wiki-linking, note folders, bulk actions, CSV export, drag-to-reorder, reminders, dashboard metrics. + +**Phase 2:** DAG visualization, MCP/AI gateway (dual: MCP + OpenAI function calling), note version history. +**Phase 3:** Mobile improvements, authentication, browser extension. + +--- + +## Conversation History + +| Session | What Was Built | +|---------|----------------| +| Pre-build | Architecture doc (50 tables, 3-phase plan), server config, schema design | +| Convo 1 | Foundation: 9 routers (domains, areas, projects, tasks, notes, links, focus, capture, contacts), base templates, sidebar, dashboard | +| Convo 2 | 7 more routers: search, admin/trash, lists, files, meetings, decisions, weblinks | +| Convo 3 | Tier 3 start: appointments CRUD, time tracking with topbar timer pill | +| Convo 4 | Timer buttons on task rows and detail pages (completes time tracking UX) | +| Test1 | Dynamic introspection-based test suite (11 files, 121 routes discovered) | +| Test2 | Test suite debugging: async event loop fixes, seed data corrections (in progress) | + +--- + +## Database Schema Overview (48 tables in dev) + +### Core Hierarchy +domains, areas, projects, tasks + +### Content +notes, note_folders, lists, list_items, links, files, weblinks, weblink_folders + +### CRM & Meetings +contacts, appointments, meetings, decisions + +### Time Management +time_entries, time_blocks, time_budgets, daily_focus + +### Processes (tables exist, CRUD not built yet) +processes, process_steps, process_runs, process_run_steps + +### System +capture, context_types, reminders, dependencies, releases, milestones, task_templates, task_template_items + +### Junction Tables (17) +note_projects, note_links, file_mappings, release_projects, release_domains, contact_tasks, contact_projects, contact_lists, contact_list_items, contact_appointments, contact_meetings, decision_projects, decision_contacts, meeting_tasks, process_run_tasks, folder_weblinks, note_version_history + +--- + +## Reference Documents + +These files are in the `project-docs/` folder alongside this CLAUDE.md. Consult them when you need deeper context: + +| File | What It Contains | +|------|------------------| +| `lifeos-development-status-convo4.md` | **App source of truth.** Complete inventory of routers, templates, deploy patterns, what's remaining. | +| `lifeos-development-status-test1.md` | **Test source of truth.** Test architecture, seed data, introspection details. | +| `lifeos-conversation-context-convo4.md` | Quick context card for app development. | +| `lifeos-conversation-context-convo-test1.md` | Quick context card for test development. | +| `lifeos-architecture.docx` | Full system spec. 50 tables, all subsystems, UI patterns, build plan. | +| `life-os-server-config.docx` | Server infrastructure: containers, ports, networks, Nginx, SSL details. | +| `lifeos_r1_full_schema.sql` | Intended R1 schema (may not match actual DB - always verify against live). | +| `lifeos_schema_r1.sql` | Schema reference (same caveat). | +| `lifeos_r0_to_r1_migration.sql` | Migration script from old Supabase schema. | +| `lifeos-setup.sh` | Repeatable server infrastructure setup script. | +| `setup_dev_database.sh` | Dev database setup. | +| `setup_prod_database.sh` | Prod database setup. | +| `lifeos-database-backup.md` | Backup and restore commands. | +| `lifeos-v2-migration-plan.docx` | V2 migration planning. | +| `_liefos-dev-test_results1.txt` | First test deploy output (introspection verification). | + +--- + +## Design Principles + +- **KISS.** Simple wins. Complexity must earn its place. +- **Logical deletes everywhere.** No data permanently destroyed without admin confirmation. +- **Generic over specific.** Shared base code. Config-driven where possible. +- **Consistent patterns.** Every list, form, detail view follows identical conventions. +- **Search is first-class.** Every new entity gets added to global search. +- **Context travels with navigation.** Drill-down pre-fills context into create forms. +- **Single source of truth.** One system for everything. diff --git a/project-docs/_liefos-dev-test_results1.txt b/project-docs/_liefos-dev-test_results1.txt new file mode 100644 index 0000000..10b839c --- /dev/null +++ b/project-docs/_liefos-dev-test_results1.txt @@ -0,0 +1,8633 @@ +root@defiant-01:/opt/lifeos/dev# cd /opt/lifeos/dev && bash deploy-tests.sh +=== Life OS Dynamic Test Suite === + +[1/5] Setting up test database... +DROP DATABASE +CREATE DATABASE + set_config +------------ + +(1 row) + + Test DB: 48 tables (cloned from lifeos_dev) + +[2/5] Installing test dependencies... +[notice] To update, run: pip install --upgrade pip + +[3/5] Writing test files... + +[4/5] Verifying route introspection... + Routes discovered: 121 + GET (no params): 36 + GET (with params): 23 + POST create: 13 + POST edit: 13 + POST delete: 17 + POST action: 19 + Entity prefixes: 32 + +[5/5] Files deployed... + tests/conftest.py (274 lines) + tests/form_factory.py (195 lines) + tests/__init__.py (0 lines) + tests/introspect.py (357 lines) + tests/registry.py (79 lines) + tests/route_report.py (65 lines) + tests/run_tests.sh (22 lines) + tests/test_business_logic.py (212 lines) + tests/test_crud_dynamic.py (161 lines) + tests/test_smoke_dynamic.py (100 lines) + +=== Deployment complete === + + docker exec lifeos-dev bash /app/tests/run_tests.sh report # Verify routes + docker exec lifeos-dev bash /app/tests/run_tests.sh smoke # All GETs + docker exec lifeos-dev bash /app/tests/run_tests.sh crud # All CRUDs + docker exec lifeos-dev bash /app/tests/run_tests.sh logic # Business logic + docker exec lifeos-dev bash /app/tests/run_tests.sh # Full suite + +root@defiant-01:/opt/lifeos/dev# docker exec lifeos-dev bash /app/tests/run_tests.sh report +============================================= + Life OS Dynamic Test Suite +============================================= + +>> Route report +====================================================================== +LIFE OS ROUTE REGISTRY +Total routes discovered: 121 +====================================================================== + + / + ──────────────────────────────────────────────────────────── + GET / page + + /admin/trash + ──────────────────────────────────────────────────────────── + GET /admin/trash/ page query=[entity_type] + POST /admin/trash/{table}/{item_id}/permanent-delete action + POST /admin/trash/{table}/{item_id}/restore action + + /admin/trash/empty + ──────────────────────────────────────────────────────────── + POST /admin/trash/empty action + + /appointments + ──────────────────────────────────────────────────────────── + GET /appointments/ list query=[status, timeframe] + POST /appointments/create create fields=[title, description, location, start_date, start_time, end_date, end_time, all_day, recurrence, tags, contact_ids] + GET /appointments/{appointment_id} detail + POST /appointments/{appointment_id}/delete delete + GET /appointments/{appointment_id}/edit edit_form + POST /appointments/{appointment_id}/edit edit fields=[title, description, location, start_date, start_time, end_date, end_time, all_day, recurrence, tags, contact_ids] + + /appointments/new + ──────────────────────────────────────────────────────────── + GET /appointments/new page + + /areas + ──────────────────────────────────────────────────────────── + GET /areas/ list query=[domain_id] + GET /areas/create create_form query=[domain_id] + POST /areas/create create fields=[name, domain_id, description, status] + POST /areas/{area_id}/delete delete + GET /areas/{area_id}/edit edit_form + POST /areas/{area_id}/edit edit fields=[name, domain_id, description, status] + + /capture + ──────────────────────────────────────────────────────────── + GET /capture/ list query=[show] + POST /capture/{capture_id}/delete delete + POST /capture/{capture_id}/dismiss action + POST /capture/{capture_id}/to-task action fields=[domain_id, project_id] + + /capture/add + ──────────────────────────────────────────────────────────── + POST /capture/add action fields=[raw_text] + + /contacts + ──────────────────────────────────────────────────────────── + GET /contacts/ list + GET /contacts/create create_form + POST /contacts/create create fields=[first_name, last_name, company, role, email, phone, notes, tags] + GET /contacts/{contact_id} detail + POST /contacts/{contact_id}/delete delete + GET /contacts/{contact_id}/edit edit_form + POST /contacts/{contact_id}/edit edit fields=[first_name, last_name, company, role, email, phone, notes, tags] + + /decisions + ──────────────────────────────────────────────────────────── + GET /decisions/ list query=[status, impact] + GET /decisions/create create_form query=[meeting_id] + POST /decisions/create create fields=[title, rationale, status, impact, decided_at, meeting_id, tags] + GET /decisions/{decision_id} detail + POST /decisions/{decision_id}/delete delete + GET /decisions/{decision_id}/edit edit_form + POST /decisions/{decision_id}/edit edit fields=[title, rationale, status, impact, decided_at, meeting_id, superseded_by_id, tags] + + /domains + ──────────────────────────────────────────────────────────── + GET /domains/ list + GET /domains/create create_form + POST /domains/create create fields=[name, color, description] + POST /domains/{domain_id}/delete delete + GET /domains/{domain_id}/edit edit_form + POST /domains/{domain_id}/edit edit fields=[name, color, description] + + /files + ──────────────────────────────────────────────────────────── + GET /files/ list query=[context_type, context_id] + POST /files/{file_id}/delete delete + GET /files/{file_id}/download detail + GET /files/{file_id}/preview detail + GET /files/{file_id}/serve detail + + /files/upload + ──────────────────────────────────────────────────────────── + GET /files/upload page query=[context_type, context_id] + POST /files/upload action fields=[file*, description, tags, context_type, context_id] + + /focus + ──────────────────────────────────────────────────────────── + GET /focus/ list query=[focus_date] + POST /focus/{focus_id}/remove action + POST /focus/{focus_id}/toggle toggle + + /focus/add + ──────────────────────────────────────────────────────────── + POST /focus/add action fields=[task_id, focus_date] + + /health + ──────────────────────────────────────────────────────────── + GET /health list + + /links + ──────────────────────────────────────────────────────────── + GET /links/ list query=[domain_id] + GET /links/create create_form query=[domain_id, project_id] + POST /links/create create fields=[label, url, domain_id, project_id, description] + POST /links/{link_id}/delete delete + GET /links/{link_id}/edit edit_form + POST /links/{link_id}/edit edit fields=[label, url, domain_id, project_id, description] + + /lists + ──────────────────────────────────────────────────────────── + GET /lists/ list query=[domain_id, project_id] + GET /lists/create create_form query=[domain_id, project_id] + POST /lists/create create fields=[name, domain_id, area_id, project_id, list_type, description, tags] + GET /lists/{list_id} detail + POST /lists/{list_id}/delete delete + GET /lists/{list_id}/edit edit_form + POST /lists/{list_id}/edit edit fields=[name, domain_id, area_id, project_id, list_type, description, tags] + POST /lists/{list_id}/items/add action fields=[content, parent_item_id] + POST /lists/{list_id}/items/{item_id}/delete delete + POST /lists/{list_id}/items/{item_id}/edit edit fields=[content] + POST /lists/{list_id}/items/{item_id}/toggle toggle + + /meetings + ──────────────────────────────────────────────────────────── + GET /meetings/ list query=[status] + GET /meetings/create create_form + POST /meetings/create create fields=[title, meeting_date, start_at, end_at, location, status, priority, parent_id, agenda, tags] + GET /meetings/{meeting_id} detail + POST /meetings/{meeting_id}/action-item action fields=[title, domain_id] + POST /meetings/{meeting_id}/delete delete + GET /meetings/{meeting_id}/edit edit_form + POST /meetings/{meeting_id}/edit edit fields=[title, meeting_date, start_at, end_at, location, status, priority, parent_id, agenda, transcript, notes_body, tags] + + /notes + ──────────────────────────────────────────────────────────── + GET /notes/ list query=[domain_id, project_id] + GET /notes/create create_form query=[domain_id, project_id] + POST /notes/create create fields=[title, domain_id, project_id, body, content_format, tags] + GET /notes/{note_id} detail + POST /notes/{note_id}/delete delete + GET /notes/{note_id}/edit edit_form + POST /notes/{note_id}/edit edit fields=[title, domain_id, project_id, body, content_format, tags] + + /projects + ──────────────────────────────────────────────────────────── + GET /projects/ list query=[domain_id, status] + GET /projects/create create_form query=[domain_id, area_id] + POST /projects/create create fields=[name, domain_id, area_id, description, status, priority, start_date, target_date, tags] + GET /projects/{project_id} detail query=[tab] + POST /projects/{project_id}/delete delete + GET /projects/{project_id}/edit edit_form + POST /projects/{project_id}/edit edit fields=[name, domain_id, area_id, description, status, priority, start_date, target_date, tags] + + /search + ──────────────────────────────────────────────────────────── + GET /search/ list query=[q] + + /search/api + ──────────────────────────────────────────────────────────── + GET /search/api page query=[q, entity_type, limit] + + /tasks + ──────────────────────────────────────────────────────────── + GET /tasks/ list query=[domain_id, project_id, status, priority, context, sort] + GET /tasks/create create_form query=[domain_id, project_id, parent_id] + POST /tasks/create create fields=[title, domain_id, project_id, parent_id, description, priority, status, due_date, deadline, context, tags, estimated_minutes, energy_required] + GET /tasks/{task_id} detail + POST /tasks/{task_id}/complete action + POST /tasks/{task_id}/delete delete + GET /tasks/{task_id}/edit edit_form + POST /tasks/{task_id}/edit edit fields=[title, domain_id, project_id, parent_id, description, priority, status, due_date, deadline, context, tags, estimated_minutes, energy_required] + POST /tasks/{task_id}/toggle toggle + + /tasks/quick-add + ──────────────────────────────────────────────────────────── + POST /tasks/quick-add action fields=[title, domain_id, project_id] + + /time + ──────────────────────────────────────────────────────────── + GET /time/ list query=[task_id, days] + POST /time/{entry_id}/delete delete + + /time/manual + ──────────────────────────────────────────────────────────── + POST /time/manual action fields=[task_id, date, duration_minutes, notes] + + /time/running + ──────────────────────────────────────────────────────────── + GET /time/running json + + /time/start + ──────────────────────────────────────────────────────────── + POST /time/start action fields=[task_id] + + /time/stop + ──────────────────────────────────────────────────────────── + POST /time/stop action fields=[entry_id] + + /weblinks + ──────────────────────────────────────────────────────────── + GET /weblinks/ list query=[folder_id] + GET /weblinks/create create_form query=[folder_id] + POST /weblinks/create create fields=[label, url, description, folder_id, tags] + POST /weblinks/{weblink_id}/delete delete + GET /weblinks/{weblink_id}/edit edit_form + POST /weblinks/{weblink_id}/edit edit fields=[label, url, description, folder_id, tags] + + /weblinks/folders + ──────────────────────────────────────────────────────────── + GET /weblinks/folders/create create_form + POST /weblinks/folders/create create fields=[name, parent_id] + POST /weblinks/folders/{folder_id}/delete delete + + +====================================================================== +SUMMARY +====================================================================== + Total routes: 121 + GET (no params): 36 + GET (with params): 23 + POST create: 13 + POST edit: 13 + POST delete: 17 + POST action/toggle: 19 + Entity prefixes: 32 + + +PREFIX_TO_SEED coverage: +---------------------------------------------------------------------- + / SKIP (no seed) + /admin/trash SKIP (no seed) + /admin/trash/empty SKIP (no seed) + /appointments OK + /appointments/new SKIP (no seed) + /areas OK + /capture OK + /capture/add SKIP (no seed) + /contacts OK + /decisions OK + /domains OK + /files SKIP (no seed) + /files/upload SKIP (no seed) + /focus OK + /focus/add SKIP (no seed) + /health SKIP (no seed) + /links OK + /lists OK + /meetings OK + /notes OK + /projects OK + /search SKIP (no seed) + /search/api SKIP (no seed) + /tasks OK + /tasks/quick-add SKIP (no seed) + /time OK + /time/manual SKIP (no seed) + /time/running SKIP (no seed) + /time/start SKIP (no seed) + /time/stop SKIP (no seed) + /weblinks OK + /weblinks/folders OK + +Form field details for create routes: +---------------------------------------------------------------------- + + /domains/create + name: str + color: Optional + description: Optional + + /areas/create + name: str + domain_id: str + description: Optional + status: str + + /projects/create + name: str + domain_id: str + area_id: Optional + description: Optional + status: str + priority: int + start_date: Optional + target_date: Optional + tags: Optional + + /tasks/create + title: str + domain_id: str + project_id: Optional + parent_id: Optional + description: Optional + priority: int + status: str + due_date: Optional + deadline: Optional + context: Optional + tags: Optional + estimated_minutes: Optional + energy_required: Optional + + /notes/create + title: str + domain_id: str + project_id: Optional + body: Optional + content_format: str + tags: Optional + + /links/create + label: str + url: str + domain_id: str + project_id: Optional + description: Optional + + /contacts/create + first_name: str + last_name: Optional + company: Optional + role: Optional + email: Optional + phone: Optional + notes: Optional + tags: Optional + + /lists/create + name: str + domain_id: str + area_id: Optional + project_id: Optional + list_type: str + description: Optional + tags: Optional + + /meetings/create + title: str + meeting_date: str + start_at: Optional + end_at: Optional + location: Optional + status: str + priority: Optional + parent_id: Optional + agenda: Optional + tags: Optional + + /decisions/create + title: str + rationale: Optional + status: str + impact: str + decided_at: Optional + meeting_id: Optional + tags: Optional + + /weblinks/create + label: str + url: str + description: Optional + folder_id: Optional + tags: Optional + + /weblinks/folders/create + name: str + parent_id: Optional + + /appointments/create + title: str + description: Optional + location: Optional + start_date: str + start_time: Optional + end_date: Optional + end_time: Optional + all_day: Optional + recurrence: Optional + tags: Optional + contact_ids: Optional + +Done +root@defiant-01:/opt/lifeos/dev# docker exec lifeos-dev bash /app/tests/run_tests.sh smoke +============================================= + Life OS Dynamic Test Suite +============================================= + +>> Smoke tests +============================= test session starts ============================== +platform linux -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0 -- /usr/local/bin/python +cachedir: .pytest_cache +rootdir: /app +configfile: pytest.ini +plugins: asyncio-1.3.0, anyio-4.12.1 +asyncio: mode=Mode.AUTO, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function +collecting ... collected 60 items + +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /] PASSED [ 1%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /health] PASSED [ 3%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /domains/] FAILED [ 5%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /domains/create] FAILED [ 6%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /areas/] FAILED [ 8%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /areas/create] FAILED [ 10%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /projects/] FAILED [ 11%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /projects/create] FAILED [ 13%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /tasks/] FAILED [ 15%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /tasks/create] FAILED [ 16%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /notes/] FAILED [ 18%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /notes/create] FAILED [ 20%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /links/] FAILED [ 21%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /links/create] FAILED [ 23%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /focus/] FAILED [ 25%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /capture/] FAILED [ 26%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /contacts/] FAILED [ 28%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /contacts/create] FAILED [ 30%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /search/api] FAILED [ 31%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /search/] FAILED [ 33%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /admin/trash/] FAILED [ 35%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /lists/] FAILED [ 36%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /lists/create] FAILED [ 38%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /files/] FAILED [ 40%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /files/upload] FAILED [ 41%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /meetings/] FAILED [ 43%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /meetings/create] FAILED [ 45%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /decisions/] FAILED [ 46%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /decisions/create] FAILED [ 48%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /weblinks/] FAILED [ 50%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /weblinks/create] FAILED [ 51%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /weblinks/folders/create] FAILED [ 53%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /appointments/] FAILED [ 55%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /appointments/new] FAILED [ 56%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /time/] FAILED [ 58%] +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /time/running] FAILED [ 60%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /domains/{domain_id}/edit] ERROR [ 61%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /areas/{area_id}/edit] ERROR [ 63%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /projects/{project_id}] ERROR [ 65%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /projects/{project_id}/edit] ERROR [ 66%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /tasks/{task_id}] ERROR [ 68%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /tasks/{task_id}/edit] ERROR [ 70%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /notes/{note_id}] ERROR [ 71%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /notes/{note_id}/edit] ERROR [ 73%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /links/{link_id}/edit] ERROR [ 75%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /contacts/{contact_id}] ERROR [ 76%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /contacts/{contact_id}/edit] ERROR [ 78%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /lists/{list_id}] ERROR [ 80%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /lists/{list_id}/edit] ERROR [ 81%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /files/{file_id}/download] ERROR [ 83%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /files/{file_id}/preview] ERROR [ 85%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /files/{file_id}/serve] ERROR [ 86%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /meetings/{meeting_id}] ERROR [ 88%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /meetings/{meeting_id}/edit] ERROR [ 90%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /decisions/{decision_id}] ERROR [ 91%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /decisions/{decision_id}/edit] ERROR [ 93%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /weblinks/{weblink_id}/edit] ERROR [ 95%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /appointments/{appointment_id}] ERROR [ 96%] +tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /appointments/{appointment_id}/edit] ERROR [ 98%] +tests/test_smoke_dynamic.py::test_get_with_fake_id_returns_404[NOTSET] SKIPPED [100%] + +==================================== ERRORS ==================================== +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /domains/{domain_id}/edit] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('78c75285-a5c9-4a18-9a06-adccbce3a022', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /areas/{area_id}/edit] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('1b388db7-0e79-43e5-a129-eeba449d1049', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /projects/{project_id}] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('b7be8530-ae2a-4c0b-b3c7-5b636a6fd9c2', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /projects/{project_id}/edit] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('677c81b0-1d4d-4ea0-a9ac-c680f4f00f6d', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +__ ERROR at setup of test_get_with_valid_id_returns_200[GET /tasks/{task_id}] __ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('62f7c7b9-c3bc-469c-8232-67781f3e69d0', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /tasks/{task_id}/edit] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('bda30a3c-3381-4c0a-9210-5c645692b2b9', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +__ ERROR at setup of test_get_with_valid_id_returns_200[GET /notes/{note_id}] __ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('61496ec7-6f6a-42e7-a03c-570e235284a5', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /notes/{note_id}/edit] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('6366c968-21b0-4a30-a6fe-4d8b3a2a4706', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /links/{link_id}/edit] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('0706dc19-3727-4398-8729-3e5127fc54c4', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /contacts/{contact_id}] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('e388bc10-d24c-4149-803f-f17b4390da7d', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /contacts/{contact_id}/edit] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('30714950-55d2-4024-ad63-a60ec4a4d88b', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +__ ERROR at setup of test_get_with_valid_id_returns_200[GET /lists/{list_id}] __ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('1cdb10cd-38ff-4355-a611-1c1183d68ec9', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /lists/{list_id}/edit] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('52744af6-49ac-483f-9e00-72cb9a067927', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /files/{file_id}/download] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('c6dd208e-0400-4601-8493-75b92c0d12f9', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /files/{file_id}/preview] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('0a79dd35-f660-464d-83c8-61e5f8daba30', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /files/{file_id}/serve] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('c3b90d81-6b46-4ecc-ae47-a8c32150d921', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /meetings/{meeting_id}] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('987863e1-fff0-428c-8506-e5dbc6e59e2c', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /meetings/{meeting_id}/edit] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('2a4914fb-b7e9-4223-b267-372dd4ed970d', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /decisions/{decision_id}] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('51a51449-b25c-4805-aaab-34ea9841e3a4', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /decisions/{decision_id}/edit] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('7d9b9b6e-c78a-4309-b393-d178f6c85385', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /weblinks/{weblink_id}/edit] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('6e21f2a4-d200-425f-b8d6-375f1eabe62b', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /appointments/{appointment_id}] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('f1f5f8ea-a0d2-4c64-af3d-8876938a273c', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_ ERROR at setup of test_get_with_valid_id_returns_200[GET /appointments/{appointment_id}/edit] _ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:458: in setup + return super().setup() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:743: in pytest_fixture_setup + hook_result = yield + ^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:361: in _async_fixture_wrapper + result = runner.run(setup(), context=context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/runners.py:118: in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/asyncio/base_events.py:691: in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:357: in setup + res = await fixture_function(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +tests/conftest.py:72: in seed_domain + await db_session.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +E [parameters: ('3ce7a5d5-7e97-40e9-8c80-88aa53469842', 'Test Domain', '#FF5733', 'Auto test domain')] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +=================================== FAILURES =================================== +________________ test_get_no_params_returns_200[GET /domains/] _________________ + + Exception Group Traceback (most recent call last): + | File "/usr/local/lib/python3.12/site-packages/starlette/_utils.py", line 76, in collapse_excgroups + | yield + | File "/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py", line 186, in __call__ + | async with anyio.create_task_group() as task_group: + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/anyio/_backends/_asyncio.py", line 783, in __aexit__ + | raise BaseExceptionGroup( + | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception) + +-+---------------- 1 ---------------- + | Traceback (most recent call last): + | File "/usr/local/lib/python3.12/site-packages/_pytest/runner.py", line 353, in from_call + | result: TResult | None = func() + | ^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/_pytest/runner.py", line 245, in + | lambda: runtest_hook(item=item, **kwds), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/pluggy/_hooks.py", line 512, in __call__ + | return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/pluggy/_manager.py", line 120, in _hookexec + | return self._inner_hookexec(hook_name, methods, kwargs, firstresult) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/pluggy/_callers.py", line 167, in _multicall + | raise exception + | File "/usr/local/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall + | teardown.throw(exception) + | File "/usr/local/lib/python3.12/site-packages/_pytest/logging.py", line 850, in pytest_runtest_call + | yield + | File "/usr/local/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall + | teardown.throw(exception) + | File "/usr/local/lib/python3.12/site-packages/_pytest/capture.py", line 900, in pytest_runtest_call + | return (yield) + | ^^^^^ + | File "/usr/local/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall + | teardown.throw(exception) + | File "/usr/local/lib/python3.12/site-packages/_pytest/skipping.py", line 268, in pytest_runtest_call + | return (yield) + | ^^^^^ + | File "/usr/local/lib/python3.12/site-packages/pluggy/_callers.py", line 121, in _multicall + | res = hook_impl.function(*args) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/_pytest/runner.py", line 179, in pytest_runtest_call + | item.runtest() + | File "/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py", line 469, in runtest + | super().runtest() + | File "/usr/local/lib/python3.12/site-packages/_pytest/python.py", line 1720, in runtest + | self.ihook.pytest_pyfunc_call(pyfuncitem=self) + | File "/usr/local/lib/python3.12/site-packages/pluggy/_hooks.py", line 512, in __call__ + | return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/pluggy/_manager.py", line 120, in _hookexec + | return self._inner_hookexec(hook_name, methods, kwargs, firstresult) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/pluggy/_callers.py", line 167, in _multicall + | raise exception + | File "/usr/local/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall + | teardown.throw(exception) + | File "/usr/local/lib/python3.12/site-packages/pluggy/_callers.py", line 53, in run_old_style_hookwrapper + | return result.get_result() + | ^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/pluggy/_result.py", line 103, in get_result + | raise exc.with_traceback(tb) + | File "/usr/local/lib/python3.12/site-packages/pluggy/_callers.py", line 38, in run_old_style_hookwrapper + | res = yield + | ^^^^^ + | File "/usr/local/lib/python3.12/site-packages/pluggy/_callers.py", line 121, in _multicall + | res = hook_impl.function(*args) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/_pytest/python.py", line 166, in pytest_pyfunc_call + | result = testfunction(**testargs) + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py", line 716, in inner + | runner.run(coro, context=context) + | File "/usr/local/lib/python3.12/asyncio/runners.py", line 118, in run + | return self._loop.run_until_complete(task) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/asyncio/base_events.py", line 691, in run_until_complete + | return future.result() + | ^^^^^^^^^^^^^^^ + | File "/app/tests/test_smoke_dynamic.py", line 49, in test_get_no_params_returns_200 + | r = await client.get(path) + | ^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 1768, in get + | return await self.request( + | ^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 1540, in request + | return await self.send(request, auth=auth, follow_redirects=follow_redirects) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 1629, in send + | response = await self._send_handling_auth( + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 1657, in _send_handling_auth + | response = await self._send_handling_redirects( + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 1694, in _send_handling_redirects + | response = await self._send_single_request(request) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 1730, in _send_single_request + | response = await transport.handle_async_request(request) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py", line 170, in handle_async_request + | await self.app(scope, receive, send) + | File "/usr/local/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__ + | await super().__call__(scope, receive, send) + | File "/usr/local/lib/python3.12/site-packages/starlette/applications.py", line 113, in __call__ + | await self.middleware_stack(scope, receive, send) + | File "/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 187, in __call__ + | raise exc + | File "/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 165, in __call__ + | await self.app(scope, receive, _send) + | File "/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py", line 185, in __call__ + | with collapse_excgroups(): + | ^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/contextlib.py", line 158, in __exit__ + | self.gen.throw(value) + | File "/usr/local/lib/python3.12/site-packages/starlette/_utils.py", line 82, in collapse_excgroups + | raise exc + | File "/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py", line 187, in __call__ + | response = await self.dispatch_func(request, call_next) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/app/main.py", line 79, in add_request_context + | response = await call_next(request) + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py", line 163, in call_next + | raise app_exc + | File "/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py", line 149, in coro + | await self.app(scope, receive_or_disconnect, send_no_error) + | File "/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in __call__ + | await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) + | File "/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app + | raise exc + | File "/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app + | await app(scope, receive, sender) + | File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 715, in __call__ + | await self.middleware_stack(scope, receive, send) + | File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 735, in app + | await route.handle(scope, receive, send) + | File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 288, in handle + | await self.app(scope, receive, send) + | File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 76, in app + | await wrap_app_handling_exceptions(app, request)(scope, receive, send) + | File "/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app + | raise exc + | File "/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app + | await app(scope, receive, sender) + | File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 73, in app + | response = await f(request) + | ^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/fastapi/routing.py", line 301, in app + | raw_response = await run_endpoint_function( + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/fastapi/routing.py", line 212, in run_endpoint_function + | return await dependant.call(**values) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/app/routers/domains.py", line 20, in list_domains + | sidebar = await get_sidebar_data(db) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/app/core/sidebar.py", line 14, in get_sidebar_data + | result = await db.execute(text(""" + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py", line 461, in execute + | result = await greenlet_spawn( + | ^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 201, in greenlet_spawn + | result = context.throw(*sys.exc_info()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 2362, in execute + | return self._execute_internal( + | ^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 2256, in _execute_internal + | result = conn.execute( + | ^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1418, in execute + | return meth( + | ^^^^^ + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py", line 515, in _execute_on_connection + | return connection._execute_clauseelement( + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1640, in _execute_clauseelement + | ret = self._execute_context( + | ^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1846, in _execute_context + | return self._exec_single_context( + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1986, in _exec_single_context + | self._handle_dbapi_exception( + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 2358, in _handle_dbapi_exception + | raise exc_info[1].with_traceback(exc_info[2]) + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context + | self.dialect.do_execute( + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 941, in do_execute + | cursor.execute(statement, parameters) + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 568, in execute + | self._adapt_connection.await_( + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 132, in await_only + | return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 196, in greenlet_spawn + | value = await result + | ^^^^^^^^^^^^ + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 504, in _prepare_and_execute + | await adapt_connection._start_transaction() + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 833, in _start_transaction + | self._handle_exception(error) + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 782, in _handle_exception + | raise error + | File "/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 831, in _start_transaction + | await self._transaction.start() + | File "/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py", line 146, in start + | await self._connection.execute(query) + | File "/usr/local/lib/python3.12/site-packages/asyncpg/connection.py", line 349, in execute + | result = await self._protocol.query(query, timeout) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | File "asyncpg/protocol/protocol.pyx", line 375, in query + | RuntimeError: Task .call_next..coro() running at /usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149> cb=[TaskGroup._spawn..task_done() at /usr/local/lib/python3.12/site-packages/anyio/_backends/_asyncio.py:805]> got Future attached to a different loop + +------------------------------------ + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "/app/tests/test_smoke_dynamic.py", line 49, in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 1768, in get + return await self.request( + ^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 1540, in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 1629, in send + response = await self._send_handling_auth( + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 1657, in _send_handling_auth + response = await self._send_handling_redirects( + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 1694, in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 1730, in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py", line 170, in handle_async_request + await self.app(scope, receive, send) + File "/usr/local/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__ + await super().__call__(scope, receive, send) + File "/usr/local/lib/python3.12/site-packages/starlette/applications.py", line 113, in __call__ + await self.middleware_stack(scope, receive, send) + File "/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 187, in __call__ + raise exc + File "/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 165, in __call__ + await self.app(scope, receive, _send) + File "/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py", line 185, in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/contextlib.py", line 158, in __exit__ + self.gen.throw(value) + File "/usr/local/lib/python3.12/site-packages/starlette/_utils.py", line 82, in collapse_excgroups + raise exc + File "/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py", line 187, in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/app/main.py", line 79, in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py", line 163, in call_next + raise app_exc + File "/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py", line 149, in coro + await self.app(scope, receive_or_disconnect, send_no_error) + File "/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) + File "/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app + raise exc + File "/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app + await app(scope, receive, sender) + File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 715, in __call__ + await self.middleware_stack(scope, receive, send) + File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 735, in app + await route.handle(scope, receive, send) + File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 288, in handle + await self.app(scope, receive, send) + File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 76, in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) + File "/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app + raise exc + File "/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app + await app(scope, receive, sender) + File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 73, in app + response = await f(request) + ^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/fastapi/routing.py", line 301, in app + raw_response = await run_endpoint_function( + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/fastapi/routing.py", line 212, in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/app/routers/domains.py", line 20, in list_domains + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/app/core/sidebar.py", line 14, in get_sidebar_data + result = await db.execute(text(""" + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py", line 461, in execute + result = await greenlet_spawn( + ^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 201, in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 2362, in execute + return self._execute_internal( + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 2256, in _execute_internal + result = conn.execute( + ^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1418, in execute + return meth( + ^^^^^ + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py", line 515, in _execute_on_connection + return connection._execute_clauseelement( + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1640, in _execute_clauseelement + ret = self._execute_context( + ^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1846, in _execute_context + return self._exec_single_context( + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1986, in _exec_single_context + self._handle_dbapi_exception( + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 2358, in _handle_dbapi_exception + raise exc_info[1].with_traceback(exc_info[2]) + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context + self.dialect.do_execute( + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 941, in do_execute + cursor.execute(statement, parameters) + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 568, in execute + self._adapt_connection.await_( + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 132, in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 196, in greenlet_spawn + value = await result + ^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 504, in _prepare_and_execute + await adapt_connection._start_transaction() + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 833, in _start_transaction + self._handle_exception(error) + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 782, in _handle_exception + raise error + File "/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 831, in _start_transaction + await self._transaction.start() + File "/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py", line 146, in start + await self._connection.execute(query) + File "/usr/local/lib/python3.12/site-packages/asyncpg/connection.py", line 349, in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "asyncpg/protocol/protocol.pyx", line 375, in query +RuntimeError: Task .call_next..coro() running at /usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149> cb=[TaskGroup._spawn..task_done() at /usr/local/lib/python3.12/site-packages/anyio/_backends/_asyncio.py:805]> got Future attached to a different loop + +During handling of the above exception, another exception occurred: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/domains.py:20: in list_domains + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2358: in _handle_dbapi_exception + raise exc_info[1].with_traceback(exc_info[2]) +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:782: in _handle_exception + raise error +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:375: in query + ??? +E RuntimeError: Task .call_next..coro() running at /usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149> cb=[TaskGroup._spawn..task_done() at /usr/local/lib/python3.12/site-packages/anyio/_backends/_asyncio.py:805]> got Future attached to a different loop +_____________ test_get_no_params_returns_200[GET /domains/create] ______________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/domains.py:30: in create_form + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_________________ test_get_no_params_returns_200[GET /areas/] __________________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/areas.py:25: in list_areas + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +______________ test_get_no_params_returns_200[GET /areas/create] _______________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/areas.py:58: in create_form + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +________________ test_get_no_params_returns_200[GET /projects/] ________________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/projects.py:25: in list_projects + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_____________ test_get_no_params_returns_200[GET /projects/create] _____________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/projects.py:78: in create_form + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_________________ test_get_no_params_returns_200[GET /tasks/] __________________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/tasks.py:39: in list_tasks + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +______________ test_get_no_params_returns_200[GET /tasks/create] _______________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/tasks.py:119: in create_form + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_________________ test_get_no_params_returns_200[GET /notes/] __________________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/notes.py:25: in list_notes + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +______________ test_get_no_params_returns_200[GET /notes/create] _______________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/notes.py:66: in create_form + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_________________ test_get_no_params_returns_200[GET /links/] __________________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/links.py:20: in list_links + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +______________ test_get_no_params_returns_200[GET /links/create] _______________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/links.py:49: in create_form + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_________________ test_get_no_params_returns_200[GET /focus/] __________________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/focus.py:21: in focus_view + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +________________ test_get_no_params_returns_200[GET /capture/] _________________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/capture.py:20: in list_capture + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +________________ test_get_no_params_returns_200[GET /contacts/] ________________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/contacts.py:20: in list_contacts + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_____________ test_get_no_params_returns_200[GET /contacts/create] _____________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/contacts.py:34: in create_form + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_______________ test_get_no_params_returns_200[GET /search/api] ________________ +tests/test_smoke_dynamic.py:50: in test_get_no_params_returns_200 + assert r.status_code == 200, f"GET {path} returned {r.status_code}" +E AssertionError: GET /search/api returned 422 +E assert 422 == 200 +E + where 422 = .status_code +_________________ test_get_no_params_returns_200[GET /search/] _________________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/search.py:220: in search_page + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +______________ test_get_no_params_returns_200[GET /admin/trash/] _______________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/admin.py:44: in trash_view + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_________________ test_get_no_params_returns_200[GET /lists/] __________________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/lists.py:26: in list_lists + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +______________ test_get_no_params_returns_200[GET /lists/create] _______________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/lists.py:75: in create_form + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_________________ test_get_no_params_returns_200[GET /files/] __________________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/files.py:40: in list_files + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +______________ test_get_no_params_returns_200[GET /files/upload] _______________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/files.py:77: in upload_form + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +________________ test_get_no_params_returns_200[GET /meetings/] ________________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/meetings.py:25: in list_meetings + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_____________ test_get_no_params_returns_200[GET /meetings/create] _____________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/meetings.py:55: in create_form + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_______________ test_get_no_params_returns_200[GET /decisions/] ________________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/decisions.py:25: in list_decisions + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +____________ test_get_no_params_returns_200[GET /decisions/create] _____________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/decisions.py:61: in create_form + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +________________ test_get_no_params_returns_200[GET /weblinks/] ________________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/weblinks.py:24: in list_weblinks + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_____________ test_get_no_params_returns_200[GET /weblinks/create] _____________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/weblinks.py:83: in create_form + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +_________ test_get_no_params_returns_200[GET /weblinks/folders/create] _________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/weblinks.py:200: in create_folder_form + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +______________ test_get_no_params_returns_200[GET /appointments/] ______________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/appointments.py:26: in list_appointments + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +____________ test_get_no_params_returns_200[GET /appointments/new] _____________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/appointments.py:84: in new_appointment + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +__________________ test_get_no_params_returns_200[GET /time/] __________________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/time_tracking.py:43: in time_log + sidebar = await get_sidebar_data(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +core/sidebar.py:14: in get_sidebar_data + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT id, name, color FROM domains +E WHERE is_deleted = false ORDER BY sort_order, name +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +______________ test_get_no_params_returns_200[GET /time/running] _______________ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:831: in _start_transaction + await self._transaction.start() +/usr/local/lib/python3.12/site-packages/asyncpg/transaction.py:146: in start + await self._connection.execute(query) +/usr/local/lib/python3.12/site-packages/asyncpg/connection.py:349: in execute + result = await self._protocol.query(query, timeout) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +asyncpg/protocol/protocol.pyx:360: in query + ??? +asyncpg/protocol/protocol.pyx:745: in asyncpg.protocol.protocol.BaseProtocol._check_state + ??? +E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: : cannot perform operation: another operation is in progress + +The above exception was the direct cause of the following exception: +tests/test_smoke_dynamic.py:49: in test_get_no_params_returns_200 + r = await client.get(path) + ^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1768: in get + return await self.request( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1540: in request + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1629: in send + response = await self._send_handling_auth( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1657: in _send_handling_auth + response = await self._send_handling_redirects( +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1694: in _send_handling_redirects + response = await self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_client.py:1730: in _send_single_request + response = await transport.handle_async_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/httpx/_transports/asgi.py:170: in handle_async_request + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/fastapi/applications.py:1054: in __call__ + await super().__call__(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/applications.py:113: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:187: in __call__ + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py:165: in __call__ + await self.app(scope, receive, _send) +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:185: in __call__ + with collapse_excgroups(): + ^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/contextlib.py:158: in __exit__ + self.gen.throw(value) +/usr/local/lib/python3.12/site-packages/starlette/_utils.py:82: in collapse_excgroups + raise exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:187: in __call__ + response = await self.dispatch_func(request, call_next) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +main.py:79: in add_request_context + response = await call_next(request) + ^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:163: in call_next + raise app_exc +/usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149: in coro + await self.app(scope, receive_or_disconnect, send_no_error) +/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py:62: in __call__ + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:715: in __call__ + await self.middleware_stack(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:735: in app + await route.handle(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:288: in handle + await self.app(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:76: in app + await wrap_app_handling_exceptions(app, request)(scope, receive, send) +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:53: in wrapped_app + raise exc +/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py:42: in wrapped_app + await app(scope, receive, sender) +/usr/local/lib/python3.12/site-packages/starlette/routing.py:73: in app + response = await f(request) + ^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:301: in app + raw_response = await run_endpoint_function( +/usr/local/lib/python3.12/site-packages/fastapi/routing.py:212: in run_endpoint_function + return await dependant.call(**values) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/time_tracking.py:157: in running_timer_api + running = await get_running_timer(db) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +routers/time_tracking.py:20: in get_running_timer + result = await db.execute(text(""" +/usr/local/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py:461: in execute + result = await greenlet_spawn( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:201: in greenlet_spawn + result = context.throw(*sys.exc_info()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2362: in execute + return self._execute_internal( +/usr/local/lib/python3.12/site-packages/sqlalchemy/orm/session.py:2256: in _execute_internal + result = conn.execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1418: in execute + return meth( +/usr/local/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:515: in _execute_on_connection + return connection._execute_clauseelement( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1640: in _execute_clauseelement + ret = self._execute_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846: in _execute_context + return self._exec_single_context( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986: in _exec_single_context + self._handle_dbapi_exception( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2355: in _handle_dbapi_exception + raise sqlalchemy_exception.with_traceback(exc_info[2]) from e +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967: in _exec_single_context + self.dialect.do_execute( +/usr/local/lib/python3.12/site-packages/sqlalchemy/engine/default.py:941: in do_execute + cursor.execute(statement, parameters) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:568: in execute + self._adapt_connection.await_( +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:132: in await_only + return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py:196: in greenlet_spawn + value = await result + ^^^^^^^^^^^^ +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:504: in _prepare_and_execute + await adapt_connection._start_transaction() +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:833: in _start_transaction + self._handle_exception(error) +/usr/local/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:780: in _handle_exception + raise translated_error from error +E sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +E [SQL: +E SELECT te.*, t.title as task_title, t.id as task_id, +E p.name as project_name, d.name as domain_name +E FROM time_entries te +E JOIN tasks t ON te.task_id = t.id +E LEFT JOIN projects p ON t.project_id = p.id +E LEFT JOIN domains d ON t.domain_id = d.id +E WHERE te.end_at IS NULL AND te.is_deleted = false +E ORDER BY te.start_at DESC +E LIMIT 1 +E ] +E (Background on this error at: https://sqlalche.me/e/20/rvf5) +=============================== warnings summary =============================== +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /] + /usr/local/lib/python3.12/site-packages/starlette/templating.py:161: DeprecationWarning: The `name` is not the first parameter anymore. The first parameter should be the `Request` instance. + Replace `TemplateResponse(name, {"request": request})` by `TemplateResponse(request, name)`. + warnings.warn( + +tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /health] + /usr/local/lib/python3.12/site-packages/_pytest/stash.py:108: RuntimeWarning: coroutine 'Connection._cancel' was never awaited + del self._storage[key] + Enable tracemalloc to get traceback where the object was allocated. + See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info. + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +=========================== short test summary info ============================ +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /domains/] - RuntimeError: Task .call_next..coro() running at /usr/local/lib/python3.12/site-packages/starlette/middleware/base.py:149> cb=[TaskGroup._spawn..task_done() at /usr/local/lib/python3.12/site-packages/anyio/_backends/_asyncio.py:805]> got Future attached to a different loop +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /domains/create] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /areas/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /areas/create] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /projects/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /projects/create] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /tasks/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /tasks/create] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /notes/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /notes/create] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /links/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /links/create] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /focus/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /capture/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /contacts/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /contacts/create] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /search/api] - AssertionError: GET /search/api returned 422 +assert 422 == 200 + + where 422 = .status_code +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /search/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /admin/trash/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /lists/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /lists/create] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /files/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /files/upload] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /meetings/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /meetings/create] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /decisions/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /decisions/create] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /weblinks/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /weblinks/create] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /weblinks/folders/create] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /appointments/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /appointments/new] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /time/] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT id, name, color FROM domains + WHERE is_deleted = false ORDER BY sort_order, name + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +FAILED tests/test_smoke_dynamic.py::test_get_no_params_returns_200[GET /time/running] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: + SELECT te.*, t.title as task_title, t.id as task_id, + p.name as project_name, d.name as domain_name + FROM time_entries te + JOIN tasks t ON te.task_id = t.id + LEFT JOIN projects p ON t.project_id = p.id + LEFT JOIN domains d ON t.domain_id = d.id + WHERE te.end_at IS NULL AND te.is_deleted = false + ORDER BY te.start_at DESC + LIMIT 1 + ] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /domains/{domain_id}/edit] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('78c75285-a5c9-4a18-9a06-adccbce3a022', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /areas/{area_id}/edit] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('1b388db7-0e79-43e5-a129-eeba449d1049', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /projects/{project_id}] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('b7be8530-ae2a-4c0b-b3c7-5b636a6fd9c2', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /projects/{project_id}/edit] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('677c81b0-1d4d-4ea0-a9ac-c680f4f00f6d', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /tasks/{task_id}] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('62f7c7b9-c3bc-469c-8232-67781f3e69d0', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /tasks/{task_id}/edit] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('bda30a3c-3381-4c0a-9210-5c645692b2b9', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /notes/{note_id}] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('61496ec7-6f6a-42e7-a03c-570e235284a5', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /notes/{note_id}/edit] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('6366c968-21b0-4a30-a6fe-4d8b3a2a4706', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /links/{link_id}/edit] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('0706dc19-3727-4398-8729-3e5127fc54c4', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /contacts/{contact_id}] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('e388bc10-d24c-4149-803f-f17b4390da7d', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /contacts/{contact_id}/edit] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('30714950-55d2-4024-ad63-a60ec4a4d88b', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /lists/{list_id}] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('1cdb10cd-38ff-4355-a611-1c1183d68ec9', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /lists/{list_id}/edit] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('52744af6-49ac-483f-9e00-72cb9a067927', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /files/{file_id}/download] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('c6dd208e-0400-4601-8493-75b92c0d12f9', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /files/{file_id}/preview] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('0a79dd35-f660-464d-83c8-61e5f8daba30', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /files/{file_id}/serve] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('c3b90d81-6b46-4ecc-ae47-a8c32150d921', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /meetings/{meeting_id}] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('987863e1-fff0-428c-8506-e5dbc6e59e2c', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /meetings/{meeting_id}/edit] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('2a4914fb-b7e9-4223-b267-372dd4ed970d', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /decisions/{decision_id}] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('51a51449-b25c-4805-aaab-34ea9841e3a4', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /decisions/{decision_id}/edit] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('7d9b9b6e-c78a-4309-b393-d178f6c85385', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /weblinks/{weblink_id}/edit] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('6e21f2a4-d200-425f-b8d6-375f1eabe62b', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /appointments/{appointment_id}] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('f1f5f8ea-a0d2-4c64-af3d-8876938a273c', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +ERROR tests/test_smoke_dynamic.py::test_get_with_valid_id_returns_200[GET /appointments/{appointment_id}/edit] - sqlalchemy.exc.InterfaceError: (sqlalchemy.dialects.postgresql.asyncpg.InterfaceError) : cannot perform operation: another operation is in progress +[SQL: INSERT INTO domains (id, name, color, description, sort_order, is_deleted, created_at, updated_at) VALUES ($1, $2, $3, $4, 0, false, now(), now())] +[parameters: ('3ce7a5d5-7e97-40e9-8c80-88aa53469842', 'Test Domain', '#FF5733', 'Auto test domain')] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +======= 34 failed, 2 passed, 1 skipped, 2 warnings, 23 errors in 21.30s ======== +root@defiant-01:/opt/lifeos/dev# docker restart lifeos-dev \ No newline at end of file diff --git a/project-docs/life-os-server-config.docx b/project-docs/life-os-server-config.docx new file mode 100644 index 0000000..a1891a7 --- /dev/null +++ b/project-docs/life-os-server-config.docx @@ -0,0 +1,349 @@ +**Life OS** + +Server & Infrastructure Configuration + +**1. Server Overview** + + ----------------------------------------------------------------------- + **Property** **Value** + ---------------------- ------------------------------------------------ + Provider Hetzner Cloud + + Server Name defiant-01 + + Public IP 46.225.166.142 + + IPv6 2a01:4f8:1c1f:9d94::1 + + OS Ubuntu 24.04.4 LTS (Noble Numbat) + + Kernel Linux 6.8.0-90-generic x86_64 + + CPU Cores 12 + + RAM 22 GB + + Disk 451 GB total / \~395 GB available + + Swap 8 GB + ----------------------------------------------------------------------- + +**1.1 Installed Software** + + ----------------------------------------------------------------------- + **Software** **Version** **Notes** + ------------------ --------------- ------------------------------------ + Ubuntu 24.04.4 LTS Base OS + + Python 3.12.3 Host-level, available system-wide + + Nginx 1.24.0 Host-level reverse proxy, not + containerized + + Docker Active Managing all application containers + + PostgreSQL (host) Not installed Postgres runs in Docker containers + only + ----------------------------------------------------------------------- + +**1.2 Hetzner Cloud Firewall** + +Firewall name: firewall-1 + + ------------------------------------------------------------------------------ + **Protocol** **Port** **Source** **Purpose** + -------------- ---------- ------------------ --------------------------------- + TCP 22 0.0.0.0/0 SSH access + + TCP 80 0.0.0.0/0 HTTP (redirects to HTTPS via + Nginx) + + TCP 443 0.0.0.0/0 HTTPS + + TCP 8443 0.0.0.0/0 Kasm Workspaces (internal, set + during setup) + ------------------------------------------------------------------------------ + +*Note: UFW is inactive on the host. Docker manages iptables rules +directly for container port exposure. No host-level firewall changes are +needed for new services - Nginx proxies all traffic on 80/443.* + +**2. DNS Records** + +Domain registrar / DNS provider: managed by Michael + +Primary domain: invixiom.com + +**2.1 Active DNS Records** + + ----------------------------------------------------------------------------------------------- + **Subdomain** **Type** **Value** **Purpose** **Status** + ----------------------------- ---------- ---------------- ---------------------- -------------- + **kasm.invixiom.com** A 46.225.166.142 Kasm Workspaces **ACTIVE** + virtual desktop + + **files.invixiom.com** A 46.225.166.142 Nextcloud file storage **ACTIVE** + + **lifeos.invixiom.com** A 46.225.166.142 Life OS PROD **PENDING** + application + + **lifeos-dev.invixiom.com** A 46.225.166.142 Life OS DEV **PENDING** + application + + **code.invixiom.com** A 46.225.166.142 Reserved - future use **RESERVED** + ----------------------------------------------------------------------------------------------- + +*Note: PENDING means DNS record exists but the Nginx config and +application container are not yet deployed. ACTIVE means fully +configured end-to-end.* + +**3. Nginx Configuration** + +Nginx runs directly on the host (not in Docker). Config files located at +/etc/nginx/sites-available/. The active config is invixiom (symlinked to +sites-enabled). + +**3.1 SSL Certificates** + + ---------------------------------------------------------------------------------------------------------- + **Certificate** **Path** **Covers** **Provider** + ----------------- ------------------------------------------------------- ----------------- -------------- + Primary cert /etc/letsencrypt/live/kasm.invixiom.com/fullchain.pem All active Let\'s Encrypt + subdomains + (wildcard or SAN) + + Primary key /etc/letsencrypt/live/kasm.invixiom.com/privkey.pem All active Let\'s Encrypt + subdomains + + Legacy cert /etc/nginx/ssl/invixiom.crt Old config only Self-signed or + (kasm manual + site-available) + ---------------------------------------------------------------------------------------------------------- + +*Note: The Let\'s Encrypt cert path uses kasm.invixiom.com as the +primary name. When lifeos.invixiom.com and lifeos-dev.invixiom.com are +added to Nginx, the cert will need to be renewed/expanded to cover the +new subdomains.* + +**3.2 Configured Virtual Hosts** + + ------------------------------------------------------------------------------------- + **Server Name** **Listens **Proxies To** **Notes** + On** + ------------------------- ----------- ------------------------ ---------------------- + kasm.invixiom.com 443 ssl https://127.0.0.1:8443 WebSocket support, + ssl_verify off, 30min + timeout + + files.invixiom.com 443 ssl http://127.0.0.1:8080 Nextcloud container + + lifeos-api.invixiom.com 443 ssl http://127.0.0.1:8000 LEGACY - maps to stub + container, to be + replaced + + code.invixiom.com 443 ssl http://127.0.0.1:8081 Nothing running on + 8081 yet + + lifeos.invixiom.com 443 ssl http://127.0.0.1:8002 TO BE ADDED - Life OS + PROD + + lifeos-dev.invixiom.com 443 ssl http://127.0.0.1:8003 TO BE ADDED - Life OS + DEV + ------------------------------------------------------------------------------------- + +**4. Docker Containers** + +**4.1 Currently Running Containers** + + ------------------------------------------------------------------------------------------------------- + **Container Name** **Image** **Ports** **Purpose** **Touch?** + ------------------------ --------------------------- ------------- ---------------------- ------------- + fastapi stack-fastapi 8000-\>8000 Stub health check **REPLACE** + only - to be replaced + by Life OS PROD + + nextcloud nextcloud:27-apache 8080-\>80 Nextcloud file storage **DO NOT + (files.invixiom.com) TOUCH** + + redis redis:7-alpine internal Task queue for **DO NOT + existing stack TOUCH** + + kasm_proxy kasmweb/proxy:1.18.0 8443-\>8443 Kasm entry point **DO NOT + (kasm.invixiom.com) TOUCH** + + kasm_rdp_https_gateway kasmweb/rdp-https-gateway internal Kasm RDP gateway **DO NOT + TOUCH** + + kasm_rdp_gateway kasmweb/rdp-gateway 3389-\>3389 Kasm RDP **DO NOT + TOUCH** + + kasm_agent kasmweb/agent:1.18.0 internal Kasm agent **DO NOT + TOUCH** + + kasm_guac kasmweb/kasm-guac internal Kasm Guacamole **DO NOT + TOUCH** + + kasm_api kasmweb/api:1.18.0 internal Kasm API **DO NOT + TOUCH** + + kasm_manager kasmweb/manager:1.18.0 internal Kasm manager **DO NOT + TOUCH** + + kasm_db kasmweb/postgres:1.18.0 internal Kasm dedicated **DO NOT + Postgres TOUCH** + + celery stack-celery internal Celery worker for **DO NOT + existing stack TOUCH** + + postgres postgres:16-alpine internal Postgres for existing **DO NOT + stack TOUCH** + ------------------------------------------------------------------------------------------------------- + +**4.2 Planned Life OS Containers** + + ------------------------------------------------------------------------------------------- + **Container **Image** **Port** **Purpose** **Status** + Name** + --------------- -------------------- ------------- --------------------------- ------------ + lifeos-db postgres:16-alpine internal only Dedicated Postgres for Life **ACTIVE** + OS - hosts lifeos_prod and + lifeos_dev databases + + lifeos-prod lifeos-app (custom) 8002-\>8002 Life OS PROD application **TO BE + (lifeos.invixiom.com) CREATED** + + lifeos-dev lifeos-app (custom) 8003-\>8003 Life OS DEV application **TO BE + (lifeos-dev.invixiom.com) CREATED** + ------------------------------------------------------------------------------------------- + +**4.3 Port Allocation** + + ----------------------------------------------------------------------------- + **Port** **Used By** **Direction** **Notes** + ---------- ------------------- --------------- ------------------------------ + 22 SSH External Hetzner firewall open + inbound + + 80 Nginx External HTTP redirect to HTTPS + inbound + + 443 Nginx External HTTPS, all subdomains + inbound + + 3389 kasm_rdp_gateway External Hetzner firewall open + inbound + + 8000 fastapi (stub) Internal To be repurposed or removed + + 8080 nextcloud Internal Proxied via files.invixiom.com + + 8081 code.invixiom.com Internal Reserved, nothing running + + 8443 kasm_proxy External Kasm, Hetzner firewall open + inbound + + 8002 lifeos-prod Internal To be created - proxied via + lifeos.invixiom.com + + 8003 lifeos-dev Internal To be created - proxied via + lifeos-dev.invixiom.com + ----------------------------------------------------------------------------- + +**5. Docker Networks** + + ------------------------------------------------------------------------------------ + **Network Name** **Driver** **Subnet** **Used By** + ---------------------- ----------------- --------------- --------------------------- + bridge bridge 172.17.0.0/16 Default Docker bridge + + kasm_default_network bridge 172.19.0.0/16 All Kasm containers + + kasm_sidecar_network kasmweb/sidecar 172.20.0.0/16 Kasm sidecar + + stack_web bridge 172.18.0.0/16 fastapi, celery, redis, + postgres containers + + lifeos_network bridge 172.21.0.0/16 ACTIVE - lifeos-prod, + lifeos-dev, lifeos-db + ------------------------------------------------------------------------------------ + +**6. Application Directories** + +All Life OS application files live under /opt/lifeos on the host, +mounted into containers as volumes. + + -------------------------------------------------------------------------- + **Path** **Purpose** **Status** + ----------------------------- --------------------------- ---------------- + /opt/lifeos/lifeos-setup.sh Infrastructure setup script **ACTIVE** + + /opt/lifeos/prod PROD application files and **ACTIVE** + config + + /opt/lifeos/prod/files PROD user uploaded files **ACTIVE** + storage + + /opt/lifeos/dev DEV application files and **ACTIVE** + config + + /opt/lifeos/dev/files DEV user uploaded files **ACTIVE** + storage + + lifeos_db_data (Docker Postgres data persistence **ACTIVE** + volume) + -------------------------------------------------------------------------- + +**7. Pending Configuration Tasks** + +The following items are in sequence order and must be completed to +finish the infrastructure setup: + + -------------------------------------------------------------------------------------------- + **\#** **Task** **Status** **Notes** + -------- ------------------------------ -------------- ------------------------------------- + 1 Verify DNS propagation for **COMPLETE** Verified 2026-02-27 + lifeos.invixiom.com and + lifeos-dev.invixiom.com + + 2 Create Docker network: **PENDING** + lifeos_network + + 3 Create lifeos-db Postgres **COMPLETE** Container: lifeos-db, image: + container postgres:16-alpine + + 4 Create lifeos_prod and **COMPLETE** lifeos_dev user created with separate + lifeos_dev databases inside password + lifeos-db + + 5 Create application directory **COMPLETE** /opt/lifeos/prod, /opt/lifeos/dev, + structure on host file storage dirs + + 6 Migrate existing Supabase **COMPLETE** 3 domains, 10 areas, 18 projects, 73 + production data to lifeos_prod tasks, 5 links, 5 daily_focus, 80 + capture, 6 context_types. Files table + empty - Supabase Storage paths + obsolete, files start fresh in R1. + + 7 Build Life OS Docker image **PENDING** FastAPI app, Python 3.12 + (Dockerfile) + + 8 Create docker-compose.yml for **PENDING** PROD and DEV services + Life OS stack + + 9 Add lifeos.invixiom.com and **PENDING** New server blocks in + lifeos-dev.invixiom.com to /etc/nginx/sites-available/invixiom + Nginx config + + 10 Expand SSL cert to cover new **PENDING** Add lifeos.invixiom.com and + subdomains (certbot \--expand) lifeos-dev.invixiom.com to cert + + 11 Remove or retire stub fastapi **PENDING** After Life OS PROD is live + container on port 8000 + + 12 Test end-to-end: HTTPS access **PENDING** + to lifeos.invixiom.com and + lifeos-dev.invixiom.com + -------------------------------------------------------------------------------------------- + +Life OS Server & Infrastructure Configuration \| Last updated: +2026-02-27 diff --git a/project-docs/lifeos-architecture.docx b/project-docs/lifeos-architecture.docx new file mode 100644 index 0000000..5dbb9c2 --- /dev/null +++ b/project-docs/lifeos-architecture.docx @@ -0,0 +1,3425 @@ +**LIFE OS** + +Architecture Design Document + +Complete System Specification --- All Layers + + -------------------- ---------------------------------------------------- + **Document Type** Final Architecture Design + + **Version** 2.0 --- February 2026 + + **Status** Approved for Build + + **Author** M. Dombaugh + + **Server** defiant-01 46.225.166.142 + + **Production URL** lifeos.invixiom.com + + **Dev URL** lifeos-dev.invixiom.com + + **Repository** github.com/mdombaugh/life-os + + **Backend** Python 3.12 / FastAPI / SQLAlchemy + + **Database** PostgreSQL 16 + + **Infrastructure** Docker / Nginx / Let\'s Encrypt + + **Phases** Phase 1 (build) / Phase 2 (AI) / Phase 3 (polish) + -------------------- ---------------------------------------------------- + + ----------------------------------------------------------------------- + **Table of Contents** + + ----------------------------------------------------------------------- + + -------- --------------------------------------------------------- ------- + **1.** Vision and Goals 3 + + -------- --------------------------------------------------------- ------- + + -------- --------------------------------------------------------- ------- + **2.** Functional Requirements 4 + + -------- --------------------------------------------------------- ------- + + -------- --------------------------------------------------------- ------- + **3.** Non-Functional Requirements 6 + + -------- --------------------------------------------------------- ------- + + -------- --------------------------------------------------------- ------- + **4.** System Architecture Overview 7 + + -------- --------------------------------------------------------- ------- + + -------- --------------------------------------------------------- ------- + **5.** Subsystems and Capabilities 9 + + -------- --------------------------------------------------------- ------- + + -------- --------------------------------------------------------- ------- + **6.** Data Architecture 12 + + -------- --------------------------------------------------------- ------- + + -------- --------------------------------------------------------- ------- + **7.** Application Layer Architecture 22 + + -------- --------------------------------------------------------- ------- + + -------- --------------------------------------------------------- ------- + **8.** Generic Code Architecture 25 + + -------- --------------------------------------------------------- ------- + + -------- --------------------------------------------------------- ------- + **9.** Frontend Architecture 27 + + -------- --------------------------------------------------------- ------- + + --------- --------------------------------------------------------- ------- + **10.** Infrastructure Architecture 30 + + --------- --------------------------------------------------------- ------- + + --------- --------------------------------------------------------- ------- + **11.** Search Architecture 33 + + --------- --------------------------------------------------------- ------- + + --------- --------------------------------------------------------- ------- + **12.** Time Management Architecture 34 + + --------- --------------------------------------------------------- ------- + + --------- --------------------------------------------------------- ------- + **13.** AI and MCP Architecture 36 + + --------- --------------------------------------------------------- ------- + + --------- --------------------------------------------------------- ------- + **14.** Security Architecture 38 + + --------- --------------------------------------------------------- ------- + + --------- --------------------------------------------------------- ------- + **15.** Phase Build Plan 39 + + --------- --------------------------------------------------------- ------- + + --------- --------------------------------------------------------- ------- + **16.** Migration Plan 42 + + --------- --------------------------------------------------------- ------- + + --------- --------------------------------------------------------- ------- + **17.** Appendix: Table Inventory 43 + + --------- --------------------------------------------------------- ------- + + ----------------------------------------------------------------------- + **1. Vision and Goals** + + ----------------------------------------------------------------------- + +**1.1 Vision Statement** + +Life OS is a personal productivity platform that unifies every aspect of +professional and personal work into a single, structured system. It +eliminates context-switching between disconnected tools by providing a +single source of truth for tasks, projects, knowledge, decisions, +relationships, meetings, processes, time, and releases. The system is +designed to grow with the user\'s workload without becoming unwieldy, +through consistent hierarchical organization, powerful search, and AI +assistance. + +**1.2 Problem Statement** + +- Too many disconnected tools: tasks in one place, notes in another, + contacts in a CRM, meetings in a calendar, decisions nowhere. + Context is lost between tools. + +- Too much to do, too little time: no visibility into total committed + work versus available capacity. Overcommitment is invisible until it + becomes a crisis. + +- Knowledge dispersal: decisions, rationale, and meeting outcomes are + not captured systematically. Institutional knowledge is lost or hard + to find. + +- No process memory: recurring work is redone from scratch each time + instead of being captured as a reusable, improvable process. + +- Reactive instead of proactive: without a structured daily focus and + time budget system, urgent work crowds out important work. + +**1.3 Strategic Goals** + + ---------------- ------------------------------------------------------ + **G1 - Single One system handles tasks, notes, knowledge, contacts, + hub** meetings, decisions, processes, releases, and time. No + external tool required for core productivity. + + **G2 - Hierarchy Everything has a clear home in the Domain \> Area \> + clarity** Project hierarchy. Navigation is always obvious. + + **G3 - Time The system surfaces overcommitment before it happens, + sovereignty** not after. Time estimates, budgets, and tracking are + first-class. + + **G4 - Knowledge Every significant decision, meeting outcome, and + capture** process is documented and findable. Organizational + knowledge accumulates over time. + + **G5 - AI The system is designed for AI interaction from day + leverage** one. Any capable AI model can read, create, and update + any entity via the MCP interface. + + **G6 - The architecture uses portable, standard technologies + Longevity** with no vendor lock-in. The system should still be + running and maintainable in 10 years. + + **G7 - Speed** Common actions (capture, task create, status update, + search) require the minimum possible steps. Friction + is the enemy of adoption. + + **G8 - Single-user system. Uptime and data safety matter more + Reliability** than scale. Logical deletes protect all data. Backups + are automated. + ---------------- ------------------------------------------------------ + +**1.4 Design Principles** + +- Hierarchy first. Everything belongs to a Domain. Areas and Projects + are optional groupings. + +- KISS. Simple solutions chosen wherever functionality is equivalent. + Complexity must earn its place. + +- Consistent patterns. Every list, form, and detail view follows + identical structural conventions. Learn once, apply everywhere. + +- Logical deletes everywhere. No data is permanently destroyed without + explicit admin action. + +- Context travels with navigation. Drill-down pre-fills context into + all create actions. + +- Search is first-class. Global search covers every entity from day + one. + +- Generic over specific. Shared base code handles common operations. + Entity-specific code handles only genuinely unique business logic. + +- Config-driven where possible. Menu structure, simple entities, and + form layouts are configuration - not code. + + ----------------------------------------------------------------------- + **2. Functional Requirements** + + ----------------------------------------------------------------------- + +*Priority: Must = required for Phase 1. Should = high value, Phase 1 if +possible. Could = Phase 2/3.* + + ----------------------------------------------------------------------- + **2.1 Core Hierarchy** + + ----------------------------------------------------------------------- + + ------------ --------------------------------------------- -------------- ----------- + **ID** **Requirement** **Priority** **Phase** + + **FR-001** System shall support four-level hierarchy: **Must** Phase 1 + Domain \> Area \> Project \> Tasks/Content + + **FR-002** Content items (Tasks, Notes, Lists, Links, **Must** Phase 1 + Files) shall attach at Domain, Area, or + Project level + + **FR-003** All hierarchy items shall support soft delete **Must** Phase 1 + with recovery via Admin \> Trash + + **FR-004** All list views shall support filter, sort, **Must** Phase 1 + search, and drag-to-reorder + + **FR-005** Sidebar shall support status filtering, text **Must** Phase 1 + search, and smart auto-collapse + + **FR-006** Breadcrumb navigation shall appear on all **Must** Phase 1 + detail views + ------------ --------------------------------------------- -------------- ----------- + + ----------------------------------------------------------------------- + **2.2 Task Management** + + ----------------------------------------------------------------------- + + ------------ --------------------------------------------- -------------- ----------- + **ID** **Requirement** **Priority** **Phase** + + **FR-010** Tasks shall support priority (1-4), status, **Must** Phase 1 + context, tags, due date, deadline, + recurrence, estimate, energy level + + **FR-011** Tasks shall support subtasks via parent_id **Must** Phase 1 + self-reference + + **FR-012** Tasks shall support dependencies with full **Must** Phase 1 + DAG (FS, FF, SS; SF via Admin) + + **FR-013** Dependency cycle detection shall run on **Must** Phase 1 + creation and reject circular dependencies + + **FR-014** Status cascade shall automatically update **Must** Phase 1 + dependent task statuses on blocker completion + + **FR-015** Task list shall display in compact density **Must** Phase 1 + (one row per task, all metadata inline) + + **FR-016** Bulk actions shall be available: mark done, **Must** Phase 1 + move, delete, add to focus + + **FR-017** Quick add inline input shall appear at top of **Must** Phase 1 + every task list + + **FR-018** Waiting for / delegated field shall link task **Must** Phase 1 + to a Contact with auto follow-up reminder + + **FR-019** Task templates shall allow reusable **Must** Phase 1 + blueprints with subtask checklists + + **FR-020** Overdue tasks shall have distinct visual **Must** Phase 1 + treatment (red date + left border) + ------------ --------------------------------------------- -------------- ----------- + + ----------------------------------------------------------------------- + **2.3 Daily Focus and Time Management** + + ----------------------------------------------------------------------- + + ------------ --------------------------------------------- -------------- ----------- + **ID** **Requirement** **Priority** **Phase** + + **FR-030** Daily focus list shall be date-scoped and **Must** Phase 1 + orderable by drag. Position is the priority + signal. + + **FR-031** Time estimates (minutes) shall be settable on **Must** Phase 1 + tasks + + **FR-032** Time tracking shall support start/stop timer **Must** Phase 1 + per task, with running timer visible in + topbar + + **FR-033** Time budgets per domain (weekly hours target) **Must** Phase 1 + shall surface overcommitment on dashboard + + **FR-034** Time blocks shall reserve calendar slots with **Must** Phase 1 + context and energy level + + **FR-035** Eisenhower Matrix view shall derive from **Must** Phase 1 + existing priority and due date data + + **FR-036** Dashboard shall show estimated hours in focus **Should** Phase 1 + vs available time for the day + + **FR-037** Weekly review built-in process template shall **Should** Phase 1 + be provided at first setup + ------------ --------------------------------------------- -------------- ----------- + + ----------------------------------------------------------------------- + **2.4 Knowledge Management** + + ----------------------------------------------------------------------- + + ------------ --------------------------------------------- -------------- ----------- + **ID** **Requirement** **Priority** **Phase** + + **FR-040** Notes shall support rich text with inline **Must** Phase 1 + wiki-style linking via \[\[ syntax + + **FR-041** Notes shall be organizable in recursive **Must** Phase 1 + folders with one folder per note + + **FR-042** Notes shall support M2M project associations **Must** Phase 1 + with is_primary flag + + **FR-043** Meeting notes shall be toggled off by default **Must** Phase 1 + in the Notes view + + **FR-044** Decisions shall be a first-class entity **Must** Phase 1 + linked to projects, contacts, and optionally + meetings + + **FR-045** Decisions shall support superseded_by **Must** Phase 1 + self-reference and status lifecycle + + **FR-046** File preview shall display images and PDFs **Must** Phase 1 + inline without downloading + + **FR-047** Note version history shall record previous **Could** Phase 2 + body states + ------------ --------------------------------------------- -------------- ----------- + + ----------------------------------------------------------------------- + **2.5 Meetings, Contacts, CRM** + + ----------------------------------------------------------------------- + + ------------ --------------------------------------------- -------------- ----------- + **ID** **Requirement** **Priority** **Phase** + + **FR-050** Meetings shall support agenda, transcript, **Must** Phase 1 + rich text notes, action items, attendees, + decisions + + **FR-051** Action items in meetings shall convert to **Must** Phase 1 + tasks with one click, retaining meeting link + + **FR-052** Meeting series shall use parent_id **Must** Phase 1 + self-reference on the meetings table + + **FR-053** Contacts shall associate to tasks, projects, **Must** Phase 1 + lists, appointments, meetings with role field + + **FR-054** Follow-up reminders per contact shall surface **Must** Phase 1 + in dashboard and as sidebar badge + + **FR-055** Pipeline / deal stages for CRM shall be **Could** Phase 2 + supported + ------------ --------------------------------------------- -------------- ----------- + + ----------------------------------------------------------------------- + **2.6 Processes and Releases** + + ----------------------------------------------------------------------- + + ------------ --------------------------------------------- -------------- ----------- + **ID** **Requirement** **Priority** **Phase** + + **FR-060** Processes shall be typed as workflow **Must** Phase 1 + (sequential, enforced) or checklist (any + order) + + **FR-061** Process runs shall copy step content at **Must** Phase 1 + creation. Template changes do not affect + active runs. + + **FR-062** Process runs shall support all_at_once or **Must** Phase 1 + step_by_step task generation modes + + **FR-063** Releases shall be a system-level entity with **Must** Phase 1 + M2M associations to multiple projects + + **FR-064** Tasks shall optionally be tagged to a **Must** Phase 1 + release. Untagged tasks form the project + backlog. + + **FR-065** Milestones shall attach to a release or **Must** Phase 1 + project with a target date and completion + state + + **FR-066** Release detail shall show aggregate progress **Must** Phase 1 + across all associated projects + ------------ --------------------------------------------- -------------- ----------- + + ----------------------------------------------------------------------- + **2.7 Search, Capture, Admin** + + ----------------------------------------------------------------------- + + ------------ --------------------------------------------- -------------- ----------- + **ID** **Requirement** **Priority** **Phase** + + **FR-070** Global search (Cmd/K) shall cover every **Must** Phase 1 + entity with results grouped by type + + **FR-071** Scoped search shall default to current **Must** Phase 1 + project context, expandable to global + + **FR-072** Capture bar shall accept multi-line paste and **Must** Phase 1 + auto-parse into individual items + + **FR-073** Capture items shall be convertible to any **Must** Phase 1 + entity type + + **FR-074** Context-aware capture shall pre-fill **Must** Phase 1 + domain/project when opened within a project + + **FR-075** Admin Trash shall show all soft-deleted items **Must** Phase 1 + with restore and permanent delete + + **FR-076** CSV export shall be available for tasks, **Must** Phase 1 + projects, contacts, decisions + + **FR-077** Personal dashboard metrics widget shall show **Must** Phase 1 + weekly/monthly completion stats + + **FR-078** AI MCP server shall expose all entities to AI **Must** Phase 2 + models via MCP and OpenAI function format + + **FR-079** Browser extension shall capture current page **Could** Phase 2 + as weblink or capture item + ------------ --------------------------------------------- -------------- ----------- + + ----------------------------------------------------------------------- + **3. Non-Functional Requirements** + + ----------------------------------------------------------------------- + + ------------------- ------------------------------------------------------ + **NFR-01 Page load under 500ms for standard views on local + Performance** network. Search results within 300ms. Timer updates in + real time. + + **NFR-02 Target 99.5% uptime. Docker restart policy: always. + Reliability** Automated daily database backup to /opt/lifeos/backups + with 30-day retention. + + **NFR-03 Data Logical deletes on all entities. No data permanently + Safety** destroyed without two-step admin confirmation. + PostgreSQL WAL enabled. + + **NFR-04 No vendor lock-in. Standard PostgreSQL schema. + Portability** Standard Python. File storage on local filesystem. + Migratable to any Linux host. + + **NFR-05 Generic base architecture reduces duplication. + Maintainability** Config-driven entities require zero code for new + simple entities. All routers follow identical + patterns. + + **NFR-06 Security** Single-user, self-hosted. API key authentication for + MCP. Environment variables for all secrets. Never + committed to git. HTTPS enforced. + + **NFR-07 Every common action reachable in 3 clicks or fewer. + Usability** Capture reachable in 1 click from anywhere. Search + reachable via keyboard shortcut always. + + **NFR-08 Mobile** Bottom tab bar navigation. All core views usable on + phone. Swipe actions in Phase 3. + + **NFR-09 Single-user system. No scale requirements. Design + Scalability** supports tens of thousands of records without + degradation via proper indexing. + + **NFR-10 Application logs to stdout, captured by Docker. Error + Observability** logging with stack traces. Nginx access logs retained + 7 days. + ------------------- ------------------------------------------------------ + + ----------------------------------------------------------------------- + **4. System Architecture Overview** + + ----------------------------------------------------------------------- + +**4.1 High-Level Architecture** + ++-----------------------------------------------------------------------+ +| **Architecture Style** | +| | +| Server-rendered monolith with a config-driven generic core. No SPA, | +| no build pipeline, no microservices. Intentionally simple stack | +| chosen for longevity and maintainability. | ++-----------------------------------------------------------------------+ + +> ┌─────────────────────────────────────────────────────────┐ +> +> │ CLIENTS │ +> +> │ Browser (desktop) Browser (mobile) AI Models │ +> +> └────────────┬────────────────┬───────────────┬───────────┘ +> +> │ │ │ +> +> ▼ ▼ ▼ +> +> ┌─────────────────────────────────────────────────────────┐ +> +> │ NGINX (defiant-01) │ +> +> │ SSL termination · routing · static files · rate limit │ +> +> │ lifeos.invixiom.com → lifeos-prod:8002 │ +> +> │ lifeos-dev.invixiom.com → lifeos-dev:8003 │ +> +> │ /ai/\* → lifeos-mcp:8004 \[Phase 2\] │ +> +> └──────────────────────┬──────────────────────────────────┘ +> +> │ +> +> ┌───────────────┼───────────────┐ +> +> ▼ ▼ ▼ +> +> lifeos-prod lifeos-dev lifeos-mcp +> +> FastAPI:8002 FastAPI:8003 MCP Server:8004 +> +> (production) (development) \[Phase 2\] +> +> │ │ │ +> +> └───────────────┴───────────────┘ +> +> │ +> +> ▼ +> +> ┌─────────────────┐ +> +> │ lifeos-db │ +> +> │ PostgreSQL 16 │ +> +> │ lifeos_prod │ +> +> │ lifeos_dev │ +> +> └─────────────────┘ +> +> │ +> +> ┌────────┴────────┐ +> +> ▼ ▼ +> +> /opt/lifeos/ /opt/lifeos/ +> +> files/prod/ files/dev/ +> +> (file storage) (file storage) + +**4.2 Request Flow** + +> Browser request (HTTPS) +> +> → Nginx: SSL termination, domain routing +> +> → FastAPI route handler +> +> → Config resolution (entity type, field definitions) +> +> → BaseRepository or EntityRepository (SQLAlchemy async) +> +> → PostgreSQL (query execution) +> +> → Jinja2 template render (server-side HTML) +> +> → HTML response → browser + +Form submissions use standard HTML POST. JavaScript handles only UI +interactions: sidebar collapse state, search modal, theme toggle, timer +display, markdown preview, drag-to-reorder. No fetch/XHR to backend from +JS. + +**4.3 Docker Network Topology** + +> Network: lifeos_network (bridge) +> +> Container Image Ports Volumes +> +> ───────────────────────────────────────────────────────────────── +> +> lifeos-db postgres:16-alpine 5432 (internal) pg_data +> +> lifeos-prod lifeos-app:latest 8002 (internal) files/prod +> +> lifeos-dev lifeos-app:latest 8003 (internal) files/dev +> +> lifeos-mcp lifeos-mcp:latest 8004 (internal) \[Phase 2\] + +All container ports are internal to the Docker network. Only Nginx is +exposed to the public internet (ports 80, 443). + + ----------------------------------------------------------------------- + **5. Subsystems and Capabilities** + + ----------------------------------------------------------------------- + +Life OS is composed of nine subsystems. Each subsystem is a coherent +capability domain with its own entities, views, and business logic. All +subsystems share the generic code base, data architecture, search, and +AI interface. + + --------------- ------------------- --------------------------------------- + **Subsystem** **Primary **Key Capabilities** + Entities** + + CRM contacts, Contact directory with roles, + appointments, appointment scheduling, follow-up + reminders reminders linked to contacts, + task/meeting/project associations with + role field + + Project projects, releases, Full project lifecycle, releases + Management milestones, tasks, spanning multiple projects, milestone + dependencies tracking, DAG dependencies with cycle + detection and status cascade, progress + calculation + + Task Management tasks, Priority/status/context, subtasks, + task_templates, dependencies, templates, time estimates + daily_focus, and tracking, Eisenhower matrix view, + time_entries daily focus with timer + + Knowledge notes, Rich text notes with wiki-linking, + Management note_folders, recursive folders, decision knowledge + note_links, base with supersession chain, file + decisions, files, management with preview + links + + Meeting meetings, decisions Full meeting records with + Management agenda/transcript/notes, action item + conversion, attendee management, series + support, decision capture + + Process processes, Workflow vs checklist distinction, + Management process_steps, reusable templates, runs with snapshot + process_runs, isolation, task generation (all-at-once + process_run_steps or step-by-step) + + Time Management time_entries, Time tracking per task, calendar time + time_blocks, blocking, domain weekly budgets, + time_budgets overcommitment surfacing, Eisenhower + matrix + + Personal capture, Capture queue with multi-line parse, + Productivity daily_focus, GTD context types, daily focus, weekly + context_types review process, personal metrics + dashboard + + Weblinks and weblinks, Organized bookmark system, recursive + Bookmarks weblink_folders folders, auto-generated project + folders, browser extension in Phase 2 + --------------- ------------------- --------------------------------------- + +**5.1 Subsystem Interaction Map** + +> Tasks ←──────── Projects ←─── Releases +> +> │ │ │ +> +> ├── Contacts ├── Processes ├── Milestones +> +> │ (waiting) │ (run tasks) │ +> +> ├── Time ├── Notes └── Projects (M2M) +> +> │ Entries │ (M2M) +> +> ├── Daily ├── Decisions +> +> │ Focus │ (tabs) +> +> └── Dependencies └── Files +> +> (DAG) (polymorphic) +> +> Meetings ──── Decisions ──── Projects +> +> │ │ +> +> ├── Contacts └── Contacts +> +> ├── Tasks (action items) +> +> └── Notes (auto-filed) +> +> Capture ──── any entity (polymorphic conversion) +> +> Search ──── every entity (full-text) +> +> MCP ──── every entity (Phase 2) + +**5.2 Admin Subsystem** + +- Trash: all soft-deleted items, grouped by entity type. Restore or + permanent delete. + +- Context Types: manage GTD execution context lookup table. + +- Dependency Settings: enable/disable start_to_finish dependency type. + +- Export: CSV (Phase 1), JSON/PDF/Markdown (Phase 3). + +- Model Registry: configure AI model connections (Phase 2). + +- Theme: dark/light toggle (Phase 3). + +- Storage: disk usage summary per domain. + + ----------------------------------------------------------------------- + **6. Data Architecture** + + ----------------------------------------------------------------------- + +**6.1 Universal Column Conventions** + +Every table without exception follows this field order and naming: + +> id UUID PK DEFAULT gen_random_uuid() +> +> \[foreign keys\] nullable where optional +> +> \[content fields\] entity-specific +> +> tags TEXT\[\] nullable - flexible labels +> +> sort_order INT NOT NULL DEFAULT 0 +> +> is_deleted BOOL NOT NULL DEFAULT false +> +> deleted_at TIMESTAMPTZ nullable +> +> created_at TIMESTAMPTZ NOT NULL DEFAULT now() +> +> updated_at TIMESTAMPTZ NOT NULL DEFAULT now() + ++-----------------------------------------------------------------------+ +| **Search Vector Convention** | +| | +| All searchable tables additionally carry: search_vector TSVECTOR. A | +| PostgreSQL trigger maintains this column automatically on | +| insert/update. A GIN index on search_vector enables fast full-text | +| queries. | ++-----------------------------------------------------------------------+ + +**6.2 Core Hierarchy Tables** + +**domains** + + ----------------- ----------------- ----------------- ----------------- + **Column** **Type** **Nullable** **Description** + + id UUID No PK + + name TEXT No Work, Personal, + Business + + color TEXT Yes Hex color #RRGGBB + + sort_order INT No + + is_deleted BOOL No + + deleted_at TIMESTAMPTZ Yes + + created_at TIMESTAMPTZ No + + updated_at TIMESTAMPTZ No + ----------------- ----------------- ----------------- ----------------- + +**areas** + + ----------------- ----------------- ----------------- ----------------- + **Column** **Type** **Nullable** **Description** + + id UUID No PK + + domain_id UUID No FK domains + CASCADE + + name TEXT No + + description TEXT Yes + + sort_order INT No + + is_deleted BOOL No + + deleted_at TIMESTAMPTZ Yes + + created_at / TIMESTAMPTZ No + updated_at + ----------------- ----------------- ----------------- ----------------- + +**projects** + + ----------------- ----------------- ----------------- -------------------------------------- + **Column** **Type** **Nullable** **Description** + + id UUID No PK + + domain_id UUID No FK domains + + area_id UUID Yes FK areas (optional grouping) + + name TEXT No + + description TEXT Yes + + status TEXT No active\|on_hold\|completed\|archived + + due_date DATE Yes + + tags TEXT\[\] Yes + + sort_order INT No + + is_deleted BOOL No + + deleted_at TIMESTAMPTZ Yes + + created_at / TIMESTAMPTZ No + updated_at + ----------------- ----------------- ----------------- -------------------------------------- + +**tasks** + + ------------------------ ----------------- ----------------- --------------------------------------------- + **Column** **Type** **Nullable** **Description** + + id UUID No PK + + domain_id UUID Yes FK domains + + area_id UUID Yes FK areas + + project_id UUID Yes FK projects (null=standalone) + + release_id UUID Yes FK releases (null=backlog) + + parent_id UUID Yes Self-ref for subtasks + + title TEXT No + + description TEXT Yes + + priority INT No 1=critical 2=high 3=normal 4=low + + status TEXT No open\|in_progress\|blocked\|done\|cancelled + + due_date DATE Yes Soft target + + deadline TIMESTAMPTZ Yes Hard deadline + + recurrence TEXT Yes null\|daily\|weekly\|monthly + + estimated_minutes INT Yes Time estimate + + energy_required TEXT Yes high\|medium\|low + + context TEXT Yes FK context_types.value + + is_custom_context BOOL Yes True if free-text context + + waiting_for_contact_id UUID Yes FK contacts - delegated to + + waiting_since DATE Yes Date delegation started + + import_batch_id UUID Yes Groups bulk-imported tasks + + tags TEXT\[\] Yes + + sort_order INT No + + is_deleted BOOL No + + deleted_at TIMESTAMPTZ Yes + + completed_at TIMESTAMPTZ Yes Set when status=done + + created_at / updated_at TIMESTAMPTZ No + ------------------------ ----------------- ----------------- --------------------------------------------- + +**notes** + + ----------------- ----------------- ----------------- ----------------- + **Column** **Type** **Nullable** **Description** + + id UUID No PK + + domain_id UUID Yes FK domains + + project_id UUID Yes FK projects + (primary project) + + folder_id UUID Yes FK note_folders + (one folder) + + meeting_id UUID Yes FK meetings if + meeting note + + title TEXT No Required + + body TEXT Yes Rich text content + + content_format TEXT No Default: rich + + is_meeting_note BOOL No Default false + + tags TEXT\[\] Yes + + sort_order INT No + + is_deleted BOOL No + + deleted_at TIMESTAMPTZ Yes + + created_at / TIMESTAMPTZ No + updated_at + ----------------- ----------------- ----------------- ----------------- + +**note_folders** + + ----------------- ----------------- ----------------- ----------------- + **Column** **Type** **Nullable** **Description** + + id UUID No PK + + parent_id UUID Yes Self-ref + recursive + + name TEXT No + + auto_generated BOOL No True for system + meeting folders + + sort_order INT No + + is_deleted BOOL No + + created_at / TIMESTAMPTZ No + updated_at + ----------------- ----------------- ----------------- ----------------- + +**lists and list_items** + + ----------------- ----------------- ----------------- ------------------------------- + **Column** **Type** **Nullable** **Description** + + id (lists) UUID No PK + + domain_id UUID Yes FK domains + + area_id UUID Yes FK areas + + project_id UUID Yes FK projects + + name TEXT No + + list_type TEXT No checklist\|ordered\|unordered + + description TEXT Yes + + tags TEXT\[\] Yes + + sort_order INT No + + is_deleted BOOL No + + \-\-- \-\-- \-\-- \-\-- list_items \-\-- + + id (list_items) UUID No PK + + list_id UUID No FK lists + + parent_item_id UUID Yes Self-ref for nested items + + content TEXT No + + completed BOOL No Default false + + completed_at TIMESTAMPTZ Yes + + sort_order INT No + + is_deleted BOOL No + ----------------- ----------------- ----------------- ------------------------------- + +**links and files** + + ------------------- ----------------- ----------------- ---------------------------------------- + **Column** **Type** **Nullable** **Description** + + id (links) UUID No PK + + domain_id UUID Yes + + project_id UUID Yes + + label TEXT No Display name + + url TEXT No Full URL + + description TEXT Yes + + sort_order INT No + + is_deleted BOOL No + + \-\-- \-\-- \-\-- \-\-- files \-\-- + + id (files) UUID No PK + + filename TEXT No UUID-prefixed storage name + + original_filename TEXT No User-facing name + + storage_path TEXT No /opt/lifeos/files/{env}/{uuid}\_{name} + + mime_type TEXT Yes + + size_bytes INT Yes + + description TEXT Yes + + tags TEXT\[\] Yes + + sort_order INT No + + is_deleted BOOL No + ------------------- ----------------- ----------------- ---------------------------------------- + +Files associate to entities via file_mappings junction (polymorphic). No +direct FK on the files table. + +**6.3 System Level Tables** + +**contacts** + + ----------------- ----------------- ----------------- ----------------- + **Column** **Type** **Nullable** **Description** + + id UUID No PK + + first_name TEXT No + + last_name TEXT Yes + + company TEXT Yes + + role TEXT Yes Job title + + email TEXT Yes + + phone TEXT Yes + + notes TEXT Yes Free text + + tags TEXT\[\] Yes + + sort_order INT No + + is_deleted BOOL No + + deleted_at TIMESTAMPTZ Yes + + created_at / TIMESTAMPTZ No + updated_at + ----------------- ----------------- ----------------- ----------------- + +**appointments** + + ----------------- ----------------- ----------------- ------------------------------ + **Column** **Type** **Nullable** **Description** + + id UUID No PK + + title TEXT No + + start_at TIMESTAMPTZ No + + end_at TIMESTAMPTZ Yes + + all_day BOOL No Default false + + location TEXT Yes + + description TEXT Yes + + recurrence TEXT Yes null\|daily\|weekly\|monthly + + tags TEXT\[\] Yes + + sort_order INT No + + is_deleted BOOL No + + created_at / TIMESTAMPTZ No + updated_at + ----------------- ----------------- ----------------- ------------------------------ + +**meetings** + + ----------------- ----------------- ----------------- --------------------------------- + **Column** **Type** **Nullable** **Description** + + id UUID No PK + + parent_id UUID Yes Self-ref: links instance to + series anchor + + title TEXT No + + meeting_date DATE No + + start_at TIMESTAMPTZ Yes + + end_at TIMESTAMPTZ Yes + + location TEXT Yes Zoom, Google Meet, room name + + status TEXT No scheduled\|completed\|cancelled + + priority INT Yes 1=critical to 4=low + + recurrence TEXT Yes For standing meetings + + agenda TEXT Yes Rich text pre-meeting + + transcript TEXT Yes Pasted from recording service + + notes_body TEXT Yes Rich text during/post meeting + + sort_order INT No Default sort: date desc + + is_deleted BOOL No + + deleted_at TIMESTAMPTZ Yes + + created_at / TIMESTAMPTZ No + updated_at + ----------------- ----------------- ----------------- --------------------------------- + +**decisions** + + ------------------ ----------------- ----------------- ------------------------------------------ + **Column** **Type** **Nullable** **Description** + + id UUID No PK + + title TEXT No Summary of the decision + + rationale TEXT Yes Full reasoning, rich text + + status TEXT No proposed\|accepted\|rejected\|superseded + + impact TEXT No low\|medium\|high + + decided_at DATE Yes When decision was made (outside meeting + too) + + meeting_id UUID Yes FK meetings (optional) + + superseded_by_id UUID Yes Self-ref FK decisions + + tags TEXT\[\] Yes + + sort_order INT No + + is_deleted BOOL No + + deleted_at TIMESTAMPTZ Yes + + created_at / TIMESTAMPTZ No + updated_at + ------------------ ----------------- ----------------- ------------------------------------------ + +**releases and milestones** + + ----------------- ----------------- ----------------- ------------------------------------------- + **Column** **Type** **Nullable** **Description** + + id (releases) UUID No PK - System level, not under a project + + name TEXT No Release 1.0, First Draft, Beta + + version_label TEXT Yes 1.0.0, v2, Draft-1 + + description TEXT Yes + + status TEXT No planned\|in_progress\|released\|cancelled + + target_date DATE Yes + + released_at DATE Yes Actual release date + + release_notes TEXT Yes Rich text changelog + + sort_order INT No + + is_deleted BOOL No + + deleted_at TIMESTAMPTZ Yes + + created_at / TIMESTAMPTZ No + updated_at + + \-\-- \-\-- \-\-- \-\-- milestones \-\-- + + id (milestones) UUID No PK + + release_id UUID Yes FK releases (optional) + + project_id UUID Yes FK projects (optional) + + name TEXT No + + target_date DATE No + + completed_at DATE Yes + + sort_order INT No + + is_deleted BOOL No + ----------------- ----------------- ----------------- ------------------------------------------- + +**processes, process_steps, process_runs, process_run_steps** + + --------------------- ----------------- ----------------- ------------------------------------------------ + **Column** **Type** **Nullable** **Description** + + id (processes) UUID No PK + + name TEXT No Publish a Book, Client Onboarding + + description TEXT Yes + + process_type TEXT No workflow\|checklist - key distinction + + category TEXT Yes operational\|creative\|admin\|technical + + status TEXT No draft\|active\|deprecated + + tags TEXT\[\] Yes + + \-\-- \-\-- \-\-- \-\-- process_steps \-\-- + + id (process_steps) UUID No PK + + process_id UUID No FK processes + + title TEXT No + + instructions TEXT Yes Rich text + + expected_output TEXT Yes + + estimated_days INT Yes + + context TEXT Yes FK context_types.value + + sort_order INT No Sequential order + + \-\-- \-\-- \-\-- \-\-- process_runs \-\-- + + id (process_runs) UUID No PK + + process_id UUID No FK processes (source template) + + title TEXT No Onboard ACME Corp - Mar 2026 + + status TEXT No not_started\|in_progress\|completed\|cancelled + + process_type TEXT No Copied from template at run creation + + task_generation TEXT No all_at_once\|step_by_step + + project_id UUID Yes FK projects (optional context) + + contact_id UUID Yes FK contacts (optional context) + + started_at TIMESTAMPTZ Yes + + completed_at TIMESTAMPTZ Yes + + \-\-- \-\-- \-\-- \-\-- process_run_steps \-\-- + + id UUID No PK + (process_run_steps) + + run_id UUID No FK process_runs + + title TEXT No Copied from process_step - immutable + + instructions TEXT Yes Copied from process_step - immutable + + status TEXT No pending\|in_progress\|done\|skipped + + completed_by_id UUID Yes FK contacts + + completed_at TIMESTAMPTZ Yes + + notes TEXT Yes + + sort_order INT No + --------------------- ----------------- ----------------- ------------------------------------------------ + +**time management tables** + + ------------------ ----------------- ----------------- ---------------------------- + **Column** **Type** **Nullable** **Description** + + id (time_entries) UUID No PK + + task_id UUID No FK tasks + + start_at TIMESTAMPTZ No + + end_at TIMESTAMPTZ Yes null if timer running + + duration_minutes INT Yes Calculated on stop + + notes TEXT Yes + + is_deleted BOOL No + + created_at TIMESTAMPTZ No + + \-\-- \-\-- \-\-- \-\-- time_blocks \-\-- + + id (time_blocks) UUID No PK + + task_id UUID Yes FK tasks (optional - block + can be contextual) + + title TEXT No + + context TEXT Yes deep_work\|meetings\|admin + + energy TEXT Yes high\|medium\|low + + start_at TIMESTAMPTZ No + + end_at TIMESTAMPTZ No + + is_deleted BOOL No + + created_at / TIMESTAMPTZ No + updated_at + + \-\-- \-\-- \-\-- \-\-- time_budgets \-\-- + + id (time_budgets) UUID No PK + + domain_id UUID No FK domains + + weekly_hours DECIMAL No Target hours per week + + effective_from DATE No + + is_deleted BOOL No + + created_at TIMESTAMPTZ No + ------------------ ----------------- ----------------- ---------------------------- + +**supporting system tables** + + ------------------- ----------------- ----------------- ---------------------------------------------------- + **Column** **Type** **Nullable** **Description** + + id (daily_focus) UUID No PK + + focus_date DATE No + + task_id UUID No FK tasks + + slot INT Yes Display order - position is the priority signal + + completed BOOL No Default false + + note TEXT Yes + + created_at TIMESTAMPTZ No + + \-\-- \-\-- \-\-- \-\-- capture \-\-- + + id (capture) UUID No PK + + raw_text TEXT No + + processed BOOL No Default false + + converted_to_type TEXT Yes task\|project\|note\|list\|contact\|decision\|link + + converted_to_id UUID Yes Polymorphic FK + + area_id UUID Yes Context at capture time + + project_id UUID Yes Context at capture time + + list_id UUID Yes Context at capture time + + import_batch_id UUID Yes Groups multi-line paste imports + + is_deleted BOOL No + + created_at TIMESTAMPTZ No + + \-\-- \-\-- \-\-- \-\-- task_templates \-\-- + + id (task_templates) UUID No PK + + name TEXT No New Client Onboarding + + description TEXT Yes + + priority INT Yes Default priority + + estimated_minutes INT Yes + + energy_required TEXT Yes + + context TEXT Yes + + tags TEXT\[\] Yes + + sort_order INT No + + is_deleted BOOL No + + \-\-- \-\-- \-\-- \-\-- task_template_items \-\-- + + id UUID No PK + + template_id UUID No FK task_templates + + title TEXT No + + sort_order INT No + + is_deleted BOOL No + ------------------- ----------------- ----------------- ---------------------------------------------------- + +**weblinks, context_types, reminders** + + ------------------- ----------------- ----------------- ----------------------------------------------------- + **Column** **Type** **Nullable** **Description** + + id UUID No PK + (weblink_folders) + + parent_id UUID Yes Self-ref recursive + + name TEXT No + + auto_generated BOOL No True for system project folders + + sort_order INT No + + is_deleted BOOL No + + \-\-- \-\-- \-\-- \-\-- weblinks \-\-- + + id (weblinks) UUID No PK + + label TEXT No Display name + + url TEXT No Full URL + + description TEXT Yes + + tags TEXT\[\] Yes + + sort_order INT No + + is_deleted BOOL No + + \-\-- \-\-- \-\-- \-\-- context_types \-\-- + + id SERIAL No Integer PK (not UUID) + + value TEXT No deep_work\|quick\|waiting\|someday\|meeting\|errand + + label TEXT No Display label + + is_system BOOL No True for built-in types + + sort_order INT No + + is_deleted BOOL No + + \-\-- \-\-- \-\-- \-\-- reminders \-\-- + + id UUID No PK + + entity_type TEXT No contact\|task\|meeting\|appointment + + entity_id UUID No Polymorphic FK + + remind_at TIMESTAMPTZ No When to surface + + note TEXT Yes Follow up re: contract renewal + + delivered BOOL No False until shown in UI + + is_deleted BOOL No + + created_at TIMESTAMPTZ No + ------------------- ----------------- ----------------- ----------------------------------------------------- + +**6.4 Junction Tables** + + ---------------------- --------------------- ----------------------------------- + **Junction Table** **Connects** **Key Columns** + + note_projects notes \<-\> projects is_primary BOOL + + note_links notes \<-\> notes source_note_id, target_note_id + (wiki graph) + + file_mappings files \<-\> any context_type TEXT, context_id UUID + entity + + release_projects releases \<-\> (no extra) + projects + + release_domains releases \<-\> (no extra - optional context) + domains + + contact_tasks contacts \<-\> tasks role TEXT + + contact_projects contacts \<-\> role TEXT + projects + + contact_lists contacts \<-\> lists role TEXT + + contact_list_items contacts \<-\> role TEXT + list_items + + contact_appointments contacts \<-\> role TEXT + appointments + + contact_meetings contacts \<-\> role TEXT + meetings (organizer\|attendee\|optional) + + decision_projects decisions \<-\> (no extra) + projects + + decision_contacts decisions \<-\> role TEXT + contacts (proposer\|approver\|stakeholder) + + meeting_tasks meetings \<-\> tasks source TEXT + (discussed\|action_item) + + process_run_tasks process_run_steps run_step_id FK + \<-\> tasks + + folder_weblinks weblink_folders \<-\> (no extra) + weblinks + ---------------------- --------------------- ----------------------------------- + +**6.5 Dependencies Table** + +One polymorphic table handles all dependency relationships across all +entity types. Full DAG support. + + ----------------- ----------------- ----------------- -------------------------------------------------------------------- + **Column** **Type** **Nullable** **Description** + + id UUID No PK + + blocker_type TEXT No task\|project\|process_step\|process_run + + blocker_id UUID No + + dependent_type TEXT No task\|project\|process_step\|process_run + + dependent_id UUID No + + dependency_type TEXT No finish_to_start\|finish_to_finish\|start_to_start\|start_to_finish + + lag_days INT No Default 0 + + note TEXT Yes + + is_deleted BOOL No Default false + + deleted_at TIMESTAMPTZ Yes + + created_at TIMESTAMPTZ No Auto + ----------------- ----------------- ----------------- -------------------------------------------------------------------- + +Indexes: idx_dependencies_blocker (blocker_type, blocker_id), +idx_dependencies_dependent (dependent_type, dependent_id) + +Constraints: UNIQUE (blocker_type, blocker_id, dependent_type, +dependent_id, dependency_type), CHECK no self-dependency + +**6.6 Complete Table Inventory (50 tables)** + + ------------------------ --------------------- ------------------------- + **Table** **Category** **Phase** + + domains Core hierarchy 1 + + areas Core hierarchy 1 + + projects Core hierarchy 1 + + tasks Core hierarchy 1 + + notes Core hierarchy 1 + + note_folders Core hierarchy 1 + + lists Core hierarchy 1 + + list_items Core hierarchy 1 + + links Core hierarchy 1 + + files Core hierarchy 1 + + contacts System level 1 + + appointments System level 1 + + meetings System level 1 + + decisions System level 1 + + releases System level 1 + + milestones System level 1 + + processes System level 1 + + process_steps System level 1 + + process_runs System level 1 + + process_run_steps System level 1 + + daily_focus System level 1 + + capture System level 1 + + task_templates System level 1 + + task_template_items System level 1 + + time_entries Time management 1 + + time_blocks Time management 1 + + time_budgets Time management 1 + + weblink_folders System level 1 + + weblinks System level 1 + + context_types Lookup 1 + + reminders System level 1 + + dependencies Universal junction 1 + + note_projects Junction 1 + + note_links Junction 1 + + file_mappings Junction 1 + + release_projects Junction 1 + + release_domains Junction 1 + + contact_tasks Junction 1 + + contact_projects Junction 1 + + contact_lists Junction 1 + + contact_list_items Junction 1 + + contact_appointments Junction 1 + + contact_meetings Junction 1 + + decision_projects Junction 1 + + decision_contacts Junction 1 + + meeting_tasks Junction 1 + + process_run_tasks Junction 1 + + folder_weblinks Junction 1 + + note_version_history Knowledge mgmt 2 + + pipelines CRM 2 + ------------------------ --------------------- ------------------------- + + ----------------------------------------------------------------------- + **7. Application Layer Architecture** + + ----------------------------------------------------------------------- + +**7.1 Technology Stack** + + ---------------- ------------------------------------------------------ + **Language** Python 3.12 + + **Framework** FastAPI (async) + + **ORM** SQLAlchemy 2.0 async + psycopg3 + + **Templates** Jinja2 (server-rendered HTML) + + **Forms** Standard HTML POST, python-multipart + + **Search** PostgreSQL tsvector/tsquery (no external service) + + **File python-multipart, aiofiles + handling** + + **Config** python-dotenv, YAML for entity/menu config + + **Validation** Pydantic v2 models for request/response + + **Testing** pytest-asyncio, httpx + ---------------- ------------------------------------------------------ + +**7.2 Project File Structure** + +> life-os/ +> +> main.py FastAPI app init, middleware, router includes +> +> config/ +> +> entities.yaml Config-driven entity definitions (12 simple entities) +> +> menu.yaml Sidebar navigation config +> +> search.yaml Searchable entities and field weights +> +> core/ +> +> database.py Async engine, session factory +> +> base_repository.py BaseRepository: +> list/get/create/update/soft_delete/restore +> +> generic_router.py Config-driven CRUD router for simple entities +> +> generic_templates.py Template context builder for config-driven views +> +> search.py Global search implementation +> +> dependencies.py DAG cycle detection, status cascade +> +> reminders.py Reminder surfacing on dashboard load +> +> timer.py Time tracking start/stop logic +> +> routers/ +> +> tasks.py Task CRUD + subtasks + templates + bulk actions +> +> projects.py Project CRUD + progress calculation +> +> releases.py Release CRUD + multi-project aggregation +> +> meetings.py Meeting CRUD + action items + series +> +> decisions.py Decision CRUD + supersession chain +> +> processes.py Template CRUD + run management + task generation +> +> capture.py Queue management + multi-line parse + conversion +> +> focus.py Daily focus list management +> +> notes.py Note CRUD + wiki links + folder management +> +> search.py Global search endpoint +> +> files.py Upload + download + preview routing +> +> calendar.py Unified calendar view (appointments + meetings + tasks) +> +> admin.py Trash + context types + settings + export +> +> dashboard.py Dashboard aggregation + metrics widget +> +> time.py Time entries + blocks + budget views +> +> eisenhower.py Matrix view derivation +> +> \[generic entities\] domains, areas, contacts, weblinks, etc via +> generic_router +> +> templates/ +> +> base.html Shell: topbar, sidebar, JS includes, theme classes +> +> \_list.html Generic list template (all entities) +> +> \_detail.html Generic detail shell (tabs, breadcrumb, header) +> +> \_form.html Generic create/edit form +> +> \_empty.html Generic empty state component +> +> dashboard.html Dashboard with widgets +> +> focus.html Daily focus view +> +> tasks.html Task list (extends \_list.html) +> +> task_detail.html Task detail with dependencies panel +> +> project_detail.html Project detail with tabs +> +> release_detail.html Release detail with multi-project view +> +> meeting_detail.html Meeting detail with action items +> +> process_detail.html Process template + runs +> +> note_detail.html Note editor with wiki link support +> +> calendar.html Calendar view +> +> eisenhower.html Eisenhower matrix view +> +> capture_queue.html Capture review and convert +> +> admin_trash.html Trash recovery view +> +> search_results.html Global search results +> +> static/ +> +> style.css All styles (dark theme, light theme, components) +> +> app.js Sidebar collapse, search modal, timer, theme toggle +> +> sortable.js Drag-to-reorder (SortableJS CDN or local) +> +> requirements.txt +> +> .env NEVER committed to git +> +> docker-compose.yml + +**7.3 Router Anatomy** + +All routers follow this identical pattern regardless of entity +complexity: + +> from fastapi import APIRouter, Request, Form, Depends +> +> from core.base_repository import BaseRepository +> +> from core.database import get_db +> +> router = APIRouter(prefix=\'/tasks\', tags=\[\'tasks\'\]) +> +> templates = Jinja2Templates(directory=\'templates\') +> +> \@router.get(\'/\') +> +> async def list_tasks(request: Request, db=Depends(get_db), +> \...filters): +> +> repo = TaskRepository(db) +> +> items = await repo.list(filters=filters, sort=sort) +> +> sidebar = await get_sidebar_data(db) +> +> return templates.TemplateResponse(\'tasks.html\', { +> +> \'request\': request, \'items\': items, \'sidebar\': sidebar +> +> }) +> +> \@router.post(\'/create\') +> +> async def create_task(request: Request, db=Depends(get_db), +> \...fields): +> +> repo = TaskRepository(db) +> +> task = await repo.create({\...fields}) +> +> return RedirectResponse(url=f\'/tasks/{task.id}\', status_code=303) + + ----------------------------------------------------------------------- + **8. Generic Code Architecture** + + ----------------------------------------------------------------------- + +The generic architecture reduces code volume by 40-45% and ensures +consistency across all entities. Three layers work together: +BaseRepository handles all common data operations, config-driven +entities eliminate entity-specific code entirely for simple entities, +and the menu/sidebar is fully configuration-driven. + +**8.1 Entity Classification** + + -------------------- ------------------------ ------------------------------ + **Classification** **Entities** **Approach** + + Fully config-driven domains, areas, entities.yaml config + + (zero custom code) context_types, weblinks, generic_router.py + + weblink_folders, \_list.html + \_form.html + note_folders, + time_budgets, + task_templates, + task_template_items, + milestones, + release_domains, + release_projects + + Generic base + contacts, appointments, BaseRepository extended with + overrides notes, links, files, custom methods. Standard + meetings, decisions, templates with entity-specific + releases, processes, blocks. + process_steps, + list_items, lists, + time_blocks, + time_entries, reminders, + note_links, + file_mappings + + Substantially custom tasks, projects, Full custom router. + logic process_runs, BaseRepository as foundation. + process_run_steps, Business logic in dedicated + daily_focus, capture, service classes. + dependencies, search, + releases (aggregate), + task_templates + (instantiate), all + contact junction tables + -------------------- ------------------------ ------------------------------ + +**8.2 BaseRepository** + +> class BaseRepository: +> +> def \_\_init\_\_(self, table: str, db: AsyncSession): +> +> self.table = table +> +> self.db = db +> +> async def list(self, filters={}, sort=\'sort_order\', +> +> page=1, per_page=50) -\> list: +> +> \# Adds WHERE is_deleted=false automatically +> +> \# Applies filter dict as WHERE clauses +> +> \# Applies sort with fallback to created_at +> +> async def get(self, id: UUID) -\> dict \| None: +> +> async def create(self, data: dict) -\> dict: +> +> \# Auto-sets created_at, updated_at, is_deleted=false +> +> \# Updates search_vector via trigger +> +> async def update(self, id: UUID, data: dict) -\> dict: +> +> \# Auto-sets updated_at +> +> async def soft_delete(self, id: UUID) -\> dict: +> +> \# Sets is_deleted=true, deleted_at=now() +> +> async def restore(self, id: UUID) -\> dict: +> +> \# Sets is_deleted=false, deleted_at=null +> +> async def bulk_soft_delete(self, ids: list\[UUID\]) -\> int: +> +> async def list_deleted(self) -\> list: +> +> \# Used by Admin \> Trash +> +> async def permanent_delete(self, id: UUID) -\> bool: +> +> \# Actual SQL DELETE - Admin only + +**8.3 Config-Driven Entity Definition** + +> \# config/entities.yaml +> +> domains: +> +> table: domains +> +> display_name: Domain +> +> display_plural: Domains +> +> icon: grid +> +> fields: +> +> \- name: name type: text required: true label: Domain Name +> +> \- name: color type: color required: false label: Color +> +> list_columns: \[name, color, created_at\] +> +> searchable: \[name\] +> +> sort_default: sort_order +> +> allow_reorder: true +> +> contacts: +> +> table: contacts +> +> display_name: Contact +> +> fields: +> +> \- name: first_name type: text required: true +> +> \- name: last_name type: text +> +> \- name: company type: text +> +> \- name: email type: email +> +> \- name: phone type: tel +> +> \- name: notes type: textarea +> +> \- name: tags type: tags +> +> list_columns: \[first_name, last_name, company, email\] +> +> searchable: \[first_name, last_name, company, email\] + +**8.4 Config-Driven Sidebar** + +> \# config/menu.yaml +> +> system_items: +> +> \- id: dashboard label: Dashboard icon: grid route: / +> +> \- id: focus label: Focus icon: target route: /focus badge: +> focus_count +> +> \- id: tasks label: All Tasks icon: check route: /tasks +> +> \- id: calendar label: Calendar icon: calendar route: /calendar +> +> \- id: meetings label: Meetings icon: users route: /meetings +> +> \- id: decisions label: Decisions icon: diamond route: /decisions +> +> \- id: releases label: Releases icon: tag route: /releases +> +> \- id: processes label: Processes icon: flow route: /processes +> +> \- id: notes label: Notes icon: file route: /notes +> +> \- id: contacts label: Contacts icon: person route: /contacts +> +> \- id: weblinks label: Weblinks icon: link route: /weblinks +> +> \- id: capture label: Capture icon: inbox route: /capture badge: +> capture_count +> +> \- id: admin label: Admin icon: settings route: /admin +> +> mobile_bottom_bar: +> +> \- id: dashboard icon: grid label: Home +> +> \- id: focus icon: target label: Focus +> +> \- id: tasks icon: check label: Tasks +> +> \- id: calendar icon: calendar label: Calendar +> +> \- id: more icon: menu label: More +> +> mobile_more_items: \[meetings, decisions, contacts, processes, +> weblinks, admin\] + + ----------------------------------------------------------------------- + **9. Frontend Architecture** + + ----------------------------------------------------------------------- + +**9.1 Approach** + +Server-rendered HTML via Jinja2 templates. No frontend framework, no +build pipeline, no npm. CSS custom properties for theming. Vanilla JS +for UI interactions only. SortableJS for drag-to-reorder (single +dependency). + +**9.2 Design Tokens** + +> /\* style.css - CSS custom properties \*/ +> +> \[data-theme=\'dark\'\] { +> +> \--bg: #0D0E13; \--surface: #14161F; +> +> \--surface2: #1A1D28; \--border: #252836; +> +> \--text: #DDE1F5; \--muted: #5A6080; +> +> \--accent: #4F6EF7; \--accent-soft:rgba(79,110,247,.12); +> +> \--green: #22C98A; \--amber: #F5A623; +> +> \--red: #F05252; \--purple: #9B7FF5; +> +> } +> +> \[data-theme=\'light\'\] { +> +> \--bg: #F0F2F8; \--surface: #FFFFFF; +> +> \--surface2: #F7F8FC; \--border: #E3E6F0; +> +> \--text: #171926; \--muted: #8892B0; +> +> \--accent: #4F6EF7; \--accent-soft:rgba(79,110,247,.10); +> +> \--green: #10B981; \--amber: #F59E0B; +> +> \--red: #DC2626; +> +> } + +**9.3 Universal Layout Patterns** + +**These patterns apply identically to every screen. Learn once, apply +everywhere.** + + ----------------------------------------------------------------------- + **Every list view** + + ----------------------------------------------------------------------- + +> \[Page title + count\] \[+ Add button\] +> +> \[Filter chips: Status / Domain / Priority\] \[Sort dropdown\] +> +> \[Search within this view input\] +> +> ───────────────────────────────────────────────────────── +> +> \[Row\] \[check\] \[pri\] \[Title\...\...\...\...\] \[tag\] \[proj\] +> \[date\] +> +> \[Row\] \[check\] \[pri\] \[Title\...\...\...\...\] \[tag\] \[proj\] +> \[date\] +> +> \[Empty state with CTA if no items\] + + ----------------------------------------------------------------------- + **Every detail view** + + ----------------------------------------------------------------------- + +> \[Breadcrumb: Domain \> Area \> Project \> Item\] +> +> \[Header: name, metadata, progress bar if applicable\] +> +> \[Tabs: Tasks \| Notes \| Lists \| Links \| Files \| Contacts \| +> Decisions\] +> +> ───────────────────────────────────────────────────────── +> +> \[Tab content: same list pattern as above\] + + ----------------------------------------------------------------------- + **Three action levels - always same position** + + ----------------------------------------------------------------------- + +- Row level: hover shows quick actions right-aligned (complete, edit, + delete) + +- Selection level: checkbox selects reveal bulk action bar at top + +- Page level: + Add button top right, always visible + +**9.4 Component Library** + + ----------------- ---------------------- --------------------------------- + **Component** **Description** **Used in** + + list-row Compact task/item row All list views + with check, pri dot, + title, meta + + filter-chip Toggleable filter All list views + button with active + state + + sort-dropdown Sort selector with All list views + current sort shown + + entity-header Name, metadata, All detail views + progress bar, status + badge + + tab-strip Horizontal tab All detail views + navigation with active + state + + related-widget Polymorphic attachment Detail views + list with + link + button + + search-modal Full-screen search Global (Cmd/K) + overlay with grouped + results + + toast Timed/dismissible Global + notification + (success/error/undo) + + confirm-dialog Destructive action Delete actions + confirmation with item + name + + timer-pill Running timer display Topbar + in topbar with stop + button + + empty-state Illustrated All list views + placeholder with + guidance text and CTA + + skeleton Grey placeholder All views + shapes for loading + state + + wiki-link Inline \[\[ trigger Note editor + for note linking + + file-preview Modal for File lists + image/PDF/video inline + preview + + eisenhower-grid 2x2 matrix derived Tasks view + from priority + + urgency + ----------------- ---------------------- --------------------------------- + +**9.5 JavaScript Responsibilities** + +JS handles only UI state. No data fetching from JS. No SPA routing. + +- Sidebar collapse state (localStorage persistence per domain) + +- Search modal open/close (Cmd/K trigger, Escape close) + +- Theme toggle (data-theme attribute on html element, localStorage) + +- Timer: start/stop, elapsed display, topbar pill update + +- Drag-to-reorder via SortableJS, POST to /reorder endpoint on drop + +- File preview modal open/close + +- Wiki link \[\[ autocomplete dropdown in note editor + +- Capture multi-line paste detection and line count preview + +- Toast auto-dismiss timer + +- Confirm dialog show/hide + +- Sidebar filter toggle per domain + + ----------------------------------------------------------------------- + **10. Infrastructure Architecture** + + ----------------------------------------------------------------------- + +**10.1 Server** + + ---------------- ------------------------------------------------------ + **Host** defiant-01 + + **IP** 46.225.166.142 + + **OS** Ubuntu 24.04 LTS + + **CPU / RAM** As provisioned by hosting provider + + **Docker** Docker Engine + docker-compose v2 + + **DNS A record** lifeos.invixiom.com -\> 46.225.166.142 + + **DNS A record** lifeos-dev.invixiom.com -\> 46.225.166.142 + ---------------- ------------------------------------------------------ + +**10.2 Docker Compose Configuration** + +> version: \'3.9\' +> +> services: +> +> lifeos-db: +> +> image: postgres:16-alpine +> +> container_name: lifeos-db +> +> restart: unless-stopped +> +> environment: +> +> POSTGRES_USER: lifeos_dev +> +> POSTGRES_PASSWORD: \${DB_PASSWORD} +> +> volumes: +> +> \- pg_data:/var/lib/postgresql/data +> +> networks: \[lifeos_network\] +> +> lifeos-prod: +> +> build: . +> +> container_name: lifeos-prod +> +> restart: unless-stopped +> +> environment: +> +> DATABASE_URL: +> postgresql+asyncpg://lifeos_dev:\${DB_PASSWORD}@lifeos-db/lifeos_prod +> +> FILE_STORAGE_PATH: /opt/lifeos/files/prod +> +> ENVIRONMENT: production +> +> MCP_API_KEY: \${MCP_API_KEY} +> +> volumes: +> +> \- /opt/lifeos/files/prod:/opt/lifeos/files/prod +> +> networks: \[lifeos_network\] +> +> depends_on: \[lifeos-db\] +> +> lifeos-dev: +> +> build: . +> +> container_name: lifeos-dev +> +> restart: unless-stopped +> +> environment: +> +> DATABASE_URL: +> postgresql+asyncpg://lifeos_dev:\${DB_PASSWORD}@lifeos-db/lifeos_dev +> +> FILE_STORAGE_PATH: /opt/lifeos/files/dev +> +> ENVIRONMENT: development +> +> volumes: +> +> \- /opt/lifeos/files/dev:/opt/lifeos/files/dev +> +> \- ./:/app \# hot reload in dev +> +> networks: \[lifeos_network\] +> +> depends_on: \[lifeos-db\] +> +> \# Phase 2: +> +> \# lifeos-mcp: +> +> \# build: ./mcp +> +> \# container_name: lifeos-mcp +> +> \# environment: +> +> \# LIFEOS_API_URL: http://lifeos-prod:8002 +> +> \# MCP_API_KEY: \${MCP_API_KEY} +> +> \# networks: \[lifeos_network\] +> +> volumes: +> +> pg_data: +> +> networks: +> +> lifeos_network: +> +> external: true + +**10.3 Nginx Configuration** + +> \# /etc/nginx/sites-available/lifeos +> +> \# HTTP -\> HTTPS redirect +> +> server { +> +> listen 80; +> +> server_name lifeos.invixiom.com lifeos-dev.invixiom.com; +> +> return 301 https://\$host\$request_uri; +> +> } +> +> \# Production +> +> server { +> +> listen 443 ssl; +> +> server_name lifeos.invixiom.com; +> +> ssl_certificate +> /etc/letsencrypt/live/lifeos.invixiom.com/fullchain.pem; +> +> ssl_certificate_key +> /etc/letsencrypt/live/lifeos.invixiom.com/privkey.pem; +> +> client_max_body_size 100M; +> +> location /static/ { alias /opt/lifeos/static/; } +> +> location /files/ { +> +> alias /opt/lifeos/files/prod/; +> +> internal; \# served only via X-Accel-Redirect from FastAPI +> +> } +> +> \# Phase 2: AI gateway +> +> \# location /ai/ { proxy_pass http://lifeos-mcp:8004/; } +> +> location / { +> +> proxy_pass http://lifeos-prod:8002; +> +> proxy_set_header Host \$host; +> +> proxy_set_header X-Real-IP \$remote_addr; +> +> } +> +> } +> +> \# Development (same structure, port 8003, lifeos-dev) + +**10.4 Database Management** + + ----------------------------------------------------------------------- + **Backups** + + ----------------------------------------------------------------------- + +> \# Daily automated backup - cron job +> +> 0 3 \* \* \* docker exec lifeos-db pg_dump -U lifeos_dev lifeos_prod +> \| \\ +> +> gzip \> /opt/lifeos/backups/prod\_\$(date +%Y%m%d).sql.gz +> +> \# Retention: 30 days +> +> find /opt/lifeos/backups -name \'prod\_\*.sql.gz\' -mtime +30 -delete + + ----------------------------------------------------------------------- + **Migrations** + + ----------------------------------------------------------------------- + +- Schema changes applied via numbered SQL migration files: + /opt/lifeos/migrations/ + +- Applied manually via psql inside lifeos-db container + +- Migration log table tracks applied migrations + +- Always apply to lifeos_dev first, verify, then apply to lifeos_prod + +**10.5 Directory Structure on defiant-01** + +> /opt/lifeos/ +> +> backups/ Daily pg_dump archives (30-day retention) +> +> files/ +> +> prod/ Production file uploads +> +> dev/ Development file uploads +> +> migrations/ Numbered SQL migration files +> +> static/ Shared static assets (CSS, JS) +> +> lifeos-setup.sh Repeatable server setup script +> +> .env Environment variables (never in git) +> +> docker-compose.yml Container definitions +> +> /var/log/nginx/ +> +> lifeos_access.log 7-day retention +> +> lifeos_error.log + + ----------------------------------------------------------------------- + **11. Search Architecture** + + ----------------------------------------------------------------------- + +**11.1 Implementation** + +PostgreSQL native full-text search via tsvector/tsquery. No external +search service required. Fast at single-user scale. + +> \-- Every searchable table gets: +> +> search_vector TSVECTOR +> +> \-- GIN index for fast queries: +> +> CREATE INDEX idx_tasks_search ON tasks USING GIN(search_vector); +> +> \-- Trigger maintains search_vector on insert/update: +> +> CREATE TRIGGER tasks_search_update +> +> BEFORE INSERT OR UPDATE ON tasks +> +> FOR EACH ROW EXECUTE FUNCTION +> +> tsvector_update_trigger(search_vector, \'pg_catalog.english\', +> +> \'title\', \'description\', \'tags\'); + +**11.2 Global Search Behavior** + +- Triggered by Cmd/K from anywhere, or search icon in topbar + +- 200ms debounce, instant results as you type + +- Searches all entities in parallel async queries + +- Results grouped by entity type, most relevant section first + +- Every result shows full context path: Title -\> Project -\> Domain + +- Recent searches shown before typing (last 10, localStorage) + +- Filter within results by entity type, domain, date range, status + +**11.3 Scoped Search** + +- Default to current project/domain scope when inside a context + +- One click or Cmd+Shift+K to expand to global scope + +- Scope indicator shown in search bar placeholder text + +**11.4 Searchable Entities** + +tasks, projects, notes, lists, list_items, contacts, appointments, +meetings, decisions, processes, weblinks, files, capture, links, +releases, milestones + + ----------------------------------------------------------------------- + **12. Time Management Architecture** + + ----------------------------------------------------------------------- + +**12.1 Components** + + ---------------- ---------------------- ------------------------------- + **Component** **Purpose** **Data source** + + Time estimates How long a task should User input at task create/edit + take + (estimated_minutes on + tasks) + + Time tracking How long a task Start/stop timer per task + actually took + (time_entries table) + + Time budgets Weekly hour targets User configures in Admin + per domain + (time_budgets table) + + Time blocks Reserved calendar User creates on Calendar view + slots (time_blocks + table) + + Eisenhower Importance vs urgency Derived from priority + due + Matrix view of current tasks date + + Availability Open time after blocks Derived from calendar + blocks + view and appointments + + Dashboard widget Today: Xh estimated vs Derived on load, cached 5min + Xh available + + Weekly metrics Tasks done, hours Derived, aggregated on load + logged, meetings, + decisions + ---------------- ---------------------- ------------------------------- + +**12.2 Timer Flow** + +> User clicks timer button on task row +> +> -\> POST /time/start {task_id} +> +> -\> Creates time_entries row: start_at=now(), end_at=null +> +> -\> Returns entry_id +> +> -\> JS updates topbar timer pill with running indicator +> +> User clicks stop in topbar pill +> +> -\> POST /time/stop {entry_id} +> +> -\> Sets end_at=now(), calculates duration_minutes +> +> -\> Returns updated entry +> +> -\> Topbar pill clears +> +> -\> Task row shows updated total logged time + +Only one timer can run at a time. Starting a new timer auto-stops any +running timer. + +**12.3 Overcommitment Surfacing** + +> Dashboard load: +> +> 1\. Get today\'s focus task list with estimated_minutes for each +> +> 2\. Sum estimated_minutes for open tasks -\> today_estimate +> +> 3\. Get time_blocks for today -\> available_hours +> +> 4\. Get time_budgets for each domain -\> weekly budget +> +> 5\. Sum estimated_minutes for all open tasks this week -\> +> week_estimate +> +> 6\. Compare: if week_estimate \> weekly_budget -\> show overcommitment +> warning + +**12.4 Eisenhower Matrix Logic** + +> For each open task: +> +> importance = priority (1=critical/2=high -\> Important) +> +> urgency = due_date proximity: +> +> overdue or due today/tomorrow -\> Urgent +> +> due within 7 days -\> Urgent +> +> due \> 7 days or no date -\> Not Urgent +> +> Quadrant assignment: +> +> Important + Urgent -\> Do First (red) +> +> Important + Not Urgent -\> Schedule (blue) +> +> Not Important + Urgent -\> Delegate (amber) +> +> Not Important + Not Urgent -\> Eliminate/Someday (grey) + +Matrix is a derived view - no new data, just a different lens on +existing task fields. Rendered as a 2x2 grid with task counts per +quadrant. Clicking a quadrant opens the task list filtered to that +quadrant. + + ----------------------------------------------------------------------- + **13. AI and MCP Architecture (Phase 2)** + + ----------------------------------------------------------------------- + +**13.1 Design Principle** + +One tool implementation. Two transport formats. Any AI model. The MCP +server is a thin transport adapter over the shared tool core. Adding a +new model provider requires only a config entry. + +**13.2 Architecture** + +> ┌───────────────────────────────────────────────────────┐ +> +> │ AI CLIENTS │ +> +> │ Claude (MCP) GPT-4o (func) Mistral Ollama │ +> +> └──────┬──────────────┬────────────────┬────────────────┘ +> +> │ │ │ +> +> MCP transport OpenAI format OpenAI format +> +> (stdio/SSE) (function call) (function call) +> +> │ │ │ +> +> └──────────────┴────────────────┘ +> +> │ +> +> ┌────────────▼────────────┐ +> +> │ lifeos-mcp:8004 │ +> +> │ MCP Server Container │ +> +> │ │ +> +> │ /mcp (MCP transport) │ +> +> │ /tools/openai (OAI fmt) │ +> +> └────────────┬─────────────┘ +> +> │ HTTP (Docker internal) +> +> ▼ +> +> ┌────────────────────────┐ +> +> │ Tool Core Layer │ +> +> │ tools/tasks.py │ +> +> │ tools/projects.py │ +> +> │ tools/meetings.py │ +> +> │ tools/search.py │ +> +> │ tools/meta.py │ +> +> │ \... (all entities) │ +> +> └────────────┬────────────┘ +> +> │ HTTP + API key +> +> ▼ +> +> ┌────────────────────────┐ +> +> │ lifeos-prod FastAPI │ +> +> └────────────────────────┘ + +**13.3 Tool Inventory (46 tools)** + + --------------- ---------------------------------------- --------------- + **Category** **Tools** **Count** + + Context/Meta get_context (domains+areas+projects), 2 + get_dashboard_summary + + Tasks create, list, get, update, complete, 9 + delete, add_to_focus, get_blocked, + list_dependencies + + Projects create, list, get, update, get_progress, 6 + list_tasks + + Meetings create, list, get, add_note, 6 + create_action_item, list_decisions + + Decisions create, list, get, update, 5 + link_to_project + + Processes list, get, start_run, complete_step, 5 + get_run_status + + Notes create, list, get, update, search_notes 5 + + Contacts create, list, get, search_contacts 4 + + Capture create, list_unprocessed, process_item 3 + + Search search (global, all entities) 1 + --------------- ---------------------------------------- --------------- + +**13.4 Model Registry Configuration** + +> \# config/ai_models.yaml (editable from Admin UI) +> +> models: +> +> personal: +> +> provider: anthropic +> +> model: claude-opus-4-6 +> +> interface: mcp +> +> api_key_env: ANTHROPIC_API_KEY +> +> work: +> +> provider: openai +> +> model: gpt-4o +> +> interface: openai_functions +> +> api_key_env: OPENAI_API_KEY_WORK +> +> local: +> +> provider: ollama +> +> model: llama3 +> +> interface: openai_functions +> +> base_url: http://localhost:11434 + +**13.5 Claude Desktop Connection** + +> \# \~/Library/Application Support/Claude/claude_desktop_config.json +> +> { +> +> \"mcpServers\": { +> +> \"lifeos\": { +> +> \"command\": \"ssh\", +> +> \"args\": \[\"root@46.225.166.142\", +> +> \"docker exec -i lifeos-mcp python mcp_server.py\"\], +> +> \"env\": { \"MCP_API_KEY\": \"your-secret-key\" } +> +> } +> +> } +> +> } + + ----------------------------------------------------------------------- + **14. Security Architecture** + + ----------------------------------------------------------------------- + +Single-user, self-hosted system. Security requirements are pragmatic, +not enterprise-grade. The primary threats are unauthorized external +access and accidental data loss. + + ------------- --------------------------- ------------------------------ + **Layer** **Mechanism** **Notes** + + Transport HTTPS enforced via Nginx + HTTP redirects to HTTPS + Let\'s Encrypt + + Application No authentication in Phase Phase 3: basic auth or simple + access 1 (single user, private session login + server) + + MCP/AI access Static API key (X-MCP-Key Rotate via .env, never in git + header) required for all + MCP calls + + File access Files served via internal X-Accel-Redirect pattern + Nginx path, not public URL prevents directory traversal + + Database PostgreSQL on internal Not exposed to public internet + Docker network only + + Secrets All in .env file, never .gitignore enforced + committed + + Data safety Logical deletes, no 30-day backup retention + destructive ops without + admin confirmation + + Dependency SQLAlchemy sessions scoped No shared mutable state + injection per request + ------------- --------------------------- ------------------------------ + ++-----------------------------------------------------------------------+ +| **Phase 3 Authentication** | +| | +| If the application is ever exposed beyond the private server or | +| accessed by multiple users, add: HTTP basic auth as immediate | +| stopgap, then full session-based auth with Supabase Auth or a simple | +| JWT implementation. Row Level Security would need to be added to the | +| PostgreSQL schema at that point. | ++-----------------------------------------------------------------------+ + + ----------------------------------------------------------------------- + **15. Phase Build Plan** + + ----------------------------------------------------------------------- + + --------- --------------------------------------------------------------- + **PHASE **Full Working Application** + 1** + + --------- --------------------------------------------------------------- + +Everything a user needs to manage their professional and personal life +daily. Deployed to DEV, tested, then promoted to PROD with migrated +data. + + ----------------------------------------------------------------------- + **Step 1 - Foundation (1-2 days)** + + ----------------------------------------------------------------------- + +1. Apply R1 PostgreSQL schema to lifeos_dev + +2. Run data migration script: R0 -\> R1 field mapping + +3. Verify migrated data: 3 domains, 10 areas, 18 projects, 73 tasks + +4. Stand up Docker stack: lifeos-db, lifeos-prod, lifeos-dev + +5. Configure Nginx for both domains + +6. Obtain SSL certificates via Certbot + +7. Verify HTTPS access to both domains + +8. Build: core/database.py, core/base_repository.py, + core/generic_router.py + +9. Build: config/ YAML files (entities.yaml, menu.yaml) + +10. Build: base.html shell with sidebar, topbar, theme classes + +11. Build: \_list.html, \_form.html, \_empty.html generic templates + + ----------------------------------------------------------------------- + **Step 2 - Config-Driven Entities (1 day)** + + ----------------------------------------------------------------------- + +12. Wire all 12 config-driven entities through generic_router + +13. Domains, areas, context_types, weblinks, weblink_folders, + note_folders, time_budgets, task_templates, task_template_items, + milestones, release_domains, release_projects + +14. Verify CRUD for all 12 entities + + ----------------------------------------------------------------------- + **Step 3 - Core Task and Project Management (3-4 days)** + + ----------------------------------------------------------------------- + +15. Tasks: full CRUD, subtasks, priority, status, context, tags, + estimates, energy, waiting_for + +16. Projects: CRUD, progress calculation, status management + +17. Daily focus: date-scoped list, drag reorder, timer per task + +18. Dependencies: DAG implementation, cycle detection, status cascade + +19. Task templates: instantiation with subtask generation + +20. Bulk actions: mark done, move, delete, add to focus + +21. Overdue visual treatment, relative date language system + + ----------------------------------------------------------------------- + **Step 4 - Knowledge and Content (2-3 days)** + + ----------------------------------------------------------------------- + +22. Notes: rich text editor, folders, M2M projects, wiki-linking \[\[ + +23. Decisions: CRUD, project/contact links, supersession chain + +24. Files: upload, download, inline preview (images + PDFs) + +25. Lists and list items: CRUD, checklist completion + +26. Links and weblinks: CRUD, folder organization + + ----------------------------------------------------------------------- + **Step 5 - Meetings, Contacts, CRM (2 days)** + + ----------------------------------------------------------------------- + +27. Meetings: agenda, transcript, notes, action items -\> tasks + +28. Contacts: CRUD, associations with roles + +29. Appointments: CRUD, calendar integration + +30. Follow-up reminders: per-contact, dashboard surfacing + +31. Meeting series via parent_id + + ----------------------------------------------------------------------- + **Step 6 - Processes and Releases (2 days)** + + ----------------------------------------------------------------------- + +32. Processes: workflow vs checklist type, step management + +33. Process runs: template snapshot, task generation, step completion + +34. Releases: system-level CRUD, M2M project associations + +35. Release detail: aggregate progress across projects, milestone + display + +36. Task release_id assignment, backlog view + + ----------------------------------------------------------------------- + **Step 7 - Time Management (2 days)** + + ----------------------------------------------------------------------- + +37. Time tracking: start/stop timer, topbar pill, time_entries + +38. Time blocks: create on calendar view, context/energy fields + +39. Time budgets: domain weekly targets, overcommitment surfacing + +40. Eisenhower matrix view + +41. Dashboard: today estimate vs available, weekly metrics widget + + ----------------------------------------------------------------------- + **Step 8 - Search and Capture (1-2 days)** + + ----------------------------------------------------------------------- + +42. Global search: tsvector setup on all tables, Cmd/K modal + +43. Scoped search within project views + +44. Capture: multi-line paste parse, context pre-fill, convert to any + type + +45. Capture bulk undo via import_batch_id + + ----------------------------------------------------------------------- + **Step 9 - UX Polish and Admin (1-2 days)** + + ----------------------------------------------------------------------- + +46. Admin Trash: all soft-deleted entities, restore, permanent delete + +47. Admin context types manager + +48. Empty states on all list views + +49. Skeleton loading screens + +50. Toast notification system + +51. Confirmation dialogs for destructive actions + +52. CSV export: tasks, projects, contacts, decisions + +53. Dashboard: focus list, deadlines, calendar, metrics, reminders + widgets + +54. Calendar view: appointments + meetings + task due dates + + ----------------------------------------------------------------------- + **Step 10 - Promotion to Production** + + ----------------------------------------------------------------------- + +55. Apply schema to lifeos_prod + +56. Run data migration on lifeos_prod + +57. Smoke test all views on production data + +58. Configure automated daily backup cron job + +59. Document final deployed state + + --------- --------------------------------------------------------------- + **PHASE **DAG Visualization and MCP/AI Gateway** + 2** + + --------- --------------------------------------------------------------- + +- DAG node graph visualization on project view (tasks as nodes, + dependencies as edges) + +- Critical path calculation and highlighting + +- MCP server container: Python MCP server with shared tool core + +- OpenAI-compatible /tools/openai endpoint on same container + +- Model registry YAML configurable from Admin UI + +- API key authentication for MCP + +- Nginx routing for /ai/ path + +- Claude Desktop connection config + +- Note version history (note_version_history table) + +- Pipeline / deal stages for CRM contacts + +- Browser extension design and scoping + + --------- --------------------------------------------------------------- + **PHASE **Polish and Advanced Features** + 3** + + --------- --------------------------------------------------------------- + +- AI-assisted import: unstructured paste -\> LLM -\> structured + preview -\> confirm + +- Dark/light theme switcher in UI (data-theme toggle, localStorage, + Phase 1 has CSS ready) + +- Mobile swipe actions on task rows: complete, delete, add to focus + +- Export: JSON (full data dump), PDF (reports), Markdown (notes) + +- Full keyboard navigation: tab order, arrow keys, shortcuts (N, D, F, + Enter) + +- Browser extension for weblink capture + +- Habit tracking subsystem + +- Goals/OKRs hierarchy above domains + +- External calendar sync (Google Calendar / Outlook) - OAuth, webhooks + +- Pre/post meeting AI summaries (requires Phase 2 MCP) + +- Basic application authentication (session-based login) + + ----------------------------------------------------------------------- + **16. Migration Plan (R0 to R1)** + + ----------------------------------------------------------------------- + +**16.1 Current State** + + ---------------- ------------------------------------------------------ + **R0 data lifeos_prod on defiant-01 PostgreSQL container + location** + + **Migrated 3 domains, 10 areas, 18 projects, 73 tasks, 2 notes, 5 + records** links, 5 daily_focus, 80 capture, 6 context_types + + **Files** Empty (Supabase Storage URLs obsolete - file uploads + start fresh in R1) + + **R0 Supabase client, Render hosting - decommissioned after + application** R1 promotion + ---------------- ------------------------------------------------------ + +**16.2 Key Transformations Required** + +- notes.content_format: update all R0 \'markdown\' values to \'rich\' + +- All tables: add is_deleted=false, deleted_at=null, sort_order + sequential by created_at + +- tasks: add release_id=null, estimated_minutes=null, + energy_required=null, waiting_for_contact_id=null + +- notes: add folder_id=null, is_meeting_note=false, meeting_id=null, + title NOT NULL (fill empty titles with \'Untitled Note\') + +- capture: add converted_to_type=null, converted_to_id=null, + import_batch_id=null + +- context_types: add sort_order, is_deleted=false + +**16.3 Migration Script Approach** + +> \# migration/r0_to_r1.py +> +> \# 1. Connect to lifeos_prod (already populated with R0 data) +> +> \# 2. ALTER TABLE statements add new R1 columns +> +> \# 3. UPDATE statements set default values for new columns +> +> \# 4. Create all new R1 tables (empty) +> +> \# 5. Create indexes and tsvector triggers +> +> \# 6. Populate context_types with system defaults +> +> \# 7. Create built-in Weekly Review process template +> +> \# 8. Verify row counts match expected + +Migration runs against lifeos_dev first. Once verified, same script +applies to lifeos_prod. Total migration time expected under 5 minutes +for current data volume. + + ----------------------------------------------------------------------- + **17. Appendix: Complete Table Inventory** + + ----------------------------------------------------------------------- + + ---------------------- -------------- --------------------------------------- + **Table** **Category** **Key FKs / Notes** + + domains Core hierarchy No parent + + areas Core hierarchy domain_id + + projects Core hierarchy domain_id, area_id (opt) + + tasks Core hierarchy domain_id, area_id, project_id, + release_id, parent_id, + waiting_for_contact_id (all opt) + + notes Core hierarchy domain_id, project_id, folder_id, + meeting_id (all opt) + + note_folders Core hierarchy parent_id self-ref + + lists Core hierarchy domain_id, area_id, project_id (all + opt) + + list_items Core hierarchy list_id, parent_item_id self-ref + + links Core hierarchy domain_id, project_id + + files Core hierarchy Associations via file_mappings junction + + contacts System level No parent + + appointments System level Associations via contact_appointments + + meetings System level parent_id self-ref for series + + decisions System level meeting_id (opt), superseded_by_id + self-ref + + releases System level M2M via release_projects, + release_domains + + milestones System level release_id (opt), project_id (opt) + + processes System level process_type: workflow\|checklist + + process_steps System level process_id + + process_runs System level process_id, project_id (opt), + contact_id (opt) + + process_run_steps System level run_id - content immutable after run + start + + daily_focus System level task_id, focus_date + + capture System level Polymorphic converted_to_type/id + + task_templates System level Instantiated to create tasks+subtasks + + task_template_items System level template_id + + time_entries Time mgmt task_id - start/stop timer records + + time_blocks Time mgmt task_id (opt) - calendar slots + + time_budgets Time mgmt domain_id - weekly hours target + + weblink_folders System level parent_id self-ref + + weblinks System level M2M via folder_weblinks + + context_types Lookup SERIAL pk, is_system flag + + reminders System level Polymorphic entity_type/entity_id + + dependencies Universal Polymorphic blocker+dependent, 4 types + junction + + note_projects Junction note_id, project_id, is_primary + + note_links Junction source_note_id, target_note_id - wiki + graph + + file_mappings Junction file_id, context_type, context_id + + release_projects Junction release_id, project_id + + release_domains Junction release_id, domain_id + + contact_tasks Junction contact_id, task_id, role + + contact_projects Junction contact_id, project_id, role + + contact_lists Junction contact_id, list_id, role + + contact_list_items Junction contact_id, list_item_id, role + + contact_appointments Junction contact_id, appointment_id, role + + contact_meetings Junction contact_id, meeting_id, role + + decision_projects Junction decision_id, project_id + + decision_contacts Junction decision_id, contact_id, role + + meeting_tasks Junction meeting_id, task_id, source + + process_run_tasks Junction run_step_id, task_id + + folder_weblinks Junction folder_id, weblink_id + + note_version_history Phase 2 note_id, body snapshot, version_num + + pipelines Phase 2 CRM deal stage tracking + ---------------------- -------------- --------------------------------------- + +*Life OS Architecture Design Document \| Version 2.0 \| February 2026 \| +Approved for Build* diff --git a/project-docs/lifeos-conversation-context-convo-test1.md b/project-docs/lifeos-conversation-context-convo-test1.md new file mode 100644 index 0000000..a1a3a5a --- /dev/null +++ b/project-docs/lifeos-conversation-context-convo-test1.md @@ -0,0 +1,57 @@ +# Life OS - Conversation Context (Test Infrastructure - Convo Test1) + +## What This Is +Life OS is my personal productivity web application, live at https://lifeos-dev.invixiom.com on my self-hosted Hetzner server (defiant-01, 46.225.166.142). Convos 1-4 built 18 routers covering hierarchy, tasks, knowledge, daily workflows, search, admin, meetings, decisions, weblinks, appointments, and time tracking. Convo Test1 built a dynamic, introspection-based automated test suite that discovers routes from the live FastAPI app at runtime -- no hardcoded routes anywhere. + +## How to Use the Project Documents + +**lifeos-development-status-test1.md** - START HERE. Source of truth for the test infrastructure: what's deployed, how it works, what state it's in, and what to do next. + +**lifeos-development-status-convo4.md** - Application source of truth. What's built, routers, templates, deploy patterns, remaining features. The test suite tests THIS application. + +**lifeos-architecture.docx** - Full system specification. 50 tables, all subsystems. Reference when adding seed data for new entities. + +**lifeos_r1_full_schema.sql** - Intended R1 schema. The test DB is cloned from the live dev DB (not this file), so always verify against: `docker exec lifeos-db psql -U postgres -d lifeos_dev -c "\d table_name"` + +**life-os-server-config.docx** - Server infrastructure: containers, ports, Docker networks, Nginx, SSL. + +## Current Tech Stack +- Python 3.12 / FastAPI / SQLAlchemy 2.0 async (raw SQL via text(), no ORM models) / asyncpg +- Jinja2 server-rendered templates, vanilla HTML/CSS/JS, no build pipeline +- PostgreSQL 16 in Docker, full-text search via tsvector +- Dark/light theme via CSS custom properties +- Container runs with hot reload (code mounted as volume) +- GitHub repo: mdombaugh/lifeos-dev (main branch) + +## Key Patterns (Application) +- BaseRepository handles all CRUD with soft deletes (is_deleted filtering automatic) +- Every route calls get_sidebar_data(db) for the nav tree +- Forms use standard HTML POST with 303 redirect (PRG pattern) +- Templates extend base.html +- Exception: time_entries has no updated_at column, so use direct SQL for deletes instead of BaseRepository.soft_delete() +- Timer state: get_running_task_id() helper in routers/tasks.py queries time_entries WHERE end_at IS NULL + +## Key Patterns (Test Suite) +- Tests introspect `app.routes` at import time to discover all paths, methods, Form() fields, and path params +- Dynamic tests auto-parametrize from the route registry -- adding a new router requires zero test file changes for smoke/CRUD coverage +- Business logic tests (timer constraints, soft delete behavior, search safety) are hand-written in test_business_logic.py +- Test DB: `lifeos_test` -- schema cloned from `lifeos_dev` via pg_dump on each deploy +- Per-test isolation: each test runs inside a transaction that rolls back +- Seed data: 15 entity fixtures inserted via raw SQL, composite `all_seeds` fixture +- `PREFIX_TO_SEED` in registry.py maps route prefixes to seed fixture keys for dynamic path resolution +- Form data auto-generated from introspected Form() signatures via form_factory.py + +## Deploy Cycle (Application) +Code lives at /opt/lifeos/dev/ on the server. The container mounts this directory and uvicorn --reload picks up changes. No rebuild needed for code changes. Claude creates deploy scripts with heredocs that are uploaded via SCP and run with bash. + +## Deploy Cycle (Tests) +```bash +scp deploy-tests.sh root@46.225.166.142:/opt/lifeos/dev/ +ssh root@46.225.166.142 +cd /opt/lifeos/dev && bash deploy-tests.sh +docker exec lifeos-dev bash /app/tests/run_tests.sh report # Verify introspection +docker exec lifeos-dev bash /app/tests/run_tests.sh # Full suite +``` + +## What I Need Help With +[State your current task here] diff --git a/project-docs/lifeos-conversation-context-convo4.md b/project-docs/lifeos-conversation-context-convo4.md new file mode 100644 index 0000000..7e1f2cd --- /dev/null +++ b/project-docs/lifeos-conversation-context-convo4.md @@ -0,0 +1,42 @@ +# Life OS - Conversation Context (Convo 4) + +## What This Is +Life OS is my personal productivity web application, live at https://lifeos-dev.invixiom.com on my self-hosted Hetzner server (defiant-01, 46.225.166.142). Convo 1 built the foundation (9 entity routers). Convo 2 added 7 more routers (search, trash, lists, files, meetings, decisions, weblinks). Convo 3 began Tier 3 (Time & Process subsystems), completing Appointments CRUD and Time Tracking with topbar timer pill. Convo 4 completed the time tracking UX by adding timer play/stop buttons to task list rows and task detail pages. + +## How to Use the Project Documents + +**lifeos-development-status-convo4.md** - START HERE. Source of truth for what's built, what's remaining, exact deploy state, file locations, and patterns to follow. Read this before doing any work. + +**lifeos-architecture.docx** - Full system specification. 50 tables, all subsystems, UI patterns, component library, frontend design tokens, search architecture, time management logic, AI/MCP design (Phase 2). Reference when building new features. + +**lifeos_r1_full_schema.sql** - The complete intended R1 schema including all tables, indexes, triggers. Verify against the live database when in doubt: `docker exec lifeos-db psql -U postgres -d lifeos_dev -c "\d table_name"` + +**life-os-server-config.docx** - Server infrastructure: containers, ports, Docker networks, Nginx, SSL. Key detail: lifeos Nginx blocks use cert path `kasm.invixiom.com-0001` (not `kasm.invixiom.com`). + +**Previous conversation docs** - Convo 3 and earlier docs are superseded by Convo 4 docs but provide historical context if needed. + +## Current Tech Stack +- Python 3.12 / FastAPI / SQLAlchemy 2.0 async (raw SQL via text(), no ORM models) / asyncpg +- Jinja2 server-rendered templates, vanilla HTML/CSS/JS, no build pipeline +- PostgreSQL 16 in Docker, full-text search via tsvector +- Dark/light theme via CSS custom properties +- Container runs with hot reload (code mounted as volume) +- GitHub repo: mdombaugh/lifeos-dev (main branch) + +## Key Patterns +- BaseRepository handles all CRUD with soft deletes (is_deleted filtering automatic) +- Every route calls get_sidebar_data(db) for the nav tree +- Forms use standard HTML POST with 303 redirect (PRG pattern) +- Templates extend base.html +- New routers: create file in routers/, add import + include_router in main.py, add nav link in base.html sidebar, create list/form/detail templates +- Search: add entity config to SEARCH_ENTITIES in routers/search.py +- Trash: add entity config to TRASH_ENTITIES in routers/admin.py +- Nullable fields for BaseRepository.update(): add to nullable_fields set in core/base_repository.py +- Exception: time_entries has no updated_at column, so use direct SQL for deletes instead of BaseRepository.soft_delete() +- Timer state: get_running_task_id() helper in routers/tasks.py queries time_entries WHERE end_at IS NULL + +## Deploy Cycle +Code lives at /opt/lifeos/dev/ on the server. The container mounts this directory and uvicorn --reload picks up changes. No rebuild needed for code changes. Claude creates deploy scripts with heredocs that are uploaded via SCP and run with bash. GitHub repo is mdombaugh/lifeos-dev. Push with PAT (personal access token) as password. + +## What I Need Help With +[State your current task here] diff --git a/project-docs/lifeos-database-backup.md b/project-docs/lifeos-database-backup.md new file mode 100644 index 0000000..a72a40c --- /dev/null +++ b/project-docs/lifeos-database-backup.md @@ -0,0 +1,44 @@ +# Life OS - Database Backup & Restore + +## Quick Backup + +```bash +docker exec lifeos-db pg_dump -U postgres -d lifeos_dev -Fc -f /tmp/lifeos_dev_backup.dump +docker cp lifeos-db:/tmp/lifeos_dev_backup.dump /opt/lifeos/backups/lifeos_dev_$(date +%Y%m%d_%H%M%S).dump +``` + +## Quick Restore + +```bash +# Drop and recreate the database, then restore +docker exec lifeos-db psql -U postgres -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'lifeos_dev' AND pid <> pg_backend_pid();" +docker exec lifeos-db psql -U postgres -c "DROP DATABASE lifeos_dev;" +docker exec lifeos-db psql -U postgres -c "CREATE DATABASE lifeos_dev;" +docker cp /opt/lifeos/backups/FILENAME.dump lifeos-db:/tmp/restore.dump +docker exec lifeos-db pg_restore -U postgres -d lifeos_dev /tmp/restore.dump +docker restart lifeos-dev +``` + +Replace `FILENAME.dump` with the actual backup filename. + +## First-Time Setup + +Create the backups directory: + +```bash +mkdir -p /opt/lifeos/backups +``` + +## List Available Backups + +```bash +ls -lh /opt/lifeos/backups/ +``` + +## Notes + +- `-Fc` = custom format (compressed, supports selective restore) +- Backup includes schema + data + indexes + triggers + search vectors +- Restore terminates active connections first, then drops/recreates the DB +- Restart the app container after restore so connection pool reconnects +- lifeos_prod is untouched by these commands (only lifeos_dev) diff --git a/project-docs/lifeos-development-status-convo4.md b/project-docs/lifeos-development-status-convo4.md new file mode 100644 index 0000000..eb483f0 --- /dev/null +++ b/project-docs/lifeos-development-status-convo4.md @@ -0,0 +1,329 @@ +# Life OS - Development Status & Continuation Guide (Convo 4) + +**Last Updated:** 2026-02-28 +**Current State:** Phase 1 - Tier 3 in progress (2 of 6 features built, time tracking UX complete) +**GitHub:** mdombaugh/lifeos-dev (main branch) + +--- + +## 1. What Was Built in This Conversation + +### Timer Buttons on Task UI (DEPLOYED) +- Play/stop button on each non-completed task row in tasks.html (between checkbox and priority dot) +- Play/stop button in task_detail.html header action bar (before Edit/Complete buttons) +- Running task row gets green left border highlight via `.timer-active` CSS class +- `get_running_task_id()` helper in routers/tasks.py queries `time_entries WHERE end_at IS NULL` +- Both list_tasks and task_detail routes pass `running_task_id` to template context +- Buttons POST to existing `/time/start` and `/time/stop` endpoints, redirect back via referer +- Only shown on non-completed, non-cancelled tasks +- ~60 lines of CSS appended to style.css (timer-btn, timer-btn-play, timer-btn-stop, timer-active, timer-detail-btn) +- Deployed via heredoc shell script (deploy-timer-buttons.sh) + +This completes the Time Tracking feature. The full time tracking system is now: +- Start/stop timer per task from task list rows, task detail page, or time log page +- Topbar timer pill with green pulsing dot, task name link, live elapsed counter, stop button +- Auto-stop of running timer when starting a new one +- Manual time entry support +- Time log at /time with daily summaries, date-grouped entries, day filter +- Soft delete via direct SQL (time_entries lacks updated_at column) + +### What Was NOT Built (deferred to Convo 5) +- **Processes / process_runs** - Most complex Tier 3 feature. 4 tables. Deferred due to usage limits. +- **Calendar view** - Unified read-only view +- **Time budgets** - Simple CRUD +- **Eisenhower matrix** - Derived view + +--- + +## 2. Complete Application Inventory + +### 2.1 Infrastructure (unchanged) + +| Component | Status | Details | +|-----------|--------|---------| +| Server | LIVE | defiant-01, Hetzner, 46.225.166.142, Ubuntu 24.04 | +| Docker network | LIVE | `lifeos_network` (172.21.0.0/16) | +| PostgreSQL | LIVE | Container `lifeos-db`, postgres:16-alpine, volume `lifeos_db_data` | +| Databases | LIVE | `lifeos_prod` (R0 data, untouched), `lifeos_dev` (R1 schema + migrated data) | +| Application | LIVE | Container `lifeos-dev`, port 8003, image `lifeos-app` | +| Nginx | LIVE | lifeos-dev.invixiom.com -> localhost:8003 | +| SSL | LIVE | Let's Encrypt cert at `/etc/letsencrypt/live/kasm.invixiom.com-0001/` | +| GitHub | PUSHED | Convo 3 changes pushed. Convo 4 changes need push (see section 4.2). | + +### 2.2 Core Modules + +- `core/database.py` - Async engine, session factory, get_db dependency +- `core/base_repository.py` - Generic CRUD: list, get, create, update, soft_delete, restore, permanent_delete, bulk_soft_delete, reorder, count, list_deleted. Has `nullable_fields` set for update() null handling. +- `core/sidebar.py` - Domain > area > project nav tree, capture/focus badge counts +- `main.py` - FastAPI app, dashboard, health check, 18 router includes + +### 2.3 Routers (18 total) + +| Router | Prefix | Templates | Status | +|--------|--------|-----------|--------| +| domains | /domains | domains, domain_form | Convo 1 | +| areas | /areas | areas, area_form | Convo 1 | +| projects | /projects | projects, project_form, project_detail | Convo 1 | +| tasks | /tasks | tasks, task_form, task_detail | Convo 1, **updated Convo 4** | +| notes | /notes | notes, note_form, note_detail | Convo 1 | +| links | /links | links, link_form | Convo 1 | +| focus | /focus | focus | Convo 1 | +| capture | /capture | capture | Convo 1 | +| contacts | /contacts | contacts, contact_form, contact_detail | Convo 1 | +| search | /search | search | Convo 2 | +| admin | /admin/trash | trash | Convo 2 | +| lists | /lists | lists, list_form, list_detail | Convo 2 | +| files | /files | files, file_upload, file_preview | Convo 2 | +| meetings | /meetings | meetings, meeting_form, meeting_detail | Convo 2 | +| decisions | /decisions | decisions, decision_form, decision_detail | Convo 2 | +| weblinks | /weblinks | weblinks, weblink_form, weblink_folder_form | Convo 2 | +| appointments | /appointments | appointments, appointment_form, appointment_detail | Convo 3 | +| time_tracking | /time | time_entries | Convo 3 | + +### 2.4 Templates (42 total, unchanged from Convo 3) + +base.html, dashboard.html, search.html, trash.html, +tasks.html, task_form.html, task_detail.html, +projects.html, project_form.html, project_detail.html, +domains.html, domain_form.html, +areas.html, area_form.html, +notes.html, note_form.html, note_detail.html, +links.html, link_form.html, +focus.html, capture.html, +contacts.html, contact_form.html, contact_detail.html, +lists.html, list_form.html, list_detail.html, +files.html, file_upload.html, file_preview.html, +meetings.html, meeting_form.html, meeting_detail.html, +decisions.html, decision_form.html, decision_detail.html, +weblinks.html, weblink_form.html, weblink_folder_form.html, +appointments.html, appointment_form.html, appointment_detail.html, +time_entries.html + +### 2.5 Static Assets + +- `style.css` - ~1040 lines (timer button CSS appended in Convo 4) +- `app.js` - ~190 lines (timer pill polling from Convo 3, unchanged in Convo 4) + +--- + +## 3. How the Container Runs + +```bash +docker run -d \ + --name lifeos-dev \ + --network lifeos_network \ + --restart unless-stopped \ + --env-file .env \ + -p 8003:8003 \ + -v /opt/lifeos/dev/files:/opt/lifeos/files/dev \ + -v /opt/lifeos/dev:/app \ + lifeos-app \ + uvicorn main:app --host 0.0.0.0 --port 8003 --workers 1 --reload +``` + +**Environment (.env):** +``` +DATABASE_URL=postgresql+asyncpg://postgres:UCTOQDZiUhN8U@lifeos-db:5432/lifeos_dev +FILE_STORAGE_PATH=/opt/lifeos/files/dev +ENVIRONMENT=development +``` + +Deploy: edit files in `/opt/lifeos/dev/`, hot reload picks them up. +Restart: `docker restart lifeos-dev` +Logs: `docker logs lifeos-dev --tail 30` + +--- + +## 4. Known Issues + +### 4.1 Immediate +1. **Not yet tested by user** - Timer buttons deployed but user testing still pending. May have bugs. +2. **Convo 4 changes not pushed to GitHub** - Run: `cd /opt/lifeos/dev && git add . && git commit -m "Timer buttons on task rows and detail" && git push origin main` + +### 4.2 Technical Debt +1. **time_entries missing `updated_at`** - Table lacks this column so BaseRepository methods that set updated_at will fail. Direct SQL used for soft_delete. If adding time_entries to TRASH_ENTITIES, restore will also need direct SQL. +2. **R1 schema file mismatch** - lifeos_schema_r1.sql in project doesn't reflect actual DB. Query DB directly to verify. +3. **No CSRF protection** - Single-user system, low risk. +4. **No pagination** - All list views load all rows. Fine at current scale. +5. **Font loading** - Google Fonts @import is render-blocking. + +--- + +## 5. What's NOT Built Yet + +### Tier 3 Remaining (4 features) +1. **Processes / process_runs** - Most complex Tier 3 feature. 4 tables: processes, process_steps, process_runs, process_run_steps. Template CRUD, run instantiation (copies steps as immutable snapshot), step completion tracking, task generation modes (all_at_once vs step_by_step). START HERE in Convo 5. +2. **Calendar view** - Unified `/calendar` page showing appointments (start_at) + meetings (meeting_date) + tasks (due_date). No new tables, read-only derived view. Filter by date range, domain, type. +3. **Time budgets** - Simple CRUD: domain_id + weekly_hours + effective_from. Used for overcommitment warnings on dashboard. +4. **Eisenhower matrix** - Derived 2x2 grid from task priority + due_date. Quadrants: Important+Urgent (priority 1-2, due <=7d), Important+Not Urgent (priority 1-2, due >7d), Not Important+Urgent (priority 3-4, due <=7d), Not Important+Not Urgent (priority 3-4, due >7d or null). Clickable to filter task list. + +### Tier 4 - Advanced Features +- Releases / milestones +- Dependencies (DAG, cycle detection, status cascade) +- Task templates (instantiation with subtask generation) +- Note wiki-linking ([[ syntax) +- Note folders +- Bulk actions (multi-select, bulk complete/move/delete) +- CSV export +- Drag-to-reorder (SortableJS) +- Reminders +- Weekly review process template +- Dashboard metrics (weekly/monthly completion stats) + +### UX Polish +- Breadcrumb navigation (partially done, inconsistent) +- Overdue visual treatment (red left border on task rows) +- Empty states with illustrations (basic emoji states exist) +- Skeleton loading screens +- Toast notification system +- Confirmation dialogs (basic confirm() exists, no modal) +- Mobile bottom tab bar +- Mobile responsive improvements + +--- + +## 6. File Locations on Server + +``` +/opt/lifeos/ + dev/ # DEV application (mounted as /app in container) + main.py # 18 router includes + core/ + __init__.py + database.py + base_repository.py + sidebar.py + routers/ + __init__.py + domains.py, areas.py, projects.py, tasks.py + notes.py, links.py, focus.py, capture.py, contacts.py + search.py, admin.py, lists.py + files.py, meetings.py, decisions.py, weblinks.py + appointments.py + time_tracking.py + templates/ + base.html, dashboard.html, search.html, trash.html + tasks.html, task_form.html, task_detail.html + projects.html, project_form.html, project_detail.html + domains.html, domain_form.html + areas.html, area_form.html + notes.html, note_form.html, note_detail.html + links.html, link_form.html + focus.html, capture.html + contacts.html, contact_form.html, contact_detail.html + lists.html, list_form.html, list_detail.html + files.html, file_upload.html, file_preview.html + meetings.html, meeting_form.html, meeting_detail.html + decisions.html, decision_form.html, decision_detail.html + weblinks.html, weblink_form.html, weblink_folder_form.html + appointments.html, appointment_form.html, appointment_detail.html + time_entries.html + static/ + style.css (~1040 lines) + app.js (~190 lines) + Dockerfile + requirements.txt + .env + backups/ # Database backups +``` + +--- + +## 7. How to Continue Development + +### Recommended build order for Convo 5: +1. **Processes / process_runs** (most complex remaining feature - do first with full usage window) +2. **Calendar view** (combines appointments + meetings + tasks) +3. **Time budgets** (simple CRUD) +4. **Eisenhower matrix** (derived view, quick win) + +### Adding a new entity router (pattern): +1. Create `routers/entity_name.py` following existing router patterns +2. Add import + `app.include_router()` in `main.py` +3. Create templates: list, form, detail (all extend base.html) +4. Add nav link in `templates/base.html` sidebar section +5. Add to `SEARCH_ENTITIES` in `routers/search.py` (if searchable) +6. Add to `TRASH_ENTITIES` in `routers/admin.py` (if soft-deletable) +7. Add any new nullable fields to `nullable_fields` in `core/base_repository.py` +8. Use `BaseRepository("table_name", db)` for all CRUD +9. Always call `get_sidebar_data(db)` and pass to template context + +### Deploy cycle: +```bash +# Files are created locally by Claude, packaged as a deploy script with heredocs +# Upload to server, run the script +scp deploy-script.sh root@46.225.166.142:/opt/lifeos/dev/ +ssh root@46.225.166.142 +cd /opt/lifeos/dev && bash deploy-script.sh + +# Commit +git add . && git commit -m "description" && git push origin main +``` + +### Database backup: +```bash +mkdir -p /opt/lifeos/backups +docker exec lifeos-db pg_dump -U postgres -d lifeos_dev -Fc -f /tmp/lifeos_dev_backup.dump +docker cp lifeos-db:/tmp/lifeos_dev_backup.dump /opt/lifeos/backups/lifeos_dev_$(date +%Y%m%d_%H%M%S).dump +``` + +### Key code patterns: +- Every route: `sidebar = await get_sidebar_data(db)` +- Forms POST to /create or /{id}/edit, redirect 303 +- Filters: query params, auto-submit via JS onchange +- Detail views: breadcrumb nav at top +- Toggle/complete: inline form with checkbox onchange +- Junction tables: raw SQL INSERT with ON CONFLICT DO NOTHING +- File upload: multipart form, save to FILE_STORAGE_PATH, record in files table +- Timer: POST /time/start with task_id, POST /time/stop, GET /time/running (JSON for topbar pill) +- Timer buttons: get_running_task_id() helper in tasks.py, play/stop inline forms on task rows + +--- + +## 8. Tier 3 Architecture Reference + +### Processes / Process Runs (BUILD NEXT) +**Tables:** processes, process_steps, process_runs, process_run_steps + +**Flow:** +1. Create a process template (processes) with ordered steps (process_steps) +2. Instantiate a run (process_runs) - copies all process_steps to process_run_steps as immutable snapshots +3. Steps in a run can be completed, which records completed_by_id and completed_at +4. Task generation modes: `all_at_once` creates all tasks when run starts, `step_by_step` creates next task only when current step completes +5. Template changes after run creation do NOT affect active runs (snapshot pattern) + +**Schema notes:** +- processes: id, name, description, process_type (workflow|checklist), category, status, tags, search_vector +- process_steps: id, process_id, title, instructions, expected_output, estimated_days, context, sort_order +- process_runs: id, process_id, title, status, process_type (copied from template), task_generation, project_id, contact_id, started_at, completed_at +- process_run_steps: id, run_id, title, instructions (immutable), status, completed_by_id, completed_at, notes, sort_order + +### Calendar View +- Unified read-only page at `/calendar` +- Show appointments (start_at), meetings (meeting_date + start_at), tasks (due_date) +- Filter by date range, domain, type +- No new tables needed + +### Time Budgets +- Simple CRUD: domain_id + weekly_hours + effective_from +- Dashboard warning when domain time_entries exceed budget + +### Eisenhower Matrix +- Derived from task priority (1-4) + due_date +- Quadrants: Important+Urgent, Important+Not Urgent, Not Important+Urgent, Not Important+Not Urgent +- Priority 1-2 = Important, Priority 3-4 = Not Important +- Due <= 7 days or overdue = Urgent, Due > 7 days or no date = Not Urgent +- Rendered as 2x2 grid, clicking quadrant filters to task list + +--- + +## 9. Production Deployment (Not Yet Done) + +When ready to go to PROD: +1. Apply R1 schema to lifeos_prod +2. Run data migration on lifeos_prod +3. Build and start lifeos-prod container on port 8002 +4. Nginx already has lifeos.invixiom.com block pointing to 8002 +5. SSL cert already covers lifeos.invixiom.com +6. Set ENVIRONMENT=production in prod .env +7. Set up daily backup cron job diff --git a/project-docs/lifeos-development-status-test1.md b/project-docs/lifeos-development-status-test1.md new file mode 100644 index 0000000..e205c50 --- /dev/null +++ b/project-docs/lifeos-development-status-test1.md @@ -0,0 +1,261 @@ +# Life OS - Development Status & Continuation Guide (Test Infrastructure - Convo Test1) + +**Last Updated:** 2026-03-01 +**Current State:** Test suite deployed, introspection verified (121 routes discovered), first test run pending +**GitHub:** mdombaugh/lifeos-dev (main branch) + +--- + +## 1. What Was Built in This Conversation + +### Dynamic Introspection-Based Test Suite (DEPLOYED) + +Built and deployed an automated test suite that discovers routes from the live FastAPI app at runtime. Zero hardcoded routes. When a new router is added, smoke and CRUD tests auto-expand on next run. + +**Architecture (11 files in /opt/lifeos/dev/tests/):** + +| File | Purpose | Lines | +|------|---------|-------| +| introspect.py | Route discovery engine: walks app.routes, extracts paths/methods/Form() fields/path params, classifies routes | 357 | +| form_factory.py | Generates valid POST form data from introspected Form() signatures + seed data UUIDs | 195 | +| registry.py | Imports app, runs introspection once, exposes route registry + PREFIX_TO_SEED mapping + resolve_path() | 79 | +| conftest.py | Fixtures only: test DB engine, per-test rollback session, httpx client, 15 seed data fixtures, all_seeds composite | 274 | +| test_smoke_dynamic.py | 3 parametrized functions expanding to ~59 tests: all GETs (no params) return 200, all GETs (with seed ID) return 200, all detail/edit GETs (fake UUID) return 404 | 100 | +| test_crud_dynamic.py | 5 parametrized functions expanding to ~62 tests: all POST create/edit/delete redirect 303, all actions non-500, create-then-verify-in-list | 161 | +| test_business_logic.py | 16 hand-written tests: timer single-run constraint, stop sets end_at, soft delete/restore visibility, search SQL injection, sidebar integrity, focus/capture workflows, edge cases | 212 | +| route_report.py | CLI tool: dumps all discovered routes with classification, form fields, seed mapping coverage | 65 | +| run_tests.sh | Test runner with aliases: smoke, crud, logic, report, fast, full, custom args | 22 | +| __init__.py | Package marker | 0 | +| pytest.ini | Config: asyncio_mode=auto, verbose output, short tracebacks | 7 | + +**Key design decisions:** +- `registry.py` separated from `conftest.py` to avoid pytest auto-loading conflicts (test files import from registry, not conftest) +- Form() detection uses `__class__.__name__` check, not `issubclass()`, because FastAPI's `Form` is a function not a class +- Test DB schema cloned from live dev DB via pg_dump (not from stale SQL files) +- Seed data uses raw SQL INSERT matching actual table columns + +### Introspection Verification Results + +Deploy script step 4 confirmed: +``` +Routes discovered: 121 +GET (no params): 36 +GET (with params): 23 +POST create: 13 +POST edit: 13 +POST delete: 17 +POST action: 19 +Entity prefixes: 32 +``` + +### What Was NOT Done +- **First test run not yet executed** -- introspection works, tests deployed, but `run_tests.sh` has not been run yet +- **Seed data column mismatches likely** -- seed INSERTs written from architecture docs, not actual table inspection. First run will surface these as SQL errors +- **No test for file upload routes** -- file routes skipped (has_file_upload flag) because they need multipart handling + +--- + +## 2. Test Infrastructure Inventory + +### 2.1 Database + +| Component | Details | +|-----------|---------| +| Test DB | `lifeos_test` on lifeos-db container | +| Schema source | Cloned from `lifeos_dev` via `pg_dump --schema-only` | +| Tables | 48 (matches dev) | +| Isolation | Per-test transaction rollback (no data persists between tests) | +| Credentials | Same as dev: postgres:UCTOQDZiUhN8U | + +### 2.2 How Introspection Works + +1. `registry.py` imports `main.app` (sets DATABASE_URL to test DB first) +2. `introspect.py` walks `app.routes`, for each `APIRoute`: + - Extracts path, HTTP methods, endpoint function reference + - Parses `{id}` path parameters via regex + - Inspects endpoint function signature for `Form()` parameters (checks `default.__class__.__name__` for "FieldInfo") + - Extracts query parameters (non-Form, non-Depends, non-Request params) + - Classifies route: list / detail / create_form / edit_form / create / edit / delete / toggle / action / json / page +3. Builds `ROUTE_REGISTRY` dict keyed by kind (get_no_params, post_create, etc.) and by prefix +4. Test files parametrize from this registry at collection time + +### 2.3 How Dynamic Tests Work + +**Smoke (test_smoke_dynamic.py):** +```python +@pytest.mark.parametrize("path", [r.path for r in GET_NO_PARAMS]) +async def test_get_no_params_returns_200(client, path): + r = await client.get(path) + assert r.status_code == 200 +``` +N discovered GET routes = N smoke tests. No manual updates. + +**CRUD (test_crud_dynamic.py):** +- Collects all POST create/edit/delete routes from registry +- Calls `build_form_data(route.form_fields, all_seeds)` to generate valid payloads +- `form_factory.py` resolves FK fields to seed UUIDs, generates values by field name pattern +- Asserts 303 redirect for create/edit/delete, non-500 for actions + +**Business Logic (test_business_logic.py):** +- Hand-written, tests behavioral contracts not discoverable via introspection +- Timer: single running constraint, stop sets end_at, /time/running returns JSON +- Soft deletes: deleted task hidden from list, restore reappears +- Search: SQL injection doesn't crash, empty query works, unicode works +- Sidebar: domain appears on every page, project hierarchy renders +- Focus/capture: add to focus, multi-line capture creates multiple items +- Edge cases: invalid UUID, timer without task_id, double delete + +### 2.4 Seed Data Fixtures (15 entities) + +| Fixture | Table | Dependencies | Key Fields | +|---------|-------|-------------|------------| +| seed_domain | domains | none | id, name, color | +| seed_area | areas | seed_domain | id, domain_id | +| seed_project | projects | seed_domain, seed_area | id, domain_id, area_id | +| seed_task | tasks | seed_domain, seed_project | id, domain_id, project_id, title | +| seed_contact | contacts | none | id, first_name, last_name | +| seed_note | notes | seed_domain | id, domain_id, title | +| seed_meeting | meetings | none | id, title, meeting_date | +| seed_decision | decisions | seed_domain, seed_project | id, title | +| seed_appointment | appointments | seed_domain | id, title, start_at, end_at | +| seed_weblink_folder | weblink_folders | none | id, name | +| seed_list | lists | seed_domain, seed_project | id, name | +| seed_link | links | seed_domain | id, title, url | +| seed_weblink | weblinks | seed_weblink_folder | id, title, url | +| seed_capture | capture | none | id, raw_text | +| seed_focus | daily_focus | seed_task | id, task_id | + +### 2.5 PREFIX_TO_SEED Mapping + +Maps route prefixes to seed fixture keys so `resolve_path()` can replace `{id}` with real UUIDs: + +``` +/domains -> domain /contacts -> contact +/areas -> area /meetings -> meeting +/projects -> project /decisions -> decision +/tasks -> task /appointments -> appointment +/notes -> note /weblinks -> weblink +/links -> link /weblinks/folders -> weblink_folder +/lists -> list /focus -> focus +/capture -> capture /time -> task +/files -> None (skipped) /admin/trash -> None (skipped) +``` + +--- + +## 3. File Locations on Server + +``` +/opt/lifeos/dev/ + tests/ + __init__.py + introspect.py # Route discovery engine + form_factory.py # Form data generation + registry.py # Route registry + PREFIX_TO_SEED + resolve_path + conftest.py # Fixtures (DB, client, seeds) + route_report.py # CLI route dump + test_smoke_dynamic.py # Auto-parametrized GET tests + test_crud_dynamic.py # Auto-parametrized POST tests + test_business_logic.py # Hand-written behavioral tests + run_tests.sh # Test runner + pytest.ini # pytest config + deploy-tests.sh # Deployment script (can re-run to reset) +``` + +--- + +## 4. Known Issues & Expected First-Run Failures + +### 4.1 Likely Seed Data Mismatches +Seed INSERT statements were written from architecture docs, not from inspecting actual table columns. The first test run will likely produce errors like: +- `column "X" of relation "Y" does not exist` -- seed INSERT has a column the actual table doesn't have +- `null value in column "X" violates not-null constraint` -- seed INSERT is missing a required column + +**Fix process:** Run tests, read the SQL errors, adjust the INSERT in conftest.py to match actual columns (query with `\d table_name`), redeploy. + +### 4.2 Possible Form Field Discovery Gaps +Some routers may use patterns the introspection engine doesn't handle: +- `Annotated[str, Form()]` style (handled via `__metadata__` check, but untested against live code) +- Form fields with non-standard defaults +- Routes that accept both Form and query params + +The route report (`run_tests.sh report`) will show warnings for POST create/edit routes with zero discovered Form fields. Those need investigation. + +### 4.3 Route Classification Edge Cases +Some routes may be misclassified: +- Admin trash restore routes (`/admin/trash/restore/{entity}/{id}`) may not match the standard patterns +- Capture routes (`/capture/add`, `/capture/{id}/convert`, `/capture/{id}/dismiss`) use non-standard action patterns +- Focus routes (`/focus/add`, `/focus/{id}/remove`) are action routes, not standard CRUD + +These will show up as action route tests (non-500 assertion) rather than typed CRUD tests. + +### 4.4 Not Yet Pushed to GitHub +Test files need to be committed: `cd /opt/lifeos/dev && git add . && git commit -m "Dynamic test suite" && git push origin main` + +--- + +## 5. How to Continue (Convo Test2) + +### Immediate Next Steps +1. **Run the route report** to verify introspection output: + ```bash + docker exec lifeos-dev bash /app/tests/run_tests.sh report + ``` +2. **Run smoke tests first** (most likely to pass): + ```bash + docker exec lifeos-dev bash /app/tests/run_tests.sh smoke + ``` +3. **Fix seed data failures** by inspecting actual tables and adjusting conftest.py INSERTs +4. **Run CRUD tests** after seeds are fixed: + ```bash + docker exec lifeos-dev bash /app/tests/run_tests.sh crud + ``` +5. **Run business logic tests** last: + ```bash + docker exec lifeos-dev bash /app/tests/run_tests.sh logic + ``` +6. **Run full suite** once individual categories pass: + ```bash + docker exec lifeos-dev bash /app/tests/run_tests.sh + ``` + +### When Adding a New Entity Router +1. Add seed fixture to `conftest.py` (INSERT matching actual table columns) +2. Add entry to `PREFIX_TO_SEED` in `registry.py` +3. Run tests -- smoke and CRUD auto-expand to cover new routes +4. Add behavioral tests to `test_business_logic.py` if entity has constraints or state machines + +### When Schema Changes +Re-run `deploy-tests.sh` (step 1 drops and recreates lifeos_test from current dev schema). + +Or manually: +```bash +docker exec lifeos-db psql -U postgres -c "DROP DATABASE IF EXISTS lifeos_test;" +docker exec lifeos-db psql -U postgres -c "CREATE DATABASE lifeos_test;" +docker exec lifeos-db pg_dump -U postgres -d lifeos_dev --schema-only -f /tmp/s.sql +docker exec lifeos-db psql -U postgres -d lifeos_test -f /tmp/s.sql -q +``` + +### Test Runner Commands +```bash +docker exec lifeos-dev bash /app/tests/run_tests.sh # Full suite +docker exec lifeos-dev bash /app/tests/run_tests.sh report # Route introspection dump +docker exec lifeos-dev bash /app/tests/run_tests.sh smoke # All GET endpoints +docker exec lifeos-dev bash /app/tests/run_tests.sh crud # All POST create/edit/delete +docker exec lifeos-dev bash /app/tests/run_tests.sh logic # Business logic +docker exec lifeos-dev bash /app/tests/run_tests.sh fast # Smoke, stop on first fail +docker exec lifeos-dev bash /app/tests/run_tests.sh -k "timer" # pytest keyword filter +``` + +--- + +## 6. Application Development Remaining (Unchanged from Convo 4) + +### Tier 3 Remaining (4 features) +1. **Processes / process_runs** -- Most complex. 4 tables. Template CRUD, run instantiation, step completion, task generation. +2. **Calendar view** -- Unified read-only view of appointments + meetings + tasks. +3. **Time budgets** -- Simple CRUD: domain_id + weekly_hours + effective_from. +4. **Eisenhower matrix** -- Derived 2x2 grid from task priority + due_date. + +### Tier 4, UX Polish, Production Deployment +See lifeos-development-status-convo4.md sections 5, 8, 9. diff --git a/project-docs/lifeos-setup.sh b/project-docs/lifeos-setup.sh new file mode 100644 index 0000000..59eda66 --- /dev/null +++ b/project-docs/lifeos-setup.sh @@ -0,0 +1,263 @@ +#!/bin/bash +# ============================================================================= +# Life OS Infrastructure Setup Script +# Server: defiant-01 (46.225.166.142) - Ubuntu 24.04 LTS +# Run as: root +# Purpose: Repeatable setup of Life OS DEV and PROD environments on Hetzner VM +# ============================================================================= +# USAGE: +# Full run: bash lifeos-setup.sh +# Single section: bash lifeos-setup.sh network +# bash lifeos-setup.sh database +# bash lifeos-setup.sh app +# bash lifeos-setup.sh nginx +# bash lifeos-setup.sh ssl +# ============================================================================= + +set -e # Exit on any error + +# --- Configuration ----------------------------------------------------------- +LIFEOS_NETWORK="lifeos_network" +DB_CONTAINER="lifeos-db" +DB_IMAGE="postgres:16-alpine" +DB_PROD="lifeos_prod" +DB_DEV="lifeos_dev" +APP_PROD_CONTAINER="lifeos-prod" +APP_DEV_CONTAINER="lifeos-dev" +APP_PROD_PORT="8002" +APP_DEV_PORT="8003" +DOMAIN_PROD="lifeos.invixiom.com" +DOMAIN_DEV="lifeos-dev.invixiom.com" +CERT_PATH="/etc/letsencrypt/live/kasm.invixiom.com" +LIFEOS_DIR="/opt/lifeos" +# DB passwords - change these before running +DB_PROD_PASSWORD="CHANGE_ME_PROD" +DB_DEV_PASSWORD="CHANGE_ME_DEV" +# ----------------------------------------------------------------------------- + +section() { + echo "" + echo "==============================================" + echo " $1" + echo "==============================================" +} + +# ============================================================================= +# SECTION 1: Docker Network +# ============================================================================= +setup_network() { + section "SECTION 1: Docker Network" + + if docker network ls | grep -q "$LIFEOS_NETWORK"; then + echo "Network $LIFEOS_NETWORK already exists, skipping." + else + docker network create "$LIFEOS_NETWORK" + echo "Created network: $LIFEOS_NETWORK" + fi + + docker network ls | grep lifeos +} + +# ============================================================================= +# SECTION 2: PostgreSQL Container +# ============================================================================= +setup_database() { + section "SECTION 2: PostgreSQL Container" + + if docker ps -a | grep -q "$DB_CONTAINER"; then + echo "Container $DB_CONTAINER already exists, skipping creation." + else + docker run -d \ + --name "$DB_CONTAINER" \ + --network "$LIFEOS_NETWORK" \ + --restart unless-stopped \ + -e POSTGRES_PASSWORD="$DB_PROD_PASSWORD" \ + -v lifeos_db_data:/var/lib/postgresql/data \ + "$DB_IMAGE" + echo "Created container: $DB_CONTAINER" + + echo "Waiting for Postgres to be ready..." + sleep 5 + fi + + # Create PROD database + docker exec "$DB_CONTAINER" psql -U postgres -tc \ + "SELECT 1 FROM pg_database WHERE datname='$DB_PROD'" | grep -q 1 || \ + docker exec "$DB_CONTAINER" psql -U postgres \ + -c "CREATE DATABASE $DB_PROD;" + + # Create DEV database + docker exec "$DB_CONTAINER" psql -U postgres -tc \ + "SELECT 1 FROM pg_database WHERE datname='$DB_DEV'" | grep -q 1 || \ + docker exec "$DB_CONTAINER" psql -U postgres \ + -c "CREATE DATABASE $DB_DEV;" + + # Create DEV user with separate password + docker exec "$DB_CONTAINER" psql -U postgres -tc \ + "SELECT 1 FROM pg_roles WHERE rolname='lifeos_dev'" | grep -q 1 || \ + docker exec "$DB_CONTAINER" psql -U postgres \ + -c "CREATE USER lifeos_dev WITH PASSWORD '$DB_DEV_PASSWORD';" + + docker exec "$DB_CONTAINER" psql -U postgres \ + -c "GRANT ALL PRIVILEGES ON DATABASE $DB_DEV TO lifeos_dev;" + + echo "Databases ready:" + docker exec "$DB_CONTAINER" psql -U postgres -c "\l" | grep lifeos +} + +# ============================================================================= +# SECTION 3: Application Directory Structure +# ============================================================================= +setup_app_dirs() { + section "SECTION 3: Application Directory Structure" + + mkdir -p "$LIFEOS_DIR/prod" + mkdir -p "$LIFEOS_DIR/dev" + mkdir -p "$LIFEOS_DIR/prod/files" + mkdir -p "$LIFEOS_DIR/dev/files" + + echo "Created directory structure:" + ls -la "$LIFEOS_DIR" +} + +# ============================================================================= +# SECTION 4: Nginx Configuration +# (Run after app containers are up and SSL cert is expanded) +# ============================================================================= +setup_nginx() { + section "SECTION 4: Nginx Virtual Hosts" + + # Add Life OS PROD and DEV server blocks to existing invixiom config + # We append to the existing file - kasm/files/code blocks remain untouched + + if grep -q "$DOMAIN_PROD" /etc/nginx/sites-available/invixiom; then + echo "Nginx config for $DOMAIN_PROD already exists, skipping." + else + cat >> /etc/nginx/sites-available/invixiom << EOF + +server { + listen 443 ssl; + server_name $DOMAIN_PROD; + ssl_certificate $CERT_PATH/fullchain.pem; + ssl_certificate_key $CERT_PATH/privkey.pem; + location / { + proxy_pass http://127.0.0.1:$APP_PROD_PORT; + proxy_http_version 1.1; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + } +} + +server { + listen 443 ssl; + server_name $DOMAIN_DEV; + ssl_certificate $CERT_PATH/fullchain.pem; + ssl_certificate_key $CERT_PATH/privkey.pem; + location / { + proxy_pass http://127.0.0.1:$APP_DEV_PORT; + proxy_http_version 1.1; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + } +} +EOF + echo "Added Nginx config for $DOMAIN_PROD and $DOMAIN_DEV" + fi + + # Add new domains to the HTTP->HTTPS redirect block + # (manual step - see notes below) + echo "" + echo "NOTE: Also add $DOMAIN_PROD and $DOMAIN_DEV to the server_name line" + echo "in the HTTP redirect block at the top of /etc/nginx/sites-available/invixiom" + + # Test and reload + nginx -t && systemctl reload nginx + echo "Nginx reloaded." +} + +# ============================================================================= +# SECTION 5: SSL Certificate Expansion +# (Expand Let's Encrypt cert to cover new subdomains) +# ============================================================================= +setup_ssl() { + section "SECTION 5: SSL Certificate Expansion" + + certbot certonly --nginx \ + -d kasm.invixiom.com \ + -d files.invixiom.com \ + -d code.invixiom.com \ + -d "$DOMAIN_PROD" \ + -d "$DOMAIN_DEV" \ + --expand + + systemctl reload nginx + echo "SSL cert expanded and Nginx reloaded." +} + +# ============================================================================= +# MAIN +# ============================================================================= +case "${1:-all}" in + network) setup_network ;; + database) setup_database ;; + dirs) setup_app_dirs ;; + nginx) setup_nginx ;; + ssl) setup_ssl ;; + all) + setup_network + setup_database + setup_app_dirs + # nginx and ssl run after app containers are built + echo "" + echo "==============================================" + echo " Sections 1-3 complete." + echo " Next: build Life OS Docker image, then run:" + echo " bash lifeos-setup.sh ssl" + echo " bash lifeos-setup.sh nginx" + echo "==============================================" + ;; + *) + echo "Unknown section: $1" + echo "Usage: bash lifeos-setup.sh [network|database|dirs|nginx|ssl|all]" + exit 1 + ;; +esac + +# ============================================================================= +# SECTION 6: Data Migration (reference - already completed) +# Documents the steps used to migrate Supabase prod data to lifeos_prod +# ============================================================================= +setup_migration_notes() { + section "SECTION 6: Data Migration Notes" + echo "Migration completed 2026-02-27" + echo "" + echo "Steps used:" + echo " 1. Exported data from Supabase using Python supabase client (supabase_export.py)" + echo " 2. Applied schema: docker exec -i lifeos-db psql -U postgres -d lifeos_prod < lifeos_schema_r0.sql" + echo " 3. Imported data: docker exec -i lifeos-db psql -U postgres -d lifeos_prod < lifeos_export.sql" + echo "" + echo "Final row counts:" + docker exec lifeos-db psql -U postgres -d lifeos_prod -c " + SELECT 'domains' as table_name, count(*) FROM domains UNION ALL + SELECT 'areas', count(*) FROM areas UNION ALL + SELECT 'projects', count(*) FROM projects UNION ALL + SELECT 'tasks', count(*) FROM tasks UNION ALL + SELECT 'notes', count(*) FROM notes UNION ALL + SELECT 'links', count(*) FROM links UNION ALL + SELECT 'files', count(*) FROM files UNION ALL + SELECT 'daily_focus', count(*) FROM daily_focus UNION ALL + SELECT 'capture', count(*) FROM capture UNION ALL + SELECT 'context_types', count(*) FROM context_types; + " + echo "" + echo "Note: files table is empty - Supabase Storage paths are obsolete." + echo "File uploads start fresh in Release 1 using local storage." +} diff --git a/project-docs/lifeos-v2-migration-plan.docx b/project-docs/lifeos-v2-migration-plan.docx new file mode 100644 index 0000000..9a75a1a --- /dev/null +++ b/project-docs/lifeos-v2-migration-plan.docx @@ -0,0 +1,667 @@ +**Life OS v2** + +Data Migration Plan + +Old Schema to New Schema Mapping + New Database DDL + + -------------------- -------------------------------------------------- + Document Version 1.0 + + Date February 2026 + + Old System Supabase (PostgreSQL) on Render + + New System Self-hosted PostgreSQL on Hetzner VM (defiant-01) + + Old Schema Tables 11 + + New Schema Tables \~50 + -------------------- -------------------------------------------------- + +**1. Migration Overview** + +This document defines the data migration from Life OS v1 +(Supabase/Render) to Life OS v2 (self-hosted PostgreSQL on Hetzner). The +v1 schema and data remain untouched on Supabase for reference. The v2 +schema is a completely separate database with new tables, new +conventions, and expanded capabilities. + +**Strategy:** Export v1 data via pg_dump, transform using a Python +migration script, import into the v2 database. V1 remains read-only as a +reference. No shared database, no incremental sync. + +**Key principle:** The new schema is NOT an evolution of the old schema. +It is a redesign. Some tables map 1:1 (domains, areas). Others split, +merge, or gain significant new columns. Some v2 tables have no v1 +equivalent at all. + +**2. Old Schema (R0 State)** + +The v1 system has 11 tables. All PKs are UUID via gen_random_uuid(). +Timestamps are TIMESTAMPTZ. + + --------------- ---------- --------------------------------------------- + **Table** **Row **Purpose** + Est.** + + domains 3-5 Top-level life categories (Work, Personal, + Sintri) + + areas 5-10 Optional grouping within a domain + + projects 10-20 Unit of work within domain/area + + tasks 50-200 Atomic actions with priority, status, context + + notes 10-50 Markdown documents attached to project/domain + + links 10-30 Named URL references + + files 5-20 Binary files in Supabase Storage with + metadata + + daily_focus 30-100 Date-scoped task commitment list + + capture 10-50 Raw text capture queue + + context_types 6 GTD execution mode lookup (deep_work, quick, + etc.) + + reminders 0 Schema exists but no UI or delivery built + --------------- ---------- --------------------------------------------- + +**3. Table-by-Table Migration Mapping** + +Each v1 table is mapped to its v2 equivalent(s) with column-level +transformations noted. Universal columns added to all v2 tables: +updated_at, is_active (BOOLEAN DEFAULT true), sort_order (INT DEFAULT +0). + +**3.1 domains -\> domains** + +**Mapping:** Direct 1:1. Preserve UUIDs. + + ----------------- ----------------- ------------ --------------------------- + **v1 Column** **v2 Column** **Action** **Notes** + + id id Copy Preserve UUID, all FKs + depend on it + + name name Copy + + color color Copy + + created_at created_at Copy + + (none) updated_at Generate Set to created_at for + initial import + + (none) is_active Default true + + (none) sort_order Generate Assign sequential 10, 20, + 30\... + + (none) description Default NULL - new optional field + + (none) icon Default NULL - new optional field + ----------------- ----------------- ------------ --------------------------- + +**3.2 areas -\> areas** + +**Mapping:** Direct 1:1. Preserve UUIDs. + + ----------------- ----------------- ------------ --------------------------- + **v1 Column** **v2 Column** **Action** **Notes** + + id id Copy Preserve UUID + + domain_id domain_id Copy FK preserved + + name name Copy + + description description Copy + + created_at created_at Copy + + (none) updated_at Generate Set to created_at + + (none) is_active Default true + + (none) sort_order Generate Sequential per domain + + (none) icon Default NULL + + (none) color Default NULL - inherit from domain + or set later + ----------------- ----------------- ------------ --------------------------- + +**3.3 projects -\> projects** + +**Mapping:** Direct 1:1 with new columns. Preserve UUIDs. + + ----------------- ----------------- ------------ --------------------------- + **v1 Column** **v2 Column** **Action** **Notes** + + id id Copy Preserve UUID + + domain_id domain_id Copy + + area_id area_id Copy Nullable preserved + + name name Copy + + description description Copy + + status status Map v1 \'archived\' -\> v2 + \'archived\' (kept as-is) + + due_date target_date Rename Column rename only, same + DATE type + + created_at created_at Copy + + updated_at updated_at Copy + + (none) start_date Default NULL + + (none) priority Default 3 (normal) + + (none) is_active Default true + + (none) sort_order Generate Sequential per area/domain + + (none) color Default NULL + + (none) release_id Default NULL - no releases in v1 + ----------------- ----------------- ------------ --------------------------- + +**3.4 tasks -\> tasks** + +**Mapping:** Direct 1:1 with significant new columns. Preserve UUIDs. +This is the most data-rich migration. + + ------------------- ------------------- ------------ --------------------------- + **v1 Column** **v2 Column** **Action** **Notes** + + id id Copy Preserve UUID - many FKs + depend on this + + domain_id domain_id Copy + + project_id project_id Copy Nullable preserved + + parent_id parent_id Copy Self-ref FK for subtasks + + title title Copy + + description description Copy + + priority priority Copy 1-4 scale preserved + + status status Copy Same enum values + + due_date due_date Copy + + deadline deadline Copy + + recurrence recurrence Copy + + tags tags Copy TEXT\[\] preserved + + context context Copy + + is_custom_context is_custom_context Copy + + created_at created_at Copy + + updated_at updated_at Copy + + completed_at completed_at Copy + + (none) assigned_to Default NULL - FK to contacts + + (none) estimated_minutes Default NULL + + (none) actual_minutes Default NULL + + (none) energy_level Default NULL (low/medium/high) + + (none) is_active Default true + + (none) sort_order Generate Sequential per project + + (none) template_id Default NULL + ------------------- ------------------- ------------ --------------------------- + +**3.5 notes -\> notes** + +**Mapping:** Direct 1:1. Preserve UUIDs. + + ----------------- ----------------- ------------ --------------------------- + **v1 Column** **v2 Column** **Action** **Notes** + + id id Copy Preserve UUID + + domain_id domain_id Copy + + project_id project_id Copy + + task_id task_id Copy + + title title Copy + + body body Copy Markdown content preserved + as-is + + content_format content_format Copy + + tags tags Copy + + created_at created_at Copy + + updated_at updated_at Copy + + (none) is_pinned Default false + + (none) is_active Default true + + (none) sort_order Default 0 + ----------------- ----------------- ------------ --------------------------- + +**3.6 links -\> bookmarks** + +**Mapping:** Renamed table. v2 expands links into a full +bookmark/weblink directory. Preserve UUIDs. + + ----------------- ----------------- ------------ --------------------------- + **v1 Column** **v2 Column** **Action** **Notes** + + id id Copy Preserve UUID + + domain_id domain_id Copy + + project_id project_id Copy + + task_id task_id Copy + + label label Copy + + url url Copy + + description description Copy + + created_at created_at Copy + + (none) updated_at Generate Set to created_at + + (none) folder_id Default NULL - bookmark folders are + new in v2 + + (none) favicon_url Default NULL + + (none) is_active Default true + + (none) sort_order Default 0 + + (none) tags Default NULL - new in v2 + ----------------- ----------------- ------------ --------------------------- + +**3.7 files -\> files** + +**Mapping:** 1:1 with storage path transformation. Files must be +downloaded from Supabase Storage and re-uploaded to local disk on +defiant-01. + + ------------------- ------------------- ------------ --------------------------- + **v1 Column** **v2 Column** **Action** **Notes** + + id id Copy Preserve UUID + + domain_id domain_id Copy + + project_id project_id Copy + + task_id task_id Copy + + capture_id capture_id Copy + + filename filename Copy Internal UUID-prefixed name + + original_filename original_filename Copy + + storage_path storage_path Transform Rewrite from Supabase path + to local path + + mime_type mime_type Copy + + size_bytes size_bytes Copy + + description description Copy + + tags tags Copy + + created_at created_at Copy + + updated_at updated_at Copy + + (none) note_id Default NULL - new FK in v2 + + (none) is_active Default true + ------------------- ------------------- ------------ --------------------------- + +**File storage migration:** Use the Supabase Python client to iterate +the life-os-files bucket, download each file, and save to +/opt/lifeos/storage/files/ on defiant-01. Update storage_path values to +reflect the new local path. + +**3.8 daily_focus -\> daily_focus** + +**Mapping:** Direct 1:1. Preserve UUIDs. + + ----------------- ----------------- ------------ --------------------------- + **v1 Column** **v2 Column** **Action** **Notes** + + id id Copy + + focus_date focus_date Copy + + task_id task_id Copy + + slot slot Copy v2 removes the 3-item limit + + completed completed Copy + + note note Copy + + created_at created_at Copy + + (none) domain_id Derive Look up from task_id -\> + tasks.domain_id + ----------------- ----------------- ------------ --------------------------- + +**3.9 capture -\> capture** + +**Mapping:** 1:1 with enrichment for new capture context fields. + + ----------------- ----------------- ------------ --------------------------- + **v1 Column** **v2 Column** **Action** **Notes** + + id id Copy + + raw_text raw_text Copy + + processed processed Copy + + task_id task_id Copy + + created_at created_at Copy + + (none) domain_id Default NULL - new optional context + during capture + + (none) project_id Default NULL + + (none) source Default \'web\' - v2 tracks capture + source (web/voice/telegram) + + (none) updated_at Generate Set to created_at + ----------------- ----------------- ------------ --------------------------- + +**3.10 context_types -\> context_types** + +**Mapping:** Direct copy. Small reference table. + + ----------------- ----------------- ------------ --------------------------- + **v1 Column** **v2 Column** **Action** **Notes** + + id id Copy v1 uses UUID, v2 keeps UUID + for consistency + + value value Copy + + label label Copy + + is_system is_system Copy + + (none) is_active Default true + + (none) sort_order Default Sequential + ----------------- ----------------- ------------ --------------------------- + +**3.11 reminders -\> reminders (redesigned)** + +**Mapping:** v1 reminders is task-only with 0 rows. v2 redesigns +reminders as polymorphic (can remind about tasks, events, projects, or +arbitrary items). Since v1 has no data, this is seed-only with no +migration. + +v2 reminders table adds: entity_type (TEXT), entity_id (UUID), +recurrence, snoozed_until, and removes the task_id-only FK in favor of +polymorphic reference. + +**4. New Tables in v2 (No v1 Data)** + +These tables exist only in v2 and will be empty after migration. They +are populated through normal application use. + + ------------------- ---------------------------------------------------- + **Table** **Purpose** + + contacts People for task assignment and project management + + contact_groups Grouping contacts (team, family, etc.) + + lists Named checklists and note lists + + list_items Individual items within a list + + calendar_events Appointments, meetings, date-based items + + time_entries Time tracking records against tasks + + time_blocks Scheduled time blocks (Pomodoro, deep work) + + time_budgets Weekly/monthly time allocation targets + + releases Release/version grouping for projects + + milestones Project milestones with target dates + + task_dependencies Task-to-task dependency relationships + + task_templates Reusable task templates + + note_links Cross-references between notes and other entities + + bookmark_folders Hierarchical folder structure for bookmarks + + tags Normalized tag table (replaces TEXT\[\] arrays + eventually) + + entity_tags Junction table for normalized tagging + + activity_log Audit trail of entity changes + + user_settings Application preferences and configuration + + saved_views Custom filtered/sorted views the user saves + + search_index Full-text search materialized view / helper + ------------------- ---------------------------------------------------- + +**5. Migration Script Approach** + +**5.1 Prerequisites** + +1\. pg_dump export of v1 Supabase database saved as +life_os_v1_backup.sql + +2\. v2 PostgreSQL database created on defiant-01 (lifeos_dev for +testing, lifeos_prod for final) + +3\. v2 schema DDL applied to the target database (see Section 6) + +4\. Supabase Storage files downloaded to a local staging directory + +5\. Python 3.11+ with psycopg2 and supabase client libraries + +**5.2 Script Structure** + +migrate_v1_to_v2.py + +1\. Connect to v1 (read-only) and v2 (read-write) + +2\. For each table in dependency order: + +a\. SELECT \* FROM v1 table + +b\. Transform each row per mapping rules above + +c\. INSERT INTO v2 table + +3\. Download files from Supabase Storage + +4\. Verify row counts match + +5\. Run FK integrity checks on v2 + +Table order (respects FK dependencies): + +domains + +areas + +projects + +context_types + +tasks + +notes + +capture + +bookmarks (from links) + +files + +daily_focus + +**5.3 Transformation Rules Summary** + +For all tables with missing updated_at: set to created_at. + +For all tables with missing is_active: set to true. + +For all tables with missing sort_order: assign sequential values (10, +20, 30) within their parent scope. + +For projects.due_date: rename to target_date, no value change. + +For links -\> bookmarks: table rename, add updated_at = created_at. + +For files.storage_path: rewrite from Supabase bucket URL to local +filesystem path. + +For daily_focus: derive domain_id by joining through task_id to +tasks.domain_id. + +**5.4 Validation Checklist** + +After migration, verify: + +1\. Row counts: v2 table row count \>= v1 for every mapped table + +2\. UUID preservation: SELECT id FROM v2.domains EXCEPT SELECT id FROM +v1.domains should be empty + +3\. FK integrity: No orphaned foreign keys in v2 + +4\. File accessibility: Every file in v2.files table can be served from +local storage + +5\. Note content: Spot-check 5 notes for body content integrity + +6\. Task hierarchy: Verify parent_id chains are intact + +**6. Platform Migration Summary** + + ----------------------- ----------------------- ------------------------ + **Component** **v1 (Old)** **v2 (New)** + + Database Supabase (managed Self-hosted PostgreSQL + PostgreSQL) on Hetzner + + Application Server Render (web service) Docker container on + Hetzner VM + + Reverse Proxy Render (built-in) Nginx on defiant-01 + + File Storage Supabase Storage Local filesystem + (S3-backed) (/opt/lifeos/storage/) + + Data Access Layer supabase Python client SQLAlchemy + psycopg2 + (REST) (direct SQL) + + Templating Jinja2 Jinja2 (unchanged) + + Backend Framework FastAPI FastAPI (unchanged) + + Frontend Vanilla HTML/CSS/JS Vanilla HTML/CSS/JS + (redesigned UI) + + Dev/Prod Separation Separate Supabase Docker Compose with + projects dev/prod configs + + Backups Manual pg_dump Automated cron pg_dump + to /opt/lifeos/backups/ + + Domain/SSL \*.onrender.com lifeos.invixiom.com with + Let\'s Encrypt + ----------------------- ----------------------- ------------------------ + +**7. Data Access Layer Migration** + +Every Supabase client call in the v1 routers must be replaced. The +pattern is consistent: + +\# v1 (Supabase REST client) + +data = supabase.table(\'tasks\').select(\'\*\').eq(\'project_id\', +pid).execute() + +rows = data.data + +\# v2 (SQLAlchemy / raw SQL) + +rows = db.execute( + +text(\'SELECT \* FROM tasks WHERE project_id = :pid\'), + +{\'pid\': pid} + +).fetchall() + +This transformation applies to every router file. The Jinja2 templates +remain unchanged because they consume the same data shape (list of +dicts). The migration is purely at the data access layer. + +**8. Rollback Plan** + +v1 on Supabase/Render remains untouched and running throughout the +migration. If v2 has issues: + +1\. Point DNS back to Render (or simply use the .onrender.com URL +directly) + +2\. v1 database on Supabase is read-only but intact - no data was +deleted + +3\. Any data created in v2 after migration would need manual +reconciliation if rolling back + +Recommended approach: run v1 and v2 in parallel for 1-2 weeks. Cut over +to v2 only after confirming data integrity and feature parity on the +critical path (tasks, focus, notes, capture). + +Life OS v2 Migration Plan // Generated February 2026 diff --git a/project-docs/lifeos_r0_to_r1_migration.sql b/project-docs/lifeos_r0_to_r1_migration.sql new file mode 100644 index 0000000..c784796 --- /dev/null +++ b/project-docs/lifeos_r0_to_r1_migration.sql @@ -0,0 +1,263 @@ +-- ============================================================================= +-- Life OS - R0 to R1 Data Migration (FIXED) +-- Source: lifeos_prod (R0 schema - actual) +-- Target: lifeos_dev (R1 schema) +-- +-- PREREQUISITE: R1 schema must already be applied to lifeos_dev +-- RUN FROM: lifeos_dev database as postgres user +-- ============================================================================= + +CREATE EXTENSION IF NOT EXISTS dblink; + +-- ============================================================================= +-- 1. DOMAINS +-- R0: id, name, color, created_at +-- R1: + description, icon, sort_order, is_deleted, deleted_at, updated_at, search_vector +-- ============================================================================= + +INSERT INTO domains (id, name, color, sort_order, is_deleted, created_at, updated_at) +SELECT id, name, color, + (ROW_NUMBER() OVER (ORDER BY created_at))::INTEGER * 10, + false, created_at, created_at +FROM dblink('dbname=lifeos_prod', ' + SELECT id, name, color, created_at FROM domains +') AS r0(id UUID, name TEXT, color TEXT, created_at TIMESTAMPTZ); + +-- ============================================================================= +-- 2. AREAS +-- R0: id, domain_id, name, description, status, created_at +-- R1: + icon, color, sort_order, is_deleted, deleted_at, updated_at, search_vector +-- ============================================================================= + +INSERT INTO areas (id, domain_id, name, description, status, sort_order, is_deleted, created_at, updated_at) +SELECT id, domain_id, name, description, COALESCE(status, 'active'), + (ROW_NUMBER() OVER (PARTITION BY domain_id ORDER BY created_at))::INTEGER * 10, + false, created_at, created_at +FROM dblink('dbname=lifeos_prod', ' + SELECT id, domain_id, name, description, status, created_at FROM areas +') AS r0(id UUID, domain_id UUID, name TEXT, description TEXT, status TEXT, created_at TIMESTAMPTZ); + +-- ============================================================================= +-- 3. PROJECTS +-- R0: id, domain_id, name, description, status, priority, start_date, +-- target_date, completed_at, tags, created_at, updated_at, area_id +-- R1: + color, sort_order, is_deleted, deleted_at, search_vector +-- ============================================================================= + +INSERT INTO projects (id, domain_id, area_id, name, description, status, priority, + start_date, target_date, completed_at, tags, sort_order, is_deleted, created_at, updated_at) +SELECT id, domain_id, area_id, name, description, + COALESCE(status, 'active'), COALESCE(priority, 3), + start_date, target_date, completed_at, tags, + (ROW_NUMBER() OVER (PARTITION BY domain_id ORDER BY created_at))::INTEGER * 10, + false, created_at, COALESCE(updated_at, created_at) +FROM dblink('dbname=lifeos_prod', ' + SELECT id, domain_id, area_id, name, description, status, priority, + start_date, target_date, completed_at, tags, created_at, updated_at + FROM projects +') AS r0( + id UUID, domain_id UUID, area_id UUID, name TEXT, description TEXT, + status TEXT, priority INTEGER, start_date DATE, target_date DATE, + completed_at TIMESTAMPTZ, tags TEXT[], created_at TIMESTAMPTZ, updated_at TIMESTAMPTZ +); + +-- ============================================================================= +-- 4. TASKS +-- R0: id, domain_id, project_id, parent_id, title, description, priority, +-- status, due_date, deadline, recurrence, tags, context, is_custom_context, +-- created_at, updated_at, completed_at +-- R1: + area_id, release_id, estimated_minutes, energy_required, +-- waiting_for_contact_id, waiting_since, import_batch_id, +-- sort_order, is_deleted, deleted_at, search_vector +-- NOTE: R0 has no area_id on tasks. Left NULL in R1. +-- ============================================================================= + +INSERT INTO tasks (id, domain_id, project_id, parent_id, title, description, + priority, status, due_date, deadline, recurrence, tags, context, + is_custom_context, sort_order, is_deleted, created_at, updated_at, completed_at) +SELECT id, domain_id, project_id, parent_id, title, description, + COALESCE(priority, 3), COALESCE(status, 'open'), + due_date, deadline, recurrence, tags, context, + COALESCE(is_custom_context, false), + (ROW_NUMBER() OVER (PARTITION BY project_id ORDER BY created_at))::INTEGER * 10, + false, created_at, COALESCE(updated_at, created_at), completed_at +FROM dblink('dbname=lifeos_prod', ' + SELECT id, domain_id, project_id, parent_id, title, description, + priority, status, due_date, deadline, recurrence, tags, context, + is_custom_context, created_at, updated_at, completed_at + FROM tasks +') AS r0( + id UUID, domain_id UUID, project_id UUID, parent_id UUID, + title TEXT, description TEXT, priority INTEGER, status TEXT, + due_date DATE, deadline TIMESTAMPTZ, recurrence TEXT, tags TEXT[], + context TEXT, is_custom_context BOOLEAN, + created_at TIMESTAMPTZ, updated_at TIMESTAMPTZ, completed_at TIMESTAMPTZ +); + +-- ============================================================================= +-- 5. NOTES +-- R0: id, domain_id, project_id, task_id, title, body, tags, +-- created_at, updated_at, content_format (default 'markdown') +-- R1: + folder_id, meeting_id, is_meeting_note, sort_order, +-- is_deleted, deleted_at, search_vector +-- Transform: content_format 'markdown' -> 'rich' +-- NOTE: R0 task_id dropped (no equivalent in R1 notes). +-- ============================================================================= + +INSERT INTO notes (id, domain_id, project_id, title, body, content_format, tags, + is_meeting_note, sort_order, is_deleted, created_at, updated_at) +SELECT id, domain_id, project_id, + CASE WHEN title IS NULL OR title = '' THEN 'Untitled Note' ELSE title END, + body, + CASE WHEN content_format = 'markdown' THEN 'rich' ELSE COALESCE(content_format, 'rich') END, + tags, false, + (ROW_NUMBER() OVER (ORDER BY created_at))::INTEGER * 10, + false, created_at, COALESCE(updated_at, created_at) +FROM dblink('dbname=lifeos_prod', ' + SELECT id, domain_id, project_id, title, body, content_format, tags, + created_at, updated_at + FROM notes +') AS r0( + id UUID, domain_id UUID, project_id UUID, title TEXT, body TEXT, + content_format TEXT, tags TEXT[], + created_at TIMESTAMPTZ, updated_at TIMESTAMPTZ +); + +-- ============================================================================= +-- 6. LINKS +-- R0: id, domain_id, project_id, task_id, label, url, description, created_at +-- R1: + area_id, tags, sort_order, is_deleted, deleted_at, updated_at, search_vector +-- NOTE: R0 task_id dropped (no equivalent in R1 links). +-- ============================================================================= + +INSERT INTO links (id, domain_id, project_id, label, url, description, + sort_order, is_deleted, created_at, updated_at) +SELECT id, domain_id, project_id, label, url, description, + (ROW_NUMBER() OVER (ORDER BY created_at))::INTEGER * 10, + false, created_at, created_at +FROM dblink('dbname=lifeos_prod', ' + SELECT id, domain_id, project_id, label, url, description, created_at + FROM links +') AS r0( + id UUID, domain_id UUID, project_id UUID, + label TEXT, url TEXT, description TEXT, created_at TIMESTAMPTZ +); + +-- ============================================================================= +-- 7. DAILY FOCUS +-- R0: id, focus_date, task_id, slot, completed, note, created_at +-- R1: + sort_order, is_deleted, deleted_at +-- ============================================================================= + +INSERT INTO daily_focus (id, focus_date, task_id, slot, completed, note, + sort_order, is_deleted, created_at) +SELECT id, focus_date, task_id, slot, COALESCE(completed, false), note, + COALESCE(slot, (ROW_NUMBER() OVER (PARTITION BY focus_date ORDER BY created_at))::INTEGER) * 10, + false, created_at +FROM dblink('dbname=lifeos_prod', ' + SELECT id, focus_date, task_id, slot, completed, note, created_at + FROM daily_focus +') AS r0( + id UUID, focus_date DATE, task_id UUID, slot INTEGER, + completed BOOLEAN, note TEXT, created_at TIMESTAMPTZ +); + +-- ============================================================================= +-- 8. CAPTURE +-- R0: id, raw_text, processed, task_id, created_at +-- R1: + converted_to_type, converted_to_id, area_id, project_id, list_id, +-- import_batch_id, sort_order, is_deleted, deleted_at +-- Map: R0 task_id -> R1 converted_to_type='task', converted_to_id=task_id +-- ============================================================================= + +INSERT INTO capture (id, raw_text, processed, converted_to_type, converted_to_id, + sort_order, is_deleted, created_at) +SELECT id, raw_text, COALESCE(processed, false), + CASE WHEN task_id IS NOT NULL THEN 'task' ELSE NULL END, + task_id, + (ROW_NUMBER() OVER (ORDER BY created_at))::INTEGER * 10, + false, created_at +FROM dblink('dbname=lifeos_prod', ' + SELECT id, raw_text, processed, task_id, created_at FROM capture +') AS r0( + id UUID, raw_text TEXT, processed BOOLEAN, task_id UUID, created_at TIMESTAMPTZ +); + +-- ============================================================================= +-- 9. CONTEXT TYPES +-- R0: id (SERIAL), name, description, is_system +-- R1: id (SERIAL), value, label, description, is_system, sort_order, is_deleted +-- Map: R0.name -> R1.value, generate label from name via INITCAP +-- ============================================================================= + +DELETE FROM context_types; + +INSERT INTO context_types (id, value, label, description, is_system, sort_order, is_deleted) +SELECT id, name, + INITCAP(REPLACE(name, '_', ' ')), + description, COALESCE(is_system, true), + id * 10, + false +FROM dblink('dbname=lifeos_prod', ' + SELECT id, name, description, is_system FROM context_types +') AS r0(id INTEGER, name TEXT, description TEXT, is_system BOOLEAN); + +SELECT setval('context_types_id_seq', GREATEST((SELECT MAX(id) FROM context_types), 1)); + +-- ============================================================================= +-- VERIFICATION +-- ============================================================================= + +DO $$ +DECLARE + r0_domains INTEGER; + r0_areas INTEGER; + r0_projects INTEGER; + r0_tasks INTEGER; + r0_notes INTEGER; + r0_links INTEGER; + r0_daily_focus INTEGER; + r0_capture INTEGER; + r0_context INTEGER; + r1_domains INTEGER; + r1_areas INTEGER; + r1_projects INTEGER; + r1_tasks INTEGER; + r1_notes INTEGER; + r1_links INTEGER; + r1_daily_focus INTEGER; + r1_capture INTEGER; + r1_context INTEGER; +BEGIN + SELECT count INTO r0_domains FROM dblink('dbname=lifeos_prod', 'SELECT count(*) FROM domains') AS t(count INTEGER); + SELECT count INTO r0_areas FROM dblink('dbname=lifeos_prod', 'SELECT count(*) FROM areas') AS t(count INTEGER); + SELECT count INTO r0_projects FROM dblink('dbname=lifeos_prod', 'SELECT count(*) FROM projects') AS t(count INTEGER); + SELECT count INTO r0_tasks FROM dblink('dbname=lifeos_prod', 'SELECT count(*) FROM tasks') AS t(count INTEGER); + SELECT count INTO r0_notes FROM dblink('dbname=lifeos_prod', 'SELECT count(*) FROM notes') AS t(count INTEGER); + SELECT count INTO r0_links FROM dblink('dbname=lifeos_prod', 'SELECT count(*) FROM links') AS t(count INTEGER); + SELECT count INTO r0_daily_focus FROM dblink('dbname=lifeos_prod', 'SELECT count(*) FROM daily_focus') AS t(count INTEGER); + SELECT count INTO r0_capture FROM dblink('dbname=lifeos_prod', 'SELECT count(*) FROM capture') AS t(count INTEGER); + SELECT count INTO r0_context FROM dblink('dbname=lifeos_prod', 'SELECT count(*) FROM context_types') AS t(count INTEGER); + + SELECT count(*) INTO r1_domains FROM domains; + SELECT count(*) INTO r1_areas FROM areas; + SELECT count(*) INTO r1_projects FROM projects; + SELECT count(*) INTO r1_tasks FROM tasks; + SELECT count(*) INTO r1_notes FROM notes; + SELECT count(*) INTO r1_links FROM links; + SELECT count(*) INTO r1_daily_focus FROM daily_focus; + SELECT count(*) INTO r1_capture FROM capture; + SELECT count(*) INTO r1_context FROM context_types; + + RAISE NOTICE '=== MIGRATION VERIFICATION ==='; + RAISE NOTICE 'domains: R0=% R1=% %', r0_domains, r1_domains, CASE WHEN r0_domains = r1_domains THEN 'OK' ELSE 'MISMATCH' END; + RAISE NOTICE 'areas: R0=% R1=% %', r0_areas, r1_areas, CASE WHEN r0_areas = r1_areas THEN 'OK' ELSE 'MISMATCH' END; + RAISE NOTICE 'projects: R0=% R1=% %', r0_projects, r1_projects, CASE WHEN r0_projects = r1_projects THEN 'OK' ELSE 'MISMATCH' END; + RAISE NOTICE 'tasks: R0=% R1=% %', r0_tasks, r1_tasks, CASE WHEN r0_tasks = r1_tasks THEN 'OK' ELSE 'MISMATCH' END; + RAISE NOTICE 'notes: R0=% R1=% %', r0_notes, r1_notes, CASE WHEN r0_notes = r1_notes THEN 'OK' ELSE 'MISMATCH' END; + RAISE NOTICE 'links: R0=% R1=% %', r0_links, r1_links, CASE WHEN r0_links = r1_links THEN 'OK' ELSE 'MISMATCH' END; + RAISE NOTICE 'daily_focus: R0=% R1=% %', r0_daily_focus, r1_daily_focus, CASE WHEN r0_daily_focus = r1_daily_focus THEN 'OK' ELSE 'MISMATCH' END; + RAISE NOTICE 'capture: R0=% R1=% %', r0_capture, r1_capture, CASE WHEN r0_capture = r1_capture THEN 'OK' ELSE 'MISMATCH' END; + RAISE NOTICE 'context_types:R0=% R1=% %', r0_context, r1_context, CASE WHEN r0_context = r1_context THEN 'OK' ELSE 'MISMATCH' END; + RAISE NOTICE '=== END VERIFICATION ==='; +END $$; diff --git a/project-docs/lifeos_r1_full_schema.sql b/project-docs/lifeos_r1_full_schema.sql new file mode 100644 index 0000000..b0f398b --- /dev/null +++ b/project-docs/lifeos_r1_full_schema.sql @@ -0,0 +1,979 @@ +-- ============================================================================= +-- Life OS - Release 1 COMPLETE Schema +-- Self-hosted PostgreSQL 16 on defiant-01 (Hetzner) +-- Database: lifeos_dev +-- Generated from Architecture Design Document v2.0 +-- ============================================================================= + +-- Extensions +CREATE EXTENSION IF NOT EXISTS "pgcrypto"; + +-- ============================================================================= +-- LOOKUP TABLE: Context Types +-- ============================================================================= + +CREATE TABLE context_types ( + id SERIAL PRIMARY KEY, + value TEXT NOT NULL UNIQUE, + label TEXT NOT NULL, + description TEXT, + is_system BOOLEAN NOT NULL DEFAULT true, + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- CORE HIERARCHY +-- ============================================================================= + +CREATE TABLE domains ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name TEXT NOT NULL, + color TEXT, + description TEXT, + icon TEXT, + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + search_vector TSVECTOR, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE areas ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + domain_id UUID NOT NULL REFERENCES domains(id) ON DELETE CASCADE, + name TEXT NOT NULL, + description TEXT, + icon TEXT, + color TEXT, + status TEXT NOT NULL DEFAULT 'active', + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + search_vector TSVECTOR, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE projects ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + domain_id UUID NOT NULL REFERENCES domains(id) ON DELETE CASCADE, + area_id UUID REFERENCES areas(id) ON DELETE SET NULL, + name TEXT NOT NULL, + description TEXT, + status TEXT NOT NULL DEFAULT 'active', + priority INTEGER NOT NULL DEFAULT 3, + start_date DATE, + target_date DATE, + completed_at TIMESTAMPTZ, + color TEXT, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + search_vector TSVECTOR, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- Forward-declare releases for tasks.release_id FK +CREATE TABLE releases ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name TEXT NOT NULL, + version_label TEXT, + description TEXT, + status TEXT NOT NULL DEFAULT 'planned', + target_date DATE, + released_at DATE, + release_notes TEXT, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + search_vector TSVECTOR, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- Forward-declare contacts for tasks.waiting_for_contact_id FK +CREATE TABLE contacts ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + first_name TEXT NOT NULL, + last_name TEXT, + company TEXT, + role TEXT, + email TEXT, + phone TEXT, + notes TEXT, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + search_vector TSVECTOR, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE tasks ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + domain_id UUID REFERENCES domains(id) ON DELETE CASCADE, + area_id UUID REFERENCES areas(id) ON DELETE SET NULL, + project_id UUID REFERENCES projects(id) ON DELETE SET NULL, + release_id UUID REFERENCES releases(id) ON DELETE SET NULL, + parent_id UUID REFERENCES tasks(id) ON DELETE SET NULL, + title TEXT NOT NULL, + description TEXT, + priority INTEGER NOT NULL DEFAULT 3, + status TEXT NOT NULL DEFAULT 'open', + due_date DATE, + deadline TIMESTAMPTZ, + recurrence TEXT, + estimated_minutes INTEGER, + energy_required TEXT, + context TEXT, + is_custom_context BOOLEAN NOT NULL DEFAULT false, + waiting_for_contact_id UUID REFERENCES contacts(id) ON DELETE SET NULL, + waiting_since DATE, + import_batch_id UUID, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + completed_at TIMESTAMPTZ, + search_vector TSVECTOR, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- KNOWLEDGE MANAGEMENT +-- ============================================================================= + +CREATE TABLE note_folders ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + parent_id UUID REFERENCES note_folders(id) ON DELETE CASCADE, + name TEXT NOT NULL, + auto_generated BOOLEAN NOT NULL DEFAULT false, + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- Forward-declare meetings for notes.meeting_id FK +CREATE TABLE meetings ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + parent_id UUID REFERENCES meetings(id) ON DELETE SET NULL, + title TEXT NOT NULL, + meeting_date DATE NOT NULL, + start_at TIMESTAMPTZ, + end_at TIMESTAMPTZ, + location TEXT, + status TEXT NOT NULL DEFAULT 'scheduled', + priority INTEGER, + recurrence TEXT, + agenda TEXT, + transcript TEXT, + notes_body TEXT, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + search_vector TSVECTOR, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE notes ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + domain_id UUID REFERENCES domains(id) ON DELETE CASCADE, + project_id UUID REFERENCES projects(id) ON DELETE SET NULL, + folder_id UUID REFERENCES note_folders(id) ON DELETE SET NULL, + meeting_id UUID REFERENCES meetings(id) ON DELETE SET NULL, + title TEXT NOT NULL, + body TEXT, + content_format TEXT NOT NULL DEFAULT 'rich', + is_meeting_note BOOLEAN NOT NULL DEFAULT false, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + search_vector TSVECTOR, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE decisions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + title TEXT NOT NULL, + rationale TEXT, + status TEXT NOT NULL DEFAULT 'proposed', + impact TEXT NOT NULL DEFAULT 'medium', + decided_at DATE, + meeting_id UUID REFERENCES meetings(id) ON DELETE SET NULL, + superseded_by_id UUID REFERENCES decisions(id) ON DELETE SET NULL, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + search_vector TSVECTOR, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE lists ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + domain_id UUID REFERENCES domains(id) ON DELETE CASCADE, + area_id UUID REFERENCES areas(id) ON DELETE SET NULL, + project_id UUID REFERENCES projects(id) ON DELETE SET NULL, + name TEXT NOT NULL, + list_type TEXT NOT NULL DEFAULT 'checklist', + description TEXT, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + search_vector TSVECTOR, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE list_items ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + list_id UUID NOT NULL REFERENCES lists(id) ON DELETE CASCADE, + parent_item_id UUID REFERENCES list_items(id) ON DELETE SET NULL, + content TEXT NOT NULL, + completed BOOLEAN NOT NULL DEFAULT false, + completed_at TIMESTAMPTZ, + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE links ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + domain_id UUID REFERENCES domains(id) ON DELETE CASCADE, + area_id UUID REFERENCES areas(id) ON DELETE SET NULL, + project_id UUID REFERENCES projects(id) ON DELETE SET NULL, + label TEXT NOT NULL, + url TEXT NOT NULL, + description TEXT, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + search_vector TSVECTOR, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE files ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + filename TEXT NOT NULL, + original_filename TEXT NOT NULL, + storage_path TEXT NOT NULL, + mime_type TEXT, + size_bytes INTEGER, + description TEXT, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + search_vector TSVECTOR, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- SYSTEM LEVEL: Appointments +-- ============================================================================= + +CREATE TABLE appointments ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + title TEXT NOT NULL, + description TEXT, + location TEXT, + start_at TIMESTAMPTZ NOT NULL, + end_at TIMESTAMPTZ, + all_day BOOLEAN NOT NULL DEFAULT false, + recurrence TEXT, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + search_vector TSVECTOR, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- SYSTEM LEVEL: Milestones +-- ============================================================================= + +CREATE TABLE milestones ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + release_id UUID REFERENCES releases(id) ON DELETE SET NULL, + project_id UUID REFERENCES projects(id) ON DELETE SET NULL, + name TEXT NOT NULL, + target_date DATE NOT NULL, + completed_at DATE, + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- SYSTEM LEVEL: Processes +-- ============================================================================= + +CREATE TABLE processes ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name TEXT NOT NULL, + description TEXT, + process_type TEXT NOT NULL DEFAULT 'checklist', + category TEXT, + status TEXT NOT NULL DEFAULT 'draft', + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + search_vector TSVECTOR, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE process_steps ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + process_id UUID NOT NULL REFERENCES processes(id) ON DELETE CASCADE, + title TEXT NOT NULL, + instructions TEXT, + expected_output TEXT, + estimated_days INTEGER, + context TEXT, + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE process_runs ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + process_id UUID NOT NULL REFERENCES processes(id) ON DELETE CASCADE, + title TEXT NOT NULL, + status TEXT NOT NULL DEFAULT 'not_started', + process_type TEXT NOT NULL, + task_generation TEXT NOT NULL DEFAULT 'all_at_once', + project_id UUID REFERENCES projects(id) ON DELETE SET NULL, + contact_id UUID REFERENCES contacts(id) ON DELETE SET NULL, + started_at TIMESTAMPTZ, + completed_at TIMESTAMPTZ, + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE process_run_steps ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + run_id UUID NOT NULL REFERENCES process_runs(id) ON DELETE CASCADE, + title TEXT NOT NULL, + instructions TEXT, + status TEXT NOT NULL DEFAULT 'pending', + completed_by_id UUID REFERENCES contacts(id) ON DELETE SET NULL, + completed_at TIMESTAMPTZ, + notes TEXT, + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- SYSTEM LEVEL: Daily Focus +-- ============================================================================= + +CREATE TABLE daily_focus ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + focus_date DATE NOT NULL, + task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE, + slot INTEGER, + completed BOOLEAN NOT NULL DEFAULT false, + note TEXT, + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- SYSTEM LEVEL: Capture Queue +-- ============================================================================= + +CREATE TABLE capture ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + raw_text TEXT NOT NULL, + processed BOOLEAN NOT NULL DEFAULT false, + converted_to_type TEXT, + converted_to_id UUID, + area_id UUID REFERENCES areas(id) ON DELETE SET NULL, + project_id UUID REFERENCES projects(id) ON DELETE SET NULL, + list_id UUID REFERENCES lists(id) ON DELETE SET NULL, + import_batch_id UUID, + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- SYSTEM LEVEL: Task Templates +-- ============================================================================= + +CREATE TABLE task_templates ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name TEXT NOT NULL, + description TEXT, + priority INTEGER, + estimated_minutes INTEGER, + energy_required TEXT, + context TEXT, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE task_template_items ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + template_id UUID NOT NULL REFERENCES task_templates(id) ON DELETE CASCADE, + title TEXT NOT NULL, + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- TIME MANAGEMENT +-- ============================================================================= + +CREATE TABLE time_entries ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE, + start_at TIMESTAMPTZ NOT NULL, + end_at TIMESTAMPTZ, + duration_minutes INTEGER, + notes TEXT, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE time_blocks ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + task_id UUID REFERENCES tasks(id) ON DELETE SET NULL, + title TEXT NOT NULL, + context TEXT, + energy TEXT, + start_at TIMESTAMPTZ NOT NULL, + end_at TIMESTAMPTZ NOT NULL, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE time_budgets ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + domain_id UUID NOT NULL REFERENCES domains(id) ON DELETE CASCADE, + weekly_hours DECIMAL NOT NULL, + effective_from DATE NOT NULL, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- SYSTEM LEVEL: Weblink Directory +-- ============================================================================= + +CREATE TABLE weblink_folders ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + parent_id UUID REFERENCES weblink_folders(id) ON DELETE CASCADE, + name TEXT NOT NULL, + auto_generated BOOLEAN NOT NULL DEFAULT false, + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE weblinks ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label TEXT NOT NULL, + url TEXT NOT NULL, + description TEXT, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + search_vector TSVECTOR, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- SYSTEM LEVEL: Reminders (polymorphic) +-- ============================================================================= + +CREATE TABLE reminders ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + entity_type TEXT NOT NULL, + entity_id UUID NOT NULL, + remind_at TIMESTAMPTZ NOT NULL, + note TEXT, + delivered BOOLEAN NOT NULL DEFAULT false, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- UNIVERSAL: Dependencies (polymorphic DAG) +-- ============================================================================= + +CREATE TABLE dependencies ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + blocker_type TEXT NOT NULL, + blocker_id UUID NOT NULL, + dependent_type TEXT NOT NULL, + dependent_id UUID NOT NULL, + dependency_type TEXT NOT NULL DEFAULT 'finish_to_start', + lag_days INTEGER NOT NULL DEFAULT 0, + note TEXT, + is_deleted BOOLEAN NOT NULL DEFAULT false, + deleted_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + UNIQUE (blocker_type, blocker_id, dependent_type, dependent_id, dependency_type), + CHECK (NOT (blocker_type = dependent_type AND blocker_id = dependent_id)) +); + +-- ============================================================================= +-- JUNCTION TABLES +-- ============================================================================= + +-- Notes <-> Projects (M2M) +CREATE TABLE note_projects ( + note_id UUID NOT NULL REFERENCES notes(id) ON DELETE CASCADE, + project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, + is_primary BOOLEAN NOT NULL DEFAULT false, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (note_id, project_id) +); + +-- Notes <-> Notes (wiki graph) +CREATE TABLE note_links ( + source_note_id UUID NOT NULL REFERENCES notes(id) ON DELETE CASCADE, + target_note_id UUID NOT NULL REFERENCES notes(id) ON DELETE CASCADE, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (source_note_id, target_note_id) +); + +-- Files <-> any entity (polymorphic M2M) +CREATE TABLE file_mappings ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + file_id UUID NOT NULL REFERENCES files(id) ON DELETE CASCADE, + context_type TEXT NOT NULL, + context_id UUID NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + UNIQUE (file_id, context_type, context_id) +); + +-- Releases <-> Projects (M2M) +CREATE TABLE release_projects ( + release_id UUID NOT NULL REFERENCES releases(id) ON DELETE CASCADE, + project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (release_id, project_id) +); + +-- Releases <-> Domains (M2M) +CREATE TABLE release_domains ( + release_id UUID NOT NULL REFERENCES releases(id) ON DELETE CASCADE, + domain_id UUID NOT NULL REFERENCES domains(id) ON DELETE CASCADE, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (release_id, domain_id) +); + +-- Contacts <-> Tasks +CREATE TABLE contact_tasks ( + contact_id UUID NOT NULL REFERENCES contacts(id) ON DELETE CASCADE, + task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE, + role TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (contact_id, task_id) +); + +-- Contacts <-> Projects +CREATE TABLE contact_projects ( + contact_id UUID NOT NULL REFERENCES contacts(id) ON DELETE CASCADE, + project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, + role TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (contact_id, project_id) +); + +-- Contacts <-> Lists +CREATE TABLE contact_lists ( + contact_id UUID NOT NULL REFERENCES contacts(id) ON DELETE CASCADE, + list_id UUID NOT NULL REFERENCES lists(id) ON DELETE CASCADE, + role TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (contact_id, list_id) +); + +-- Contacts <-> List Items +CREATE TABLE contact_list_items ( + contact_id UUID NOT NULL REFERENCES contacts(id) ON DELETE CASCADE, + list_item_id UUID NOT NULL REFERENCES list_items(id) ON DELETE CASCADE, + role TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (contact_id, list_item_id) +); + +-- Contacts <-> Appointments +CREATE TABLE contact_appointments ( + contact_id UUID NOT NULL REFERENCES contacts(id) ON DELETE CASCADE, + appointment_id UUID NOT NULL REFERENCES appointments(id) ON DELETE CASCADE, + role TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (contact_id, appointment_id) +); + +-- Contacts <-> Meetings +CREATE TABLE contact_meetings ( + contact_id UUID NOT NULL REFERENCES contacts(id) ON DELETE CASCADE, + meeting_id UUID NOT NULL REFERENCES meetings(id) ON DELETE CASCADE, + role TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (contact_id, meeting_id) +); + +-- Decisions <-> Projects +CREATE TABLE decision_projects ( + decision_id UUID NOT NULL REFERENCES decisions(id) ON DELETE CASCADE, + project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (decision_id, project_id) +); + +-- Decisions <-> Contacts +CREATE TABLE decision_contacts ( + decision_id UUID NOT NULL REFERENCES decisions(id) ON DELETE CASCADE, + contact_id UUID NOT NULL REFERENCES contacts(id) ON DELETE CASCADE, + role TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (decision_id, contact_id) +); + +-- Meetings <-> Tasks +CREATE TABLE meeting_tasks ( + meeting_id UUID NOT NULL REFERENCES meetings(id) ON DELETE CASCADE, + task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE, + source TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (meeting_id, task_id) +); + +-- Process Run Steps <-> Tasks +CREATE TABLE process_run_tasks ( + run_step_id UUID NOT NULL REFERENCES process_run_steps(id) ON DELETE CASCADE, + task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (run_step_id, task_id) +); + +-- Weblinks <-> Folders (M2M) +CREATE TABLE folder_weblinks ( + folder_id UUID NOT NULL REFERENCES weblink_folders(id) ON DELETE CASCADE, + weblink_id UUID NOT NULL REFERENCES weblinks(id) ON DELETE CASCADE, + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (folder_id, weblink_id) +); + +-- ============================================================================= +-- INDEXES +-- ============================================================================= + +-- Sort order indexes +CREATE INDEX idx_domains_sort ON domains(sort_order); +CREATE INDEX idx_areas_sort ON areas(domain_id, sort_order); +CREATE INDEX idx_projects_sort ON projects(domain_id, sort_order); +CREATE INDEX idx_projects_area_sort ON projects(area_id, sort_order); +CREATE INDEX idx_tasks_project_sort ON tasks(project_id, sort_order); +CREATE INDEX idx_tasks_parent_sort ON tasks(parent_id, sort_order); +CREATE INDEX idx_tasks_domain_sort ON tasks(domain_id, sort_order); +CREATE INDEX idx_list_items_sort ON list_items(list_id, sort_order); +CREATE INDEX idx_list_items_parent_sort ON list_items(parent_item_id, sort_order); +CREATE INDEX idx_weblink_folders_sort ON weblink_folders(parent_id, sort_order); + +-- Lookup indexes +CREATE INDEX idx_tasks_status ON tasks(status); +CREATE INDEX idx_tasks_due_date ON tasks(due_date); +CREATE INDEX idx_tasks_priority ON tasks(priority); +CREATE INDEX idx_projects_status ON projects(status); +CREATE INDEX idx_daily_focus_date ON daily_focus(focus_date); +CREATE INDEX idx_appointments_start ON appointments(start_at); +CREATE INDEX idx_capture_processed ON capture(processed); +CREATE INDEX idx_file_mappings_context ON file_mappings(context_type, context_id); +CREATE INDEX idx_dependencies_blocker ON dependencies(blocker_type, blocker_id); +CREATE INDEX idx_dependencies_dependent ON dependencies(dependent_type, dependent_id); +CREATE INDEX idx_reminders_entity ON reminders(entity_type, entity_id); +CREATE INDEX idx_time_entries_task ON time_entries(task_id); +CREATE INDEX idx_meetings_date ON meetings(meeting_date); + +-- Full-text search GIN indexes +CREATE INDEX idx_domains_search ON domains USING GIN(search_vector); +CREATE INDEX idx_areas_search ON areas USING GIN(search_vector); +CREATE INDEX idx_projects_search ON projects USING GIN(search_vector); +CREATE INDEX idx_tasks_search ON tasks USING GIN(search_vector); +CREATE INDEX idx_notes_search ON notes USING GIN(search_vector); +CREATE INDEX idx_contacts_search ON contacts USING GIN(search_vector); +CREATE INDEX idx_meetings_search ON meetings USING GIN(search_vector); +CREATE INDEX idx_decisions_search ON decisions USING GIN(search_vector); +CREATE INDEX idx_lists_search ON lists USING GIN(search_vector); +CREATE INDEX idx_links_search ON links USING GIN(search_vector); +CREATE INDEX idx_files_search ON files USING GIN(search_vector); +CREATE INDEX idx_weblinks_search ON weblinks USING GIN(search_vector); +CREATE INDEX idx_processes_search ON processes USING GIN(search_vector); +CREATE INDEX idx_appointments_search ON appointments USING GIN(search_vector); + +-- ============================================================================= +-- SEARCH VECTOR TRIGGERS +-- ============================================================================= + +CREATE OR REPLACE FUNCTION update_search_vector() RETURNS trigger AS $$ +BEGIN + NEW.search_vector := to_tsvector('pg_catalog.english', + coalesce(NEW.title, '') || ' ' || + coalesce(NEW.description, '') || ' ' || + coalesce(NEW.name, '') || ' ' || + coalesce(array_to_string(NEW.tags, ' '), '') + ); + RETURN NEW; +EXCEPTION WHEN undefined_column THEN + -- Fallback for tables with different column names + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- Per-table triggers with correct columns +CREATE OR REPLACE FUNCTION update_domains_search() RETURNS trigger AS $$ +BEGIN + NEW.search_vector := to_tsvector('pg_catalog.english', coalesce(NEW.name, '')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_domains_search BEFORE INSERT OR UPDATE ON domains + FOR EACH ROW EXECUTE FUNCTION update_domains_search(); + +CREATE OR REPLACE FUNCTION update_areas_search() RETURNS trigger AS $$ +BEGIN + NEW.search_vector := to_tsvector('pg_catalog.english', + coalesce(NEW.name, '') || ' ' || coalesce(NEW.description, '')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_areas_search BEFORE INSERT OR UPDATE ON areas + FOR EACH ROW EXECUTE FUNCTION update_areas_search(); + +CREATE OR REPLACE FUNCTION update_projects_search() RETURNS trigger AS $$ +BEGIN + NEW.search_vector := to_tsvector('pg_catalog.english', + coalesce(NEW.name, '') || ' ' || coalesce(NEW.description, '') || ' ' || + coalesce(array_to_string(NEW.tags, ' '), '')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_projects_search BEFORE INSERT OR UPDATE ON projects + FOR EACH ROW EXECUTE FUNCTION update_projects_search(); + +CREATE OR REPLACE FUNCTION update_tasks_search() RETURNS trigger AS $$ +BEGIN + NEW.search_vector := to_tsvector('pg_catalog.english', + coalesce(NEW.title, '') || ' ' || coalesce(NEW.description, '') || ' ' || + coalesce(array_to_string(NEW.tags, ' '), '')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_tasks_search BEFORE INSERT OR UPDATE ON tasks + FOR EACH ROW EXECUTE FUNCTION update_tasks_search(); + +CREATE OR REPLACE FUNCTION update_notes_search() RETURNS trigger AS $$ +BEGIN + NEW.search_vector := to_tsvector('pg_catalog.english', + coalesce(NEW.title, '') || ' ' || coalesce(NEW.body, '') || ' ' || + coalesce(array_to_string(NEW.tags, ' '), '')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_notes_search BEFORE INSERT OR UPDATE ON notes + FOR EACH ROW EXECUTE FUNCTION update_notes_search(); + +CREATE OR REPLACE FUNCTION update_contacts_search() RETURNS trigger AS $$ +BEGIN + NEW.search_vector := to_tsvector('pg_catalog.english', + coalesce(NEW.first_name, '') || ' ' || coalesce(NEW.last_name, '') || ' ' || + coalesce(NEW.company, '') || ' ' || coalesce(NEW.email, '') || ' ' || + coalesce(array_to_string(NEW.tags, ' '), '')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_contacts_search BEFORE INSERT OR UPDATE ON contacts + FOR EACH ROW EXECUTE FUNCTION update_contacts_search(); + +CREATE OR REPLACE FUNCTION update_meetings_search() RETURNS trigger AS $$ +BEGIN + NEW.search_vector := to_tsvector('pg_catalog.english', + coalesce(NEW.title, '') || ' ' || coalesce(NEW.agenda, '') || ' ' || + coalesce(NEW.notes_body, '') || ' ' || + coalesce(array_to_string(NEW.tags, ' '), '')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_meetings_search BEFORE INSERT OR UPDATE ON meetings + FOR EACH ROW EXECUTE FUNCTION update_meetings_search(); + +CREATE OR REPLACE FUNCTION update_decisions_search() RETURNS trigger AS $$ +BEGIN + NEW.search_vector := to_tsvector('pg_catalog.english', + coalesce(NEW.title, '') || ' ' || coalesce(NEW.rationale, '') || ' ' || + coalesce(array_to_string(NEW.tags, ' '), '')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_decisions_search BEFORE INSERT OR UPDATE ON decisions + FOR EACH ROW EXECUTE FUNCTION update_decisions_search(); + +CREATE OR REPLACE FUNCTION update_lists_search() RETURNS trigger AS $$ +BEGIN + NEW.search_vector := to_tsvector('pg_catalog.english', + coalesce(NEW.name, '') || ' ' || coalesce(NEW.description, '') || ' ' || + coalesce(array_to_string(NEW.tags, ' '), '')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_lists_search BEFORE INSERT OR UPDATE ON lists + FOR EACH ROW EXECUTE FUNCTION update_lists_search(); + +CREATE OR REPLACE FUNCTION update_links_search() RETURNS trigger AS $$ +BEGIN + NEW.search_vector := to_tsvector('pg_catalog.english', + coalesce(NEW.label, '') || ' ' || coalesce(NEW.url, '') || ' ' || + coalesce(NEW.description, '') || ' ' || + coalesce(array_to_string(NEW.tags, ' '), '')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_links_search BEFORE INSERT OR UPDATE ON links + FOR EACH ROW EXECUTE FUNCTION update_links_search(); + +CREATE OR REPLACE FUNCTION update_files_search() RETURNS trigger AS $$ +BEGIN + NEW.search_vector := to_tsvector('pg_catalog.english', + coalesce(NEW.original_filename, '') || ' ' || coalesce(NEW.description, '') || ' ' || + coalesce(array_to_string(NEW.tags, ' '), '')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_files_search BEFORE INSERT OR UPDATE ON files + FOR EACH ROW EXECUTE FUNCTION update_files_search(); + +CREATE OR REPLACE FUNCTION update_weblinks_search() RETURNS trigger AS $$ +BEGIN + NEW.search_vector := to_tsvector('pg_catalog.english', + coalesce(NEW.label, '') || ' ' || coalesce(NEW.url, '') || ' ' || + coalesce(NEW.description, '') || ' ' || + coalesce(array_to_string(NEW.tags, ' '), '')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_weblinks_search BEFORE INSERT OR UPDATE ON weblinks + FOR EACH ROW EXECUTE FUNCTION update_weblinks_search(); + +CREATE OR REPLACE FUNCTION update_processes_search() RETURNS trigger AS $$ +BEGIN + NEW.search_vector := to_tsvector('pg_catalog.english', + coalesce(NEW.name, '') || ' ' || coalesce(NEW.description, '') || ' ' || + coalesce(array_to_string(NEW.tags, ' '), '')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_processes_search BEFORE INSERT OR UPDATE ON processes + FOR EACH ROW EXECUTE FUNCTION update_processes_search(); + +CREATE OR REPLACE FUNCTION update_appointments_search() RETURNS trigger AS $$ +BEGIN + NEW.search_vector := to_tsvector('pg_catalog.english', + coalesce(NEW.title, '') || ' ' || coalesce(NEW.description, '') || ' ' || + coalesce(NEW.location, '') || ' ' || + coalesce(array_to_string(NEW.tags, ' '), '')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_appointments_search BEFORE INSERT OR UPDATE ON appointments + FOR EACH ROW EXECUTE FUNCTION update_appointments_search(); + +CREATE OR REPLACE FUNCTION update_releases_search() RETURNS trigger AS $$ +BEGIN + NEW.search_vector := to_tsvector('pg_catalog.english', + coalesce(NEW.name, '') || ' ' || coalesce(NEW.description, '') || ' ' || + coalesce(NEW.version_label, '') || ' ' || + coalesce(array_to_string(NEW.tags, ' '), '')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_releases_search BEFORE INSERT OR UPDATE ON releases + FOR EACH ROW EXECUTE FUNCTION update_releases_search(); + +-- ============================================================================= +-- SEED DATA: Context Types +-- ============================================================================= + +INSERT INTO context_types (value, label, is_system, sort_order) VALUES + ('deep_work', 'Deep Work', true, 10), + ('quick', 'Quick', true, 20), + ('waiting', 'Waiting', true, 30), + ('someday', 'Someday', true, 40), + ('meeting', 'Meeting', true, 50), + ('errand', 'Errand', true, 60); diff --git a/project-docs/lifeos_schema_r1.sql b/project-docs/lifeos_schema_r1.sql new file mode 100644 index 0000000..7f1f33c --- /dev/null +++ b/project-docs/lifeos_schema_r1.sql @@ -0,0 +1,358 @@ +-- ============================================================================= +-- Life OS - Release 1 Schema +-- Self-hosted PostgreSQL on defiant-01 (Hetzner) +-- ============================================================================= + +CREATE EXTENSION IF NOT EXISTS "pgcrypto"; + +-- ============================================================================= +-- SYSTEM LEVEL: Context Types +-- ============================================================================= + +CREATE TABLE context_types ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL UNIQUE, + label TEXT NOT NULL, + description TEXT, + is_system BOOLEAN NOT NULL DEFAULT true, + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- ORGANIZATIONAL HIERARCHY +-- ============================================================================= + +CREATE TABLE domains ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name TEXT NOT NULL, + color TEXT, + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE areas ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + domain_id UUID NOT NULL REFERENCES domains(id) ON DELETE CASCADE, + name TEXT NOT NULL, + description TEXT, + status TEXT NOT NULL DEFAULT 'active', + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE projects ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + domain_id UUID NOT NULL REFERENCES domains(id) ON DELETE CASCADE, + area_id UUID REFERENCES areas(id) ON DELETE SET NULL, + name TEXT NOT NULL, + description TEXT, + status TEXT NOT NULL DEFAULT 'active', + priority INTEGER NOT NULL DEFAULT 3, + start_date DATE, + target_date DATE, + completed_at TIMESTAMPTZ, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE tasks ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + domain_id UUID NOT NULL REFERENCES domains(id) ON DELETE CASCADE, + area_id UUID REFERENCES areas(id) ON DELETE SET NULL, + project_id UUID REFERENCES projects(id) ON DELETE SET NULL, + parent_id UUID REFERENCES tasks(id) ON DELETE SET NULL, + title TEXT NOT NULL, + description TEXT, + priority INTEGER NOT NULL DEFAULT 3, + status TEXT NOT NULL DEFAULT 'open', + due_date DATE, + deadline TIMESTAMPTZ, + recurrence TEXT, + tags TEXT[], + context TEXT, + is_custom_context BOOLEAN NOT NULL DEFAULT false, + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + completed_at TIMESTAMPTZ +); + +CREATE TABLE notes ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + domain_id UUID NOT NULL REFERENCES domains(id) ON DELETE CASCADE, + title TEXT NOT NULL, + body TEXT, + content_format TEXT NOT NULL DEFAULT 'rich', + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE lists ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + domain_id UUID NOT NULL REFERENCES domains(id) ON DELETE CASCADE, + area_id UUID REFERENCES areas(id) ON DELETE SET NULL, + project_id UUID REFERENCES projects(id) ON DELETE SET NULL, + name TEXT NOT NULL, + list_type TEXT NOT NULL DEFAULT 'checklist', + description TEXT, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE list_items ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + list_id UUID NOT NULL REFERENCES lists(id) ON DELETE CASCADE, + parent_item_id UUID REFERENCES list_items(id) ON DELETE SET NULL, + content TEXT NOT NULL, + completed BOOLEAN NOT NULL DEFAULT false, + completed_at TIMESTAMPTZ, + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE links ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + domain_id UUID NOT NULL REFERENCES domains(id) ON DELETE CASCADE, + area_id UUID REFERENCES areas(id) ON DELETE SET NULL, + project_id UUID REFERENCES projects(id) ON DELETE SET NULL, + label TEXT NOT NULL, + url TEXT NOT NULL, + description TEXT, + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE files ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + filename TEXT NOT NULL, + original_filename TEXT NOT NULL, + storage_path TEXT NOT NULL, + mime_type TEXT, + size_bytes INTEGER, + description TEXT, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- SYSTEM LEVEL: Contacts +-- ============================================================================= + +CREATE TABLE contacts ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name TEXT NOT NULL, + company TEXT, + role TEXT, + email TEXT, + phone TEXT, + notes TEXT, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- SYSTEM LEVEL: Appointments +-- ============================================================================= + +CREATE TABLE appointments ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + title TEXT NOT NULL, + description TEXT, + location TEXT, + start_at TIMESTAMPTZ NOT NULL, + end_at TIMESTAMPTZ, + all_day BOOLEAN NOT NULL DEFAULT false, + recurrence TEXT, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- SYSTEM LEVEL: Weblink Directory +-- ============================================================================= + +CREATE TABLE weblink_folders ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + parent_id UUID REFERENCES weblink_folders(id) ON DELETE CASCADE, + name TEXT NOT NULL, + auto_generated BOOLEAN NOT NULL DEFAULT false, + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE weblinks ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label TEXT NOT NULL, + url TEXT NOT NULL, + description TEXT, + tags TEXT[], + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- SYSTEM LEVEL: Daily Focus +-- ============================================================================= + +CREATE TABLE daily_focus ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + focus_date DATE NOT NULL, + task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE, + slot INTEGER, + completed BOOLEAN NOT NULL DEFAULT false, + note TEXT, + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- SYSTEM LEVEL: Capture Queue +-- ============================================================================= + +CREATE TABLE capture ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + raw_text TEXT NOT NULL, + processed BOOLEAN NOT NULL DEFAULT false, + converted_to_type TEXT, + converted_to_id UUID, + area_id UUID REFERENCES areas(id) ON DELETE SET NULL, + project_id UUID REFERENCES projects(id) ON DELETE SET NULL, + list_id UUID REFERENCES lists(id) ON DELETE SET NULL, + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- SYSTEM LEVEL: Reminders +-- ============================================================================= + +CREATE TABLE reminders ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE, + remind_at TIMESTAMPTZ NOT NULL, + delivered BOOLEAN NOT NULL DEFAULT false, + channel TEXT NOT NULL DEFAULT 'web', + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- ============================================================================= +-- JUNCTION TABLES +-- ============================================================================= + +-- Notes <-> Projects (M2M) +CREATE TABLE note_projects ( + note_id UUID NOT NULL REFERENCES notes(id) ON DELETE CASCADE, + project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, + is_primary BOOLEAN NOT NULL DEFAULT false, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (note_id, project_id) +); + +-- Files <-> any entity (polymorphic M2M) +CREATE TABLE file_mappings ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + file_id UUID NOT NULL REFERENCES files(id) ON DELETE CASCADE, + context_type TEXT NOT NULL, + context_id UUID NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + UNIQUE (file_id, context_type, context_id) +); + +-- Contacts <-> Tasks +CREATE TABLE contact_tasks ( + contact_id UUID NOT NULL REFERENCES contacts(id) ON DELETE CASCADE, + task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE, + role TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (contact_id, task_id) +); + +-- Contacts <-> Lists +CREATE TABLE contact_lists ( + contact_id UUID NOT NULL REFERENCES contacts(id) ON DELETE CASCADE, + list_id UUID NOT NULL REFERENCES lists(id) ON DELETE CASCADE, + role TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (contact_id, list_id) +); + +-- Contacts <-> List Items +CREATE TABLE contact_list_items ( + contact_id UUID NOT NULL REFERENCES contacts(id) ON DELETE CASCADE, + list_item_id UUID NOT NULL REFERENCES list_items(id) ON DELETE CASCADE, + role TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (contact_id, list_item_id) +); + +-- Contacts <-> Projects +CREATE TABLE contact_projects ( + contact_id UUID NOT NULL REFERENCES contacts(id) ON DELETE CASCADE, + project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, + role TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (contact_id, project_id) +); + +-- Contacts <-> Appointments +CREATE TABLE contact_appointments ( + contact_id UUID NOT NULL REFERENCES contacts(id) ON DELETE CASCADE, + appointment_id UUID NOT NULL REFERENCES appointments(id) ON DELETE CASCADE, + role TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (contact_id, appointment_id) +); + +-- Weblinks <-> Folders (M2M) +CREATE TABLE folder_weblinks ( + folder_id UUID NOT NULL REFERENCES weblink_folders(id) ON DELETE CASCADE, + weblink_id UUID NOT NULL REFERENCES weblinks(id) ON DELETE CASCADE, + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (folder_id, weblink_id) +); + +-- ============================================================================= +-- INDEXES +-- ============================================================================= + +-- Sort order indexes (used on every list render) +CREATE INDEX idx_domains_sort ON domains(sort_order); +CREATE INDEX idx_areas_sort ON areas(domain_id, sort_order); +CREATE INDEX idx_projects_sort ON projects(domain_id, sort_order); +CREATE INDEX idx_projects_area_sort ON projects(area_id, sort_order); +CREATE INDEX idx_tasks_project_sort ON tasks(project_id, sort_order); +CREATE INDEX idx_tasks_parent_sort ON tasks(parent_id, sort_order); +CREATE INDEX idx_tasks_domain_sort ON tasks(domain_id, sort_order); +CREATE INDEX idx_list_items_sort ON list_items(list_id, sort_order); +CREATE INDEX idx_list_items_parent_sort ON list_items(parent_item_id, sort_order); +CREATE INDEX idx_weblinks_sort ON weblink_folders(parent_id, sort_order); + +-- Lookup indexes +CREATE INDEX idx_tasks_status ON tasks(status); +CREATE INDEX idx_tasks_due_date ON tasks(due_date); +CREATE INDEX idx_tasks_priority ON tasks(priority); +CREATE INDEX idx_projects_status ON projects(status); +CREATE INDEX idx_daily_focus_date ON daily_focus(focus_date); +CREATE INDEX idx_appointments_start ON appointments(start_at); +CREATE INDEX idx_capture_processed ON capture(processed); +CREATE INDEX idx_file_mappings_context ON file_mappings(context_type, context_id); + diff --git a/project-docs/setup_dev_database.sh b/project-docs/setup_dev_database.sh new file mode 100644 index 0000000..0b42fcb --- /dev/null +++ b/project-docs/setup_dev_database.sh @@ -0,0 +1,122 @@ +#!/bin/bash +# ============================================================================= +# Life OS - Step 1: DEV Database Setup +# Applies R1 schema to lifeos_dev, migrates data from lifeos_prod (R0) +# Run on: defiant-01 as root +# ============================================================================= + +set -e + +DB_CONTAINER="lifeos-db" +DB_USER="postgres" +DEV_DB="lifeos_dev" +PROD_DB="lifeos_prod" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +section() { + echo "" + echo "==============================================" + echo " $1" + echo "==============================================" +} + +# ============================================================================= +# 1. Verify prerequisites +# ============================================================================= +section "1. Verifying prerequisites" + +echo "Checking lifeos-db container..." +if ! docker ps | grep -q "$DB_CONTAINER"; then + echo "ERROR: $DB_CONTAINER is not running" + exit 1 +fi +echo "OK: $DB_CONTAINER is running" + +echo "Checking lifeos_dev database exists..." +DEV_EXISTS=$(docker exec $DB_CONTAINER psql -U $DB_USER -tc "SELECT 1 FROM pg_database WHERE datname='$DEV_DB'" | tr -d ' ') +if [ "$DEV_EXISTS" != "1" ]; then + echo "ERROR: $DEV_DB database does not exist" + exit 1 +fi +echo "OK: $DEV_DB exists" + +echo "Checking lifeos_prod database exists..." +PROD_EXISTS=$(docker exec $DB_CONTAINER psql -U $DB_USER -tc "SELECT 1 FROM pg_database WHERE datname='$PROD_DB'" | tr -d ' ') +if [ "$PROD_EXISTS" != "1" ]; then + echo "ERROR: $PROD_DB database does not exist" + exit 1 +fi +echo "OK: $PROD_DB exists" + +echo "Checking R0 data in lifeos_prod..." +R0_DOMAINS=$(docker exec $DB_CONTAINER psql -U $DB_USER -d $PROD_DB -tc "SELECT count(*) FROM domains" 2>/dev/null | tr -d ' ') +echo "R0 domains count: $R0_DOMAINS" +if [ "$R0_DOMAINS" = "0" ] || [ -z "$R0_DOMAINS" ]; then + echo "WARNING: No domains found in lifeos_prod. Migration will produce empty tables." +fi + +# ============================================================================= +# 2. Drop existing R1 tables in lifeos_dev (clean slate) +# ============================================================================= +section "2. Cleaning lifeos_dev (drop all tables)" + +docker exec $DB_CONTAINER psql -U $DB_USER -d $DEV_DB -c " + DROP SCHEMA public CASCADE; + CREATE SCHEMA public; + GRANT ALL ON SCHEMA public TO $DB_USER; + GRANT ALL ON SCHEMA public TO public; +" +echo "OK: lifeos_dev schema reset" + +# ============================================================================= +# 3. Apply R1 schema +# ============================================================================= +section "3. Applying R1 schema to lifeos_dev" + +docker exec -i $DB_CONTAINER psql -U $DB_USER -d $DEV_DB < "$SCRIPT_DIR/lifeos_r1_full_schema.sql" +echo "OK: R1 schema applied" + +# Verify table count +TABLE_COUNT=$(docker exec $DB_CONTAINER psql -U $DB_USER -d $DEV_DB -tc " + SELECT count(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_type = 'BASE TABLE' +" | tr -d ' ') +echo "Tables created: $TABLE_COUNT" + +# ============================================================================= +# 4. Run data migration (R0 -> R1) +# ============================================================================= +section "4. Migrating data from lifeos_prod (R0) to lifeos_dev (R1)" + +docker exec -i $DB_CONTAINER psql -U $DB_USER -d $DEV_DB < "$SCRIPT_DIR/lifeos_r0_to_r1_migration.sql" +echo "OK: Data migration complete" + +# ============================================================================= +# 5. Final verification +# ============================================================================= +section "5. Final verification" + +echo "R1 table row counts:" +docker exec $DB_CONTAINER psql -U $DB_USER -d $DEV_DB -c " + SELECT 'domains' as table_name, count(*) FROM domains UNION ALL + SELECT 'areas', count(*) FROM areas UNION ALL + SELECT 'projects', count(*) FROM projects UNION ALL + SELECT 'tasks', count(*) FROM tasks UNION ALL + SELECT 'notes', count(*) FROM notes UNION ALL + SELECT 'links', count(*) FROM links UNION ALL + SELECT 'daily_focus', count(*) FROM daily_focus UNION ALL + SELECT 'capture', count(*) FROM capture UNION ALL + SELECT 'context_types', count(*) FROM context_types UNION ALL + SELECT 'contacts', count(*) FROM contacts UNION ALL + SELECT 'meetings', count(*) FROM meetings UNION ALL + SELECT 'decisions', count(*) FROM decisions UNION ALL + SELECT 'releases', count(*) FROM releases UNION ALL + SELECT 'processes', count(*) FROM processes + ORDER BY table_name; +" + +echo "" +echo "==============================================" +echo " DEV database setup complete." +echo " lifeos_dev has R1 schema + migrated R0 data." +echo " lifeos_prod R0 data is UNTOUCHED." +echo "==============================================" diff --git a/project-docs/setup_prod_database.sh b/project-docs/setup_prod_database.sh new file mode 100644 index 0000000..e4b027d --- /dev/null +++ b/project-docs/setup_prod_database.sh @@ -0,0 +1,118 @@ +#!/bin/bash +# ============================================================================= +# Life OS - PROD Database Setup +# Backs up lifeos_dev (R1) and restores to lifeos_prod +# Run AFTER DEV is fully tested and confirmed working +# Run on: defiant-01 as root +# ============================================================================= + +set -e + +DB_CONTAINER="lifeos-db" +DB_USER="postgres" +DEV_DB="lifeos_dev" +PROD_DB="lifeos_prod" +BACKUP_DIR="/opt/lifeos/backups" +TIMESTAMP=$(date +%Y%m%d_%H%M%S) +BACKUP_FILE="$BACKUP_DIR/dev_to_prod_${TIMESTAMP}.sql" + +section() { + echo "" + echo "==============================================" + echo " $1" + echo "==============================================" +} + +# ============================================================================= +# 1. Verify prerequisites +# ============================================================================= +section "1. Verifying prerequisites" + +if ! docker ps | grep -q "$DB_CONTAINER"; then + echo "ERROR: $DB_CONTAINER is not running" + exit 1 +fi +echo "OK: $DB_CONTAINER is running" + +mkdir -p "$BACKUP_DIR" + +# ============================================================================= +# 2. Backup current lifeos_prod (safety net) +# ============================================================================= +section "2. Backing up current lifeos_prod (R0 safety copy)" + +docker exec $DB_CONTAINER pg_dump -U $DB_USER $PROD_DB | gzip > "$BACKUP_DIR/prod_r0_backup_${TIMESTAMP}.sql.gz" +echo "OK: R0 prod backup saved to $BACKUP_DIR/prod_r0_backup_${TIMESTAMP}.sql.gz" + +# ============================================================================= +# 3. Backup lifeos_dev (source for PROD) +# ============================================================================= +section "3. Backing up lifeos_dev (R1 source)" + +docker exec $DB_CONTAINER pg_dump -U $DB_USER --clean --if-exists $DEV_DB > "$BACKUP_FILE" +echo "OK: DEV backup saved to $BACKUP_FILE" + +# ============================================================================= +# 4. Drop and recreate lifeos_prod with R1 data +# ============================================================================= +section "4. Replacing lifeos_prod with lifeos_dev contents" + +echo "WARNING: This will destroy the current lifeos_prod database." +echo "R0 backup is at: $BACKUP_DIR/prod_r0_backup_${TIMESTAMP}.sql.gz" +read -p "Continue? (yes/no): " CONFIRM +if [ "$CONFIRM" != "yes" ]; then + echo "Aborted." + exit 0 +fi + +# Drop and recreate prod database +docker exec $DB_CONTAINER psql -U $DB_USER -c " + SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '$PROD_DB' AND pid <> pg_backend_pid(); +" +docker exec $DB_CONTAINER psql -U $DB_USER -c "DROP DATABASE IF EXISTS $PROD_DB;" +docker exec $DB_CONTAINER psql -U $DB_USER -c "CREATE DATABASE $PROD_DB;" + +# Restore DEV backup into PROD +docker exec -i $DB_CONTAINER psql -U $DB_USER -d $PROD_DB < "$BACKUP_FILE" +echo "OK: lifeos_prod now contains R1 schema + data from DEV" + +# ============================================================================= +# 5. Verify +# ============================================================================= +section "5. Verification" + +echo "PROD table row counts:" +docker exec $DB_CONTAINER psql -U $DB_USER -d $PROD_DB -c " + SELECT 'domains' as table_name, count(*) FROM domains UNION ALL + SELECT 'areas', count(*) FROM areas UNION ALL + SELECT 'projects', count(*) FROM projects UNION ALL + SELECT 'tasks', count(*) FROM tasks UNION ALL + SELECT 'notes', count(*) FROM notes UNION ALL + SELECT 'links', count(*) FROM links UNION ALL + SELECT 'daily_focus', count(*) FROM daily_focus UNION ALL + SELECT 'capture', count(*) FROM capture UNION ALL + SELECT 'context_types', count(*) FROM context_types + ORDER BY table_name; +" + +# ============================================================================= +# 6. Setup automated daily backup cron +# ============================================================================= +section "6. Setting up automated daily backups" + +CRON_LINE="0 3 * * * docker exec $DB_CONTAINER pg_dump -U $DB_USER $PROD_DB | gzip > $BACKUP_DIR/prod_\$(date +\\%Y\\%m\\%d).sql.gz && find $BACKUP_DIR -name 'prod_*.sql.gz' -mtime +30 -delete" + +if crontab -l 2>/dev/null | grep -q "lifeos_prod"; then + echo "Backup cron already exists, skipping." +else + (crontab -l 2>/dev/null; echo "$CRON_LINE") | crontab - + echo "OK: Daily backup cron installed (3am, 30-day retention)" +fi + +echo "" +echo "==============================================" +echo " PROD setup complete." +echo " lifeos_prod now has R1 schema + data." +echo " R0 backup: $BACKUP_DIR/prod_r0_backup_${TIMESTAMP}.sql.gz" +echo " Daily backups configured." +echo "==============================================" diff --git a/setup-claude-code.sh b/setup-claude-code.sh new file mode 100644 index 0000000..98a46c0 --- /dev/null +++ b/setup-claude-code.sh @@ -0,0 +1,97 @@ +#!/bin/bash +# ============================================================================= +# Claude Code Setup for Life OS +# Run as: root on defiant-01 +# ============================================================================= +set -e + +echo "=== Claude Code Setup for Life OS ===" +echo "" + +# ----------------------------------------------------------------------------- +# Step 1: Install Node.js (required for Claude Code) +# ----------------------------------------------------------------------------- +echo "[1/5] Checking Node.js..." +if command -v node &> /dev/null; then + echo " Node.js already installed: $(node --version)" +else + echo " Installing Node.js 20 LTS..." + curl -fsSL https://deb.nodesource.com/setup_20.x | bash - + apt-get install -y nodejs + echo " Installed: $(node --version)" +fi + +echo " npm version: $(npm --version)" + +# ----------------------------------------------------------------------------- +# Step 2: Install Claude Code +# ----------------------------------------------------------------------------- +echo "" +echo "[2/5] Installing Claude Code..." +npm install -g @anthropic-ai/claude-code +echo " Claude Code installed: $(claude --version 2>/dev/null || echo 'run claude to verify')" + +# ----------------------------------------------------------------------------- +# Step 3: Create project-docs folder structure +# ----------------------------------------------------------------------------- +echo "" +echo "[3/5] Creating folder structure..." + +mkdir -p /opt/lifeos/dev/project-docs + +echo " /opt/lifeos/dev/project-docs/ <- Upload reference docs here" +echo " /opt/lifeos/dev/CLAUDE.md <- Will be placed here" + +# ----------------------------------------------------------------------------- +# Step 4: Place CLAUDE.md (if uploaded to project-docs already) +# ----------------------------------------------------------------------------- +echo "" +echo "[4/5] Checking for CLAUDE.md..." +if [ -f /opt/lifeos/dev/project-docs/CLAUDE.md ]; then + cp /opt/lifeos/dev/project-docs/CLAUDE.md /opt/lifeos/dev/CLAUDE.md + echo " CLAUDE.md copied to /opt/lifeos/dev/CLAUDE.md" +else + echo " CLAUDE.md not found in project-docs yet." + echo " Upload it, then run:" + echo " cp /opt/lifeos/dev/project-docs/CLAUDE.md /opt/lifeos/dev/CLAUDE.md" +fi + +# ----------------------------------------------------------------------------- +# Step 5: Summary +# ----------------------------------------------------------------------------- +echo "" +echo "[5/5] Summary" +echo "" +echo " Folder structure:" +echo " /opt/lifeos/dev/" +echo " CLAUDE.md <- Claude Code reads this automatically" +echo " project-docs/ <- Reference documents" +echo " lifeos-architecture.docx" +echo " lifeos-development-status-convo4.md" +echo " lifeos-development-status-test1.md" +echo " ... (all project reference files)" +echo " main.py" +echo " core/" +echo " routers/" +echo " templates/" +echo " static/" +echo " tests/" +echo "" +echo "=== Next Steps ===" +echo "" +echo " 1. Upload project docs from your Windows machine:" +echo " scp C:\\lifeos-dev\\ubuntu\\* root@46.225.166.142:/opt/lifeos/dev/project-docs/" +echo "" +echo " 2. Upload CLAUDE.md separately:" +echo " scp C:\\lifeos-dev\\ubuntu\\CLAUDE.md root@46.225.166.142:/opt/lifeos/dev/CLAUDE.md" +echo "" +echo " 3. First run of Claude Code:" +echo " cd /opt/lifeos/dev && claude" +echo "" +echo " 4. You'll be prompted to authenticate with your Anthropic account." +echo " Follow the browser/URL instructions." +echo "" +echo " 5. Add CLAUDE.md to .gitignore (optional - keeps it out of the app repo):" +echo " echo 'CLAUDE.md' >> /opt/lifeos/dev/.gitignore" +echo " echo 'project-docs/' >> /opt/lifeos/dev/.gitignore" +echo ""