diff --git a/bluesky_httpserver/authenticators.py b/bluesky_httpserver/authenticators.py index 61c2da4..b270035 100644 --- a/bluesky_httpserver/authenticators.py +++ b/bluesky_httpserver/authenticators.py @@ -221,11 +221,11 @@ async def exchange_code(token_uri, auth_code, client_id, client_secret, redirect token_url ([type]): [description] auth_code ([type]): [description] """ - if not modules_available("httpx"): - raise ModuleNotFoundError("This authenticator requires 'httpx'. (pip install httpx)") - import httpx + if not modules_available("httpx2"): + raise ModuleNotFoundError("This authenticator requires 'httpx2'. (pip install httpx2)") + import httpx2 - response = httpx.post( + response = httpx2.post( url=token_uri, data={ "grant_type": "authorization_code", diff --git a/bluesky_httpserver/authorization/api_access.py b/bluesky_httpserver/authorization/api_access.py index 54263d9..55a3fd1 100644 --- a/bluesky_httpserver/authorization/api_access.py +++ b/bluesky_httpserver/authorization/api_access.py @@ -5,7 +5,7 @@ import time as ttime from collections.abc import Iterable -import httpx +import httpx2 import jsonschema import yaml @@ -610,7 +610,7 @@ async def update_access_info(self): Send a single request to the API server and update locally stored access control info. """ access_api = f"/instrument/{self._instrument.lower()}/qserver/access" - async with httpx.AsyncClient(base_url=self._base_url, timeout=self._http_timeout) as client: + async with httpx2.AsyncClient(base_url=self._base_url, timeout=self._http_timeout) as client: response = await client.get(access_api) response.raise_for_status() groups = response.json() diff --git a/bluesky_httpserver/database/base.py b/bluesky_httpserver/database/base.py index 9da1233..f8e4cc8 100644 --- a/bluesky_httpserver/database/base.py +++ b/bluesky_httpserver/database/base.py @@ -1,4 +1,4 @@ -from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import declarative_base # Everything imports this so we put it in its own module to # avoid circular imports. diff --git a/bluesky_httpserver/schemas.py b/bluesky_httpserver/schemas.py index c52d8f2..db323b4 100644 --- a/bluesky_httpserver/schemas.py +++ b/bluesky_httpserver/schemas.py @@ -33,9 +33,11 @@ class Response(generic_model, Generic[DataT, LinksT, MetaT]): links: Optional[LinksT] = None meta: Optional[MetaT] = None - @pydantic.validator("error", always=True) - def check_consistency(cls, v, values): - if v is not None and values["data"] is not None: + @pydantic.field_validator("error", mode="after") + @classmethod + def check_consistency(cls, v, info): + values = info.data + if v is not None and values.get("data") is not None: raise ValueError("must not provide both data and error") if v is None and values.get("data") is None: raise ValueError("must provide data or error") @@ -291,7 +293,7 @@ class APIKeyRequestParams(pydantic.BaseModel): # Provide an example for expires_in. Otherwise, OpenAPI suggests lifetime=0. # If the user is not reading carefully, they will be frustrated when they # try to use the instantly-expiring API key! - expires_in: Optional[int] = pydantic.Field(..., example=600) # seconds - # scopes: Optional[List[str]] = pydantic.Field(..., example=["inherit"]) - scopes: Optional[List[str]] = pydantic.Field(default=["inherit"], example=["inherit"]) + expires_in: Optional[int] = pydantic.Field(..., json_schema_extra={"example": 600}) # seconds + # scopes: Optional[List[str]] = pydantic.Field(..., json_schema_extra={"example": ["inherit"]}) + scopes: Optional[List[str]] = pydantic.Field(default=["inherit"], json_schema_extra={"example": ["inherit"]}) note: Optional[str] = None diff --git a/requirements.txt b/requirements.txt index f465abd..033186a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,14 +2,15 @@ alembic bluesky-queueserver bluesky-queueserver-api fastapi +httpx2 ldap3 orjson pamela -pydantic +pydantic>2 pydantic-settings python-jose pyzmq -sqlalchemy +sqlalchemy>2 starlette typing-extensions;python_version<'3.8' uvicorn