diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4561fa5..f8f3a33 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,7 +54,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.10", "3.13"] + python-version: ["3.11", "3.13"] services: mongodb: @@ -106,7 +106,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.10", "3.13"] + python-version: ["3.11", "3.13"] steps: - uses: actions/checkout@v7 @@ -137,7 +137,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.10", "3.13"] + python-version: ["3.11", "3.13"] runs-on: [windows-latest, macos-latest] steps: diff --git a/docs/tutorials/installation.md b/docs/tutorials/installation.md index 019933f..52451c8 100644 --- a/docs/tutorials/installation.md +++ b/docs/tutorials/installation.md @@ -8,7 +8,7 @@ :::{tab-item} pip :sync: pip -You will need Python 3.10 or later. You can check your version of Python by +You will need Python 3.11 or later. You can check your version of Python by typing into a terminal: ```sh diff --git a/docs/tutorials/saving.md b/docs/tutorials/saving.md index c0a8d7f..178b30b 100644 --- a/docs/tutorials/saving.md +++ b/docs/tutorials/saving.md @@ -13,7 +13,7 @@ server dependencies. :::{tab-item} pip :sync: pip -You will need Python 3.10 or later. You can check your version of Python by +You will need Python 3.11 or later. You can check your version of Python by typing into a terminal: ```sh diff --git a/pyproject.toml b/pyproject.toml index 30d23f6..106307b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ description = "Integrations for using Tiled with Bluesky" readme = { file = "README.md", content-type = "text/markdown" } license = "BSD-3-Clause" license-files = ["LICENSE"] -requires-python = ">=3.10" +requires-python = ">=3.11" classifiers = [ "Development Status :: 1 - Planning", "Intended Audience :: Science/Research", @@ -24,7 +24,6 @@ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", @@ -36,13 +35,14 @@ dynamic = ["version"] dependencies = [ "dask", "event-model", + "httpx2", # the generation used by the tiled client since 0.2.21 "mongoquery", "ndindex", # imported by tiled.ndslice "numpy", "pandas", "pyarrow", "pytz", - "tiled[minimal-client] >=0.2.19", + "tiled[minimal-client] >=0.2.21", "tzlocal", "xarray", ] @@ -88,7 +88,7 @@ test = [ "redis-json-dict", "suitcase-mongo", "tifffile", - "tiled[server] >=0.2.19", + "tiled[server] >=0.2.21", ] dev = [{ include-group = "test" }] docs = [ @@ -133,6 +133,11 @@ filterwarnings = [ # so they remain readable; zarr warns that these dtypes have no stable Zarr V3 # specification yet. This warning is emitted by the (in-process) test server. "ignore:The data type .* does not have a Zarr V3 specification", + # SQLAlchemy 2.1 deprecates the `noload` loader strategy, which tiled's catalog + # ORM uses for the Webhook.node relationship. Raising this warning as an error + # inside `configure_mappers()` poisons every mapper in the (in-process) test + # server; third-party issue, to be fixed in tiled. + "ignore:The ``noload`` loader strategy is deprecated:DeprecationWarning", ] log_level = "INFO" testpaths = ["tests"] @@ -144,7 +149,7 @@ report.exclude_also = ['\.\.\.', 'if typing.TYPE_CHECKING:'] [tool.mypy] files = ["src", "tests"] -python_version = "3.10" +python_version = "3.11" warn_unused_configs = true strict = false enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] @@ -174,7 +179,7 @@ ignore = [ [tool.pylint] -py-version = "3.10" +py-version = "3.11" ignore-paths = [".*/_version.py"] reports.output-format = "colorized" similarities.ignore-imports = "yes" diff --git a/src/bluesky_tiled_plugins/clients/bluesky_run.py b/src/bluesky_tiled_plugins/clients/bluesky_run.py index 7be9ccf..83da862 100644 --- a/src/bluesky_tiled_plugins/clients/bluesky_run.py +++ b/src/bluesky_tiled_plugins/clients/bluesky_run.py @@ -1,7 +1,7 @@ import codecs import copy import functools -import httpx +import httpx2 import io import json import keyword @@ -534,13 +534,13 @@ def validate( msg = "Remote validation failed: " + "; ".join(notes) raise ValidationException(msg, self.item["id"]) - except httpx.HTTPStatusError as e: + except httpx2.HTTPStatusError as e: # Backcompatibility: if the server does not support validation endpoint, # it will return 404 Not Found error; in this case, attempt to validate # the data structure locally by the client itself (requires multiple # round-trips to the server, but better than nothing). - if response.status_code == httpx.codes.NOT_FOUND: + if response.status_code == httpx2.codes.NOT_FOUND: warnings.warn( "Tiled server does not support remote validation. " "Attempting to validate the data structure by the client.", diff --git a/src/bluesky_tiled_plugins/writing/tiled_writer.py b/src/bluesky_tiled_plugins/writing/tiled_writer.py index a95c63e..be50eb0 100644 --- a/src/bluesky_tiled_plugins/writing/tiled_writer.py +++ b/src/bluesky_tiled_plugins/writing/tiled_writer.py @@ -9,7 +9,7 @@ from typing import Any, Optional, cast import warnings -import httpx +import httpx2 import numpy import pyarrow from event_model import ( @@ -129,9 +129,7 @@ def concatenate_stream_datums(*docs: StreamDatum): "All StreamDatum documents must reference the same stream_resource." ) docs = tuple(sorted(docs, key=lambda doc: doc["indices"]["start"])) - for d1, d2 in zip( - docs[:-1], docs[1:] - ): # TODO: use itertools.pairwise(docs) in python 3.10+ + for d1, d2 in itertools.pairwise(docs): if d1["indices"]["stop"] != d2["indices"]["start"]: raise ValueError("StreamDatum documents must be consecutive.") @@ -908,9 +906,9 @@ def _append_with_retry(self, df_client: DataFrameClient, table, desc_name: str): try: df_client.append_partition(0, table) return - except (httpx.TransportError, httpx.HTTPStatusError) as err: + except (httpx2.TransportError, httpx2.HTTPStatusError) as err: if ( - isinstance(err, httpx.HTTPStatusError) + isinstance(err, httpx2.HTTPStatusError) and err.response.status_code < 500 and err.response.status_code != 429 ): diff --git a/tests/test_tiled_writer.py b/tests/test_tiled_writer.py index c2def29..3b53c24 100644 --- a/tests/test_tiled_writer.py +++ b/tests/test_tiled_writer.py @@ -6,7 +6,7 @@ from typing import cast from urllib.parse import parse_qs, urlparse -import httpx +import httpx2 from bluesky import RunEngine import bluesky.plan_stubs as bps @@ -1013,7 +1013,7 @@ def patched_event(name, doc): assert lines[6]["name"] == "stop" -class _LoseAppendResponseOnce(httpx.BaseTransport): +class _LoseAppendResponseOnce(httpx2.BaseTransport): """Forward the first PATCH /table/partition request to the wrapped transport -- so the server fully processes the append -- but raise ReadTimeout to the caller, simulating a lost response for an append that actually succeeded.""" @@ -1030,7 +1030,7 @@ def handle_request(self, request): and "/table/partition/" in str(request.url) ): self.tripped = True - raise httpx.ReadTimeout("Simulated lost response", request=request) + raise httpx2.ReadTimeout("Simulated lost response", request=request) return response