Skip to content

Pydantic migration#1034

Merged
frankrousseau merged 19 commits intocgwire:mainfrom
frankrousseau:pydantic
Apr 8, 2026
Merged

Pydantic migration#1034
frankrousseau merged 19 commits intocgwire:mainfrom
frankrousseau:pydantic

Conversation

@frankrousseau
Copy link
Copy Markdown
Contributor

Problem

Argument validation is not easy to maintain.

Solution

Use Pydantic to validate data sent to the API.

frankrousseau and others added 14 commits April 8, 2026 09:48
When an asset is deleted but other entities reference it via parent_id,
the DELETE fails with IntegrityError (ForeignKeyViolation). Fix by
nullifying parent_id on child entities before deletion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The LocalBackend.path monkey-patch shards files into subdirectories
using the first 6 chars of the ID (designed for UUIDs). For dbbackup
files with names like "zou-db-backup-2026-...", this created broken
paths like dbbackup/zou/-db/ instead of a flat dbbackup/ directory.

Skip the UUID-based sharding for the "dbbackup" prefix so backup files
are stored directly under the dbbackup folder.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fixes cgwire#1032

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… v2 schemas

Replace deprecated get_args()/RequestParser in POST/PUT methods with
Pydantic v2 schemas across 16 blueprints (~80 endpoints). Create
BaseSchema with extra="forbid" in validation.py, fix existing persons
and playlists schemas, and add new schema modules for all remaining
blueprints. GET query param endpoints kept on ArgsMixin.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allow unknown fields to be silently dropped instead of rejected,
preserving backwards compatibility with clients that may send extra
fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace all abort() calls in blueprints with typed business exceptions
(WrongParameterException, *NotFoundException, PermissionDenied). Fix
except BaseException and bare except clauses to use except Exception.
Correct several wrong HTTP status codes (abort(404) for date format
errors now properly returns 400).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wrap memoize_function to deepcopy results when using SimpleCache
(in-memory), preventing callers from corrupting cached dicts/lists.
With Redis the serialization round-trip already produces fresh copies,
so no extra overhead is added in production.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fetch task IDs as scalars in remove_project to avoid the identity-map
refresh trap that crashed on expired ORM instances whose row had
already been deleted. Make remove_task tolerant of vanished rows.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Catch storage failures (Swift 401, S3 timeout, etc.) during source,
movie and thumbnail variant uploads in prepare_and_store_movie so
the worker logs the error and marks the preview as broken instead
of crashing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Delete EntityConceptLink rows on both entity_in_id and entity_out_id
sides before deleting entities to avoid FK violations when a project
holds either side of a concept link.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
frankrousseau and others added 5 commits April 8, 2026 15:24
Override LocalBackend.default_root to read FS_ROOT / FS_LOCAL_ROOT
without wrapping in `with current_app.app_context()`. The upstream
nested context teardown invokes Flask-SQLAlchemy's session.remove(),
which detached every ORM instance loaded in the outer request session
the first time a storage write hit the cached_property.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Deepcopying a SQLAlchemy ORM instance preserves its InstanceState in
a way that makes session.merge(load=False) reject the object as
"dirty", breaking get_person_raw_cached on every authenticated
request after a person mutation. ORM callers are expected to merge()
the cached instance, which already creates a session-owned copy and
leaves the cache untouched, so deepcopy adds nothing for that case.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fall back to request.values when no JSON body is present so clients
that POST credentials or params as URL args keep working (matches the
legacy ArgsMixin.get_args behavior). Treat a missing body as an empty
dict instead of raising 400, so schemas with all-optional fields
validate cleanly and required fields raise field-level errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
months_duration is an Integer column and daily_salary is a Float
column, but the schemas declared them as Optional[str], so Pydantic
rejected the numeric values clients send.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The SearchFilterGroup model defaults color to empty string and the
client may send "" intentionally, so the schema must not enforce
min_length=1.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@frankrousseau frankrousseau merged commit b946c43 into cgwire:main Apr 8, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant