Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DM-48307: Updates for new ruff, mypy, Pydantic and Sqlalchemy changes #87

Merged
merged 9 commits into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: check-yaml
- id: check-toml

- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.6.4
rev: v0.8.6
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
17 changes: 3 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,9 @@ update-deps:
pip install --upgrade uv
uv pip install --upgrade pre-commit
pre-commit autoupdate
uv pip compile --upgrade --generate-hashes \
uv pip compile --upgrade --universal --generate-hashes \
--output-file requirements/main.txt requirements/main.in
uv pip compile --upgrade --generate-hashes \
uv pip compile --upgrade --universal --generate-hashes \
--output-file requirements/dev.txt requirements/dev.in
uv pip compile --upgrade --generate-hashes \
--output-file requirements/tox.txt requirements/tox.in

# Useful for testing against a Git version of Safir.
.PHONY: update-deps-no-hashes
update-deps-no-hashes:
pip install --upgrade uv
uv pip compile --upgrade \
--output-file requirements/main.txt requirements/main.in
uv pip compile --upgrade \
--output-file requirements/dev.txt requirements/dev.in
uv pip compile --upgrade \
uv pip compile --upgrade --universal --generate-hashes \
--output-file requirements/tox.txt requirements/tox.in
20 changes: 20 additions & 0 deletions changelog.d/20250106_164329_jsick_DM_48307.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!-- Delete the sections that don't apply -->

### Backwards-incompatible changes

-

### New features

-

### Bug fixes

-

### Other changes

- Update the `make update` command in the Makefile to use the `--universal` flag with `uv pip compile`.
- Begin SQLAlchemy 2 migration by adopting the new `DeclarativeBase`, `mapped_column`, and the `Mapped` type.
- Fix type checking issues for Pydantic fields to use empty lists as the default, rather than using a default factory.
- Explicitly set `asyncio_default_fixture_loop_scope` to function. An explicit setting is now required by pytest-asyncio.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ exclude_lines = [
]

[tool.pytest.ini_options]
asyncio_default_fixture_loop_scope = "function"
asyncio_mode = "strict"
python_files = [
"tests/*.py",
Expand Down
1 change: 1 addition & 0 deletions requirements/dev.in
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ respx
types-PyYAML
documenteer[guide]>=1.0
httpx-sse == 0.4.0
scriv
1,630 changes: 927 additions & 703 deletions requirements/dev.txt

Large diffs are not rendered by default.

1,996 changes: 1,094 additions & 902 deletions requirements/main.txt

Large diffs are not rendered by default.

317 changes: 172 additions & 145 deletions requirements/tox.txt

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/timessquare/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from safir.logging import LogLevel, Profile
from safir.pydantic import EnvAsyncPostgresDsn, EnvRedisDsn

__all__ = ["Config", "Profile", "LogLevel"]
__all__ = ["Config", "LogLevel", "Profile"]


class Config(BaseSettings):
Expand Down
6 changes: 4 additions & 2 deletions src/timessquare/dbschema/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

from __future__ import annotations

from sqlalchemy.orm import declarative_base
from sqlalchemy.orm import DeclarativeBase

__all__ = ["Base"]

Base = declarative_base()

class Base(DeclarativeBase):
"""The base class for all SQLAlchemy table schemas."""
53 changes: 31 additions & 22 deletions src/timessquare/dbschema/page.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
from datetime import datetime
from typing import Any

from sqlalchemy import JSON, Column, DateTime, Integer, Unicode, UnicodeText
from sqlalchemy import JSON, DateTime, Integer, Unicode, UnicodeText
from sqlalchemy.orm import Mapped, mapped_column

from .base import Base

Expand All @@ -31,73 +32,77 @@ class SqlPage(Base):

__tablename__ = "pages"

name: str = Column(
name: Mapped[str] = mapped_column(
Unicode(32), primary_key=True, default=lambda: uuid.uuid4().hex
)
"""The primary key, and also the ID for the Page REST API."""

ipynb: str = Column(UnicodeText, nullable=False)
ipynb: Mapped[str] = mapped_column(UnicodeText, nullable=False)
"""The Jinja-parameterized notebook, as a JSON-formatted string."""

parameters: dict[str, Any] = Column(JSON, nullable=False)
parameters: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=False)
"""Parameters and their jsonschema descriptors."""

title: str = Column(UnicodeText, nullable=False)
title: Mapped[str] = mapped_column(UnicodeText, nullable=False)
"""Display title of the notebook."""

date_added: datetime = Column(DateTime, nullable=False)
date_added: Mapped[datetime] = mapped_column(DateTime, nullable=False)
"""Date when the page is registered through the Times Square API."""

authors: list[dict[str, Any]] = Column(JSON, nullable=False)
authors: Mapped[list[dict[str, Any]]] = mapped_column(JSON, nullable=False)
"""Authors of the notebook.

The schema for this column is described by the NotebookSidecarFile
authors field schema.
"""

tags: list[str] = Column(JSON, nullable=False)
tags: Mapped[list[str]] = mapped_column(JSON, nullable=False)
"""Tags (keywords) assigned to this page."""

uploader_username: str | None = Column(Unicode(64), nullable=True)
uploader_username: Mapped[str | None] = mapped_column(
Unicode(64), nullable=True
)
"""Username of the uploader, if this page is uploaded without GitHub
backing.
"""

date_deleted: datetime | None = Column(DateTime)
date_deleted: Mapped[datetime | None] = mapped_column(DateTime)
"""A nullable datetime that is set to the datetime when the page is
soft-deleted.
"""

description: str | None = Column(UnicodeText)
description: Mapped[str | None] = mapped_column(UnicodeText)
"""Description of a page (markdown-formatted)."""

cache_ttl: int | None = Column(Integer)
cache_ttl: Mapped[int | None] = mapped_column(Integer)
"""The cache TTL (seconds) for HTML renders, or None to retain renders
indefinitely.
"""

github_owner: str | None = Column(Unicode(255))
github_owner: Mapped[str | None] = mapped_column(Unicode(255))
"""The GitHub repository owner (username or organization name) for
GitHub-backed pages.
"""

github_repo: str | None = Column(Unicode(255))
github_repo: Mapped[str | None] = mapped_column(Unicode(255))
"""The GitHub repository name for GitHub-backed pages."""

github_commit: str | None = Column(Unicode(40))
github_commit: Mapped[str | None] = mapped_column(Unicode(40))
"""The SHA of the commit this page corresponds to; only used for pages
associated with a GitHub Check Run.
"""

repository_path_prefix: str | None = Column(Unicode(2048))
repository_path_prefix: Mapped[str | None] = mapped_column(Unicode(2048))
"""The repository path prefix, relative to the root of the directory."""

repository_display_path_prefix: str | None = Column(Unicode(2048))
repository_display_path_prefix: Mapped[str | None] = mapped_column(
Unicode(2048)
)
"""The repository path prefix, relative to the configured root of Times
Square notebooks in a repository.
"""

repository_path_stem: str | None = Column(Unicode(255))
repository_path_stem: Mapped[str | None] = mapped_column(Unicode(255))
"""The filename stem (without prefix and without extension) of the
source file in the GitHub repository for GitHub-backed pages.

Expand All @@ -106,22 +111,26 @@ class SqlPage(Base):
the corresponding files.
"""

repository_source_extension: str | None = Column(Unicode(255))
repository_source_extension: Mapped[str | None] = mapped_column(
Unicode(255)
)
"""The filename extension of the source file in the GitHub
repository for GitHub-backed pages.

Combine with repository_path_stem to get the file path.
"""

repository_sidecar_extension: str | None = Column(Unicode(255))
repository_sidecar_extension: Mapped[str | None] = mapped_column(
Unicode(255)
)
"""The filename extension of the sidecar YAML file in the GitHub
repository for GitHub-backed pages.

Combine with repository_path_stem to get the file path.
"""

repository_source_sha: str | None = Column(Unicode(40))
repository_source_sha: Mapped[str | None] = mapped_column(Unicode(40))
"""The git tree sha of the source file for GitHub-backed pages."""

repository_sidecar_sha: str | None = Column(Unicode(40))
repository_sidecar_sha: Mapped[str | None] = mapped_column(Unicode(40))
"""The git tree sha of the sidecar YAML file for GitHub-backed pages."""
2 changes: 1 addition & 1 deletion src/timessquare/handlers/external/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from .githubwebhooks import router as webhook_router
from .models import Index

__all__ = ["get_index", "external_router", "post_github_webhook"]
__all__ = ["external_router", "get_index", "post_github_webhook"]

external_router = APIRouter()
"""FastAPI router for all external handlers."""
Expand Down
16 changes: 8 additions & 8 deletions src/timessquare/handlers/external/githubwebhooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,20 @@
from timessquare.config import config

__all__ = [
"router",
"handle_installation_created",
"handle_installation_unsuspend",
"handle_installation_deleted",
"handle_installation_suspend",
"handle_repositories_added",
"handle_repositories_removed",
"handle_check_run_created",
"handle_check_run_rerequested",
"handle_check_suite_request",
"handle_installation_created",
"handle_installation_deleted",
"handle_installation_suspend",
"handle_installation_unsuspend",
"handle_ping",
"handle_pr_opened",
"handle_pr_sync",
"handle_push_event",
"handle_ping",
"handle_repositories_added",
"handle_repositories_removed",
"router",
]


Expand Down
1 change: 0 additions & 1 deletion src/timessquare/handlers/internal.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
" a health check. This route is not exposed outside the cluster and"
" therefore cannot be used by external clients."
),
response_model=Metadata,
response_model_exclude_none=True,
summary="Application metadata",
include_in_schema=False,
Expand Down
10 changes: 0 additions & 10 deletions src/timessquare/handlers/v1/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@

@v1_router.get(
"/",
response_model=Index,
summary="v1 API metadata",
)
async def get_index(
Expand All @@ -104,7 +103,6 @@ async def get_index(

@v1_router.get(
"/pages/{page}",
response_model=Page,
summary="Page metadata",
name="get_page",
tags=[ApiTags.pages],
Expand Down Expand Up @@ -136,7 +134,6 @@ async def get_page(

@v1_router.get(
"/pages",
response_model=list[PageSummary],
summary="List pages",
name="get_pages",
tags=[ApiTags.pages],
Expand All @@ -156,7 +153,6 @@ async def get_pages(

@v1_router.post(
"/pages",
response_model=Page,
summary="Create a new page",
status_code=201,
tags=[ApiTags.pages],
Expand Down Expand Up @@ -378,7 +374,6 @@ async def get_page_html(
"/pages/{page}/html",
summary="Delete the cached HTML of a notebook.",
name="delete_page_html",
response_model=DeleteHtmlResponse,
tags=[ApiTags.pages],
responses={
404: {"description": "Cached HTML not found", "model": ErrorModel},
Expand Down Expand Up @@ -423,7 +418,6 @@ async def delete_page_html(
"/pages/{page}/htmlstatus",
summary="Get the status of a page's HTML rendering",
name="get_page_html_status",
response_model=HtmlStatus,
tags=[ApiTags.pages],
responses={
404: {"description": "Page not found", "model": ErrorModel},
Expand Down Expand Up @@ -498,7 +492,6 @@ async def get_page_html_events(
"/github",
summary="Get a tree of GitHub-backed pages",
name="get_github_tree",
response_model=GitHubContentsRoot,
tags=[ApiTags.github],
)
async def get_github_tree(
Expand All @@ -519,7 +512,6 @@ async def get_github_tree(

@v1_router.get(
"/github/{display_path:path}",
response_model=Page,
summary="Metadata for GitHub-backed page",
name="get_github_page",
tags=[ApiTags.github],
Expand Down Expand Up @@ -556,7 +548,6 @@ async def get_github_page(
"/github-pr/{owner}/{repo}/{commit}",
summary="Get a tree of GitHub PR preview pages",
name="get_github_pr_tree",
response_model=GitHubPrContents,
tags=[ApiTags.pr],
)
async def get_github_pr_tree(
Expand Down Expand Up @@ -607,7 +598,6 @@ async def get_github_pr_tree(

@v1_router.get(
"/github-pr/{owner}/{repo}/{commit}/{path:path}",
response_model=Page,
summary="Metadata for page in a pull request",
name="get_github_pr_page",
tags=[ApiTags.pr],
Expand Down
6 changes: 3 additions & 3 deletions src/timessquare/handlers/v1/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ class Index(BaseModel):
description="Date when the page was originally added.",
)

page_authors_field = Field(
default_factory=list,
page_authors_field: list[Person] = Field(
default=[],
title="Page authors",
description="Authors of the page",
)

page_tags_field = Field(default_factory=list, title="Tags (keywords)")
page_tags_field: list[str] = Field(default=[], title="Tags (keywords)")

page_url_field = Field(
...,
Expand Down
10 changes: 5 additions & 5 deletions src/timessquare/worker/functions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
from .repo_removed import repo_removed

__all__ = [
"ping",
"repo_push",
"repo_added",
"repo_removed",
"pull_request_sync",
"compute_check_run",
"create_check_run",
"create_rerequested_check_run",
"ping",
"pull_request_sync",
"replace_nbhtml",
"repo_added",
"repo_push",
"repo_removed",
]
Loading
Loading