diff --git a/docs/source/release-history.rst b/docs/source/release-history.rst index 4d1aaad..0b74c0b 100644 --- a/docs/source/release-history.rst +++ b/docs/source/release-history.rst @@ -3,6 +3,15 @@ Release History =============== +Unreleased +========== + +Removed +------- + +- Support for Python 3.10. The minimum supported Python version is now 3.11. + + v0.0.14 (2026-01-21) ==================== diff --git a/pixi.toml b/pixi.toml index 3b33d01..c8bfb72 100644 --- a/pixi.toml +++ b/pixi.toml @@ -8,7 +8,7 @@ version = "0.0.14" [tasks] [dependencies] -python = "*" +python = "<3.15" pip = "*" [pypi-dependencies] @@ -34,4 +34,3 @@ py311 = { features = ["py311"] } py312 = { features = ["py312"] } py313 = { features = ["py313"] } py314 = { features = ["py314"] } - diff --git a/pyproject.toml b/pyproject.toml index 187fb9e..5fd7d63 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,62 +5,62 @@ build-backend = "setuptools.build_meta" [project] name = "bluesky-httpserver" classifiers = [ - "Development Status :: 3 - Alpha", - "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", + "Development Status :: 3 - Alpha", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", ] description = "HTTP Server for communicating with Bluesky Queue Server." dependencies = [ - "alembic", - "bluesky-queueserver", - "bluesky-queueserver-api", - "cachetools", - "fastapi", - "httpx", - "ldap3", - "orjson", - "pamela", - "pydantic >=2, <3", - "pydantic-settings >=2", - "python-jose", - "pyzmq", - "sqlalchemy >=2", - "starlette", - "uvicorn", + "alembic", + "bluesky-queueserver", + "bluesky-queueserver-api", + "cachetools", + "fastapi", + "httpx", + "ldap3", + "orjson", + "pamela", + "pydantic >=2, <3", + "pydantic-settings >=2", + "python-jose", + "pyzmq", + "sqlalchemy >=2", + "starlette", + "uvicorn", ] dynamic = ["version"] license = { file = "LICENSE" } readme = "README.rst" -requires-python = ">=3.10" +requires-python = ">=3.11" [project.optional-dependencies] dev = [ - "codecov", - "coverage", - "ruff", - "cryptography", - "fastapi[all]", - "flake8", - "pre-commit", - "pytest", - "pytest-asyncio", - "pytest-xprocess", - "pytest-split", - "py", - "respx", - "sphinx", - "ipython", - "numpydoc", - "matplotlib", - "pandas", - "sphinx", - "sphinx_rtd_theme", - "requests", - "build", - "twine", + "codecov", + "coverage", + "ruff", + "cryptography", + "fastapi[all]", + "flake8", + "pre-commit", + "pytest", + "pytest-asyncio", + "pytest-xprocess", + "pytest-split", + "py", + "respx", + "sphinx", + "ipython", + "numpydoc", + "matplotlib", + "pandas", + "sphinx", + "sphinx_rtd_theme", + "requests", + "build", + "twine", ] [project.scripts] @@ -88,10 +88,10 @@ addopts = """ """ # https://iscinumpy.gitlab.io/post/bound-version-constraints/#watch-for-warnings filterwarnings = [ - "error", - "ignore::PendingDeprecationWarning", - "ignore::UserWarning", - "ignore::DeprecationWarning", + "error", + "ignore::PendingDeprecationWarning", + "ignore::UserWarning", + "ignore::DeprecationWarning", ] # Doctest python code in docs, python code in src docstrings, test functions in tests testpaths = "src/bluesky_httpserver/tests" @@ -110,39 +110,38 @@ source = ["src", "**/site-packages/"] src = ["src", "tests"] line-length = 115 exclude = [ - "docs/source/conf.py", - "docs/source/examples", - "src/bluesky_httpserver/_version.py", + "docs/source/conf.py", + "docs/source/examples", + "src/bluesky_httpserver/_version.py", ] [tool.ruff.lint] select = [ - "B", # flake8-bugbear - https://docs.astral.sh/ruff/rules/#flake8-bugbear-b - "C4", # flake8-comprehensions - https://docs.astral.sh/ruff/rules/#flake8-comprehensions-c4 - "E", # pycodestyle errors - https://docs.astral.sh/ruff/rules/#error-e - "F", # pyflakes rules - https://docs.astral.sh/ruff/rules/#pyflakes-f - "W", # pycodestyle warnings - https://docs.astral.sh/ruff/rules/#warning-w - "I", # isort - https://docs.astral.sh/ruff/rules/#isort-i - "UP", # pyupgrade - https://docs.astral.sh/ruff/rules/#pyupgrade-up + "B", # flake8-bugbear - https://docs.astral.sh/ruff/rules/#flake8-bugbear-b + "C4", # flake8-comprehensions - https://docs.astral.sh/ruff/rules/#flake8-comprehensions-c4 + "E", # pycodestyle errors - https://docs.astral.sh/ruff/rules/#error-e + "F", # pyflakes rules - https://docs.astral.sh/ruff/rules/#pyflakes-f + "W", # pycodestyle warnings - https://docs.astral.sh/ruff/rules/#warning-w + "I", # isort - https://docs.astral.sh/ruff/rules/#isort-i + "UP", # pyupgrade - https://docs.astral.sh/ruff/rules/#pyupgrade-up ] unfixable = [ - "F401", - "UP006", # ignore non-PEP 585 generic annotations (e.g. typing.List -> list) - "UP007", # e.g. typing.Union[int, float] -> int | float - "UP045", # e.g. typing.Optional[int] -> int | None + "F401", + "UP006", # ignore non-PEP 585 generic annotations (e.g. typing.List -> list) + "UP007", # e.g. typing.Union[int, float] -> int | float + "UP045", # e.g. typing.Optional[int] -> int | None ] ignore = [ - "B905", # adding strict=False to every zip call is just noise - "C408", # errors due to using dict() - "B011", # do not use 'assert False' error - "B008", # do not perform function call ... in argument defaults - "B006", # do not use mutable data structures for argument defaults - "B024", # abstract base class has no abstract methods or properties - "B026", # star-arg unpacking after a keyword argument is strongly discouraged - "B904", # ithin an `except` clause, raise exceptions with `raise ... from err` or `raise ... from None` -] -isort.required-imports = [ + "B905", # adding strict=False to every zip call is just noise + "C408", # errors due to using dict() + "B011", # do not use 'assert False' error + "B008", # do not perform function call ... in argument defaults + "B006", # do not use mutable data structures for argument defaults + "B024", # abstract base class has no abstract methods or properties + "B026", # star-arg unpacking after a keyword argument is strongly discouraged + "B904", # ithin an `except` clause, raise exceptions with `raise ... from err` or `raise ... from None` ] +isort.required-imports = [] [tool.black] line-length = 115 diff --git a/src/bluesky_httpserver/routers/core_api.py b/src/bluesky_httpserver/routers/core_api.py index 4501e88..af8cf70 100644 --- a/src/bluesky_httpserver/routers/core_api.py +++ b/src/bluesky_httpserver/routers/core_api.py @@ -1138,7 +1138,7 @@ async def _task(self): try: # The following will raise an exception if the socket is disconnected. await asyncio.wait_for(self._websocket.receive(), timeout=0.01) - except asyncio.TimeoutError: + except TimeoutError: # The socket is still connected. pass except Exception: @@ -1191,7 +1191,7 @@ async def _authenticate_websocket(websocket, scopes): await websocket.accept() try: message = await asyncio.wait_for(websocket.receive_json(), timeout=10) - except asyncio.TimeoutError: + except TimeoutError: await websocket.close(code=_WS_CLOSE_AUTH_REQUIRED, reason="Auth required") return None, True except WebSocketDisconnect: @@ -1226,7 +1226,7 @@ async def console_output_ws(websocket: WebSocket, scopes=["read:console"]): try: msg = await asyncio.wait_for(q.get(), timeout=1) await websocket.send_text(msg) - except asyncio.TimeoutError: + except TimeoutError: pass except RuntimeError: # 'send' after the client is disconnected pass @@ -1253,7 +1253,7 @@ async def status_ws(websocket: WebSocket, scopes=["read:monitor"]): try: msg = await asyncio.wait_for(q.get(), timeout=1) await websocket.send_text(msg) - except asyncio.TimeoutError: + except TimeoutError: pass except RuntimeError: # 'send' after the client is disconnected pass @@ -1279,7 +1279,7 @@ async def info_ws(websocket: WebSocket, scopes=["read:monitor"]): try: msg = await asyncio.wait_for(q.get(), timeout=1) await websocket.send_text(msg) - except asyncio.TimeoutError: + except TimeoutError: pass except RuntimeError: # 'send' after the client is disconnected pass diff --git a/src/bluesky_httpserver/schemas.py b/src/bluesky_httpserver/schemas.py index 2a8cf90..b8d717d 100644 --- a/src/bluesky_httpserver/schemas.py +++ b/src/bluesky_httpserver/schemas.py @@ -52,7 +52,7 @@ class PaginationLinks(pydantic.BaseModel): last: str -class EntryFields(str, enum.Enum): +class EntryFields(enum.StrEnum): metadata = "metadata" structure_family = "structure_family" microstructure = "structure.micro" @@ -182,7 +182,7 @@ class DeviceCodeResponse(pydantic.BaseModel): interval: int -class AuthenticationMode(str, enum.Enum): +class AuthenticationMode(enum.StrEnum): password = "password" external = "external" @@ -219,7 +219,7 @@ class About(pydantic.BaseModel): meta: dict -class PrincipalType(str, enum.Enum): +class PrincipalType(enum.StrEnum): user = "user" service = "service" # TODO Add support for services. diff --git a/src/bluesky_httpserver/utils.py b/src/bluesky_httpserver/utils.py index de2dbbd..f555cb2 100644 --- a/src/bluesky_httpserver/utils.py +++ b/src/bluesky_httpserver/utils.py @@ -181,7 +181,7 @@ def get_api_access_manager(): ) -class SpecialUsers(str, enum.Enum): +class SpecialUsers(enum.StrEnum): public = _DEFAULT_USERNAME_PUBLIC single_user = _DEFAULT_USERNAME_SINGLE_USER