From 5d12a0ea677105886d346d31e4bc09120e90bea7 Mon Sep 17 00:00:00 2001 From: galaxybot Date: Sat, 4 Apr 2026 03:51:29 +0000 Subject: [PATCH 1/3] Update Python dependencies by running `make update-dependencies`. --- lib/galaxy/dependencies/dev-requirements.txt | 92 ++++++------ .../dependencies/pinned-lint-requirements.txt | 4 +- .../dependencies/pinned-requirements.txt | 141 +++++++++--------- .../dependencies/pinned-test-requirements.txt | 82 +++++----- .../pinned-typecheck-requirements.txt | 22 +-- 5 files changed, 171 insertions(+), 170 deletions(-) diff --git a/lib/galaxy/dependencies/dev-requirements.txt b/lib/galaxy/dependencies/dev-requirements.txt index b24b3daf1ec..48e90daebfd 100644 --- a/lib/galaxy/dependencies/dev-requirements.txt +++ b/lib/galaxy/dependencies/dev-requirements.txt @@ -1,33 +1,33 @@ # This file was autogenerated by uv via the following command: # uv export --frozen --no-annotate --no-hashes --only-group=dev aiohappyeyeballs==2.6.1 -aiohttp==3.13.4 +aiohttp==3.13.5 aiosignal==1.4.0 alabaster==1.0.0 -ase==3.27.0 +ase==3.28.0 async-timeout==5.0.1 ; python_full_version < '3.11' -attrs==25.4.0 +attrs==26.1.0 axe-selenium-python==2.1.6 babel==2.18.0 backports-asyncio-runner==1.2.0 ; python_full_version < '3.11' backports-tarfile==1.2.0 ; python_full_version < '3.12' and platform_machine != 'ppc64le' and platform_machine != 's390x' black==26.3.1 -boto3==1.42.61 -botocore==1.42.61 -build==1.4.0 +boto3==1.42.70 +botocore==1.42.70 +build==1.4.2 cachecontrol==0.14.4 cachetools==7.0.5 cattrs==26.1.0 certifi==2026.2.25 cffi==2.0.0 ; (implementation_name != 'pypy' and os_name == 'nt') or platform_python_implementation != 'PyPy' -charset-normalizer==3.4.5 -click==8.3.1 +charset-normalizer==3.4.7 +click==8.3.2 codespell==2.4.2 colorama==0.4.6 ; os_name == 'nt' or sys_platform == 'win32' colorlog==6.10.1 contourpy==1.3.2 ; python_full_version < '3.11' contourpy==1.3.3 ; python_full_version >= '3.11' -coverage==7.13.4 +coverage==7.13.5 cryptography==46.0.7 cwltest==2.6.20251216093331 cycler==0.12.1 @@ -44,22 +44,22 @@ filelock==3.25.2 fluent-logger==0.11.1 fonttools==4.62.1 frozenlist==1.8.0 -fsspec==2026.2.0 +fsspec==2026.3.0 galaxy-release-util==0.3.2 -gcsfs==2026.2.0 -google-api-core==2.30.0 +gcsfs==2026.3.0 +google-api-core==2.30.2 google-auth==2.49.1 -google-auth-oauthlib==1.3.0 -google-cloud-core==2.5.0 -google-cloud-storage==3.9.0 -google-cloud-storage-control==1.10.0 +google-auth-oauthlib==1.3.1 +google-cloud-core==2.5.1 +google-cloud-storage==3.10.1 +google-cloud-storage-control==1.11.0 google-crc32c==1.8.0 -google-resumable-media==2.8.0 -googleapis-common-protos==1.73.0 +google-resumable-media==2.8.2 +googleapis-common-protos==1.74.0 greenlet==3.3.2 -grpc-google-iam-v1==0.14.3 -grpcio==1.78.0 -grpcio-status==1.78.0 +grpc-google-iam-v1==0.14.4 +grpcio==1.80.0 +grpcio-status==1.80.0 h11==0.16.0 html5rdf==1.2.1 hvac==2.4.0 @@ -72,13 +72,13 @@ inquirerpy==0.3.4 isodate==0.7.2 ; python_full_version < '3.11' isort==8.0.1 jaraco-classes==3.4.0 ; platform_machine != 'ppc64le' and platform_machine != 's390x' -jaraco-context==6.1.1 ; platform_machine != 'ppc64le' and platform_machine != 's390x' +jaraco-context==6.1.2 ; platform_machine != 'ppc64le' and platform_machine != 's390x' jaraco-functools==4.4.0 ; platform_machine != 'ppc64le' and platform_machine != 's390x' jeepney==0.9.0 ; platform_machine != 'ppc64le' and platform_machine != 's390x' and sys_platform == 'linux' jinja2==3.1.6 jmespath==1.1.0 jsonpatch==1.33 -jsonpointer==3.0.0 +jsonpointer==3.1.1 jsonschema==4.26.0 jsonschema-specifications==2025.9.1 junit-xml==1.9 @@ -94,17 +94,17 @@ matplotlib==3.10.8 mdit-py-plugins==0.5.0 mdurl==0.1.2 mirakuru==3.0.2 -mistune==3.1.4 -more-itertools==10.8.0 ; platform_machine != 'ppc64le' and platform_machine != 's390x' +mistune==3.2.0 +more-itertools==11.0.1 ; platform_machine != 'ppc64le' and platform_machine != 's390x' msgpack==1.1.2 multidict==6.7.1 -mypy==1.19.1 +mypy==1.20.0 mypy-extensions==1.1.0 myst-parser==4.0.1 ; python_full_version < '3.11' myst-parser==5.0.0 ; python_full_version >= '3.11' -nh3==0.3.3 +nh3==0.3.4 numpy==2.2.6 ; python_full_version < '3.11' -numpy==2.4.3 ; python_full_version >= '3.11' +numpy==2.4.4 ; python_full_version >= '3.11' oauthlib==3.3.1 onedatafilerestclient==21.2.5.2 outcome==1.3.0.post0 @@ -112,7 +112,7 @@ owlrl==7.1.4 packaging==25.0 pathspec==1.0.4 pfzy==0.3.4 -pillow==12.1.1 +pillow==12.2.0 pkce==1.0.3 platformdirs==4.9.4 playwright==1.58.0 @@ -121,15 +121,15 @@ port-for==1.0.0 prettytable==3.17.0 prompt-toolkit==3.0.52 propcache==0.4.1 -proto-plus==1.27.1 -protobuf==6.33.5 +proto-plus==1.27.2 +protobuf==6.33.6 psutil==7.2.2 ; sys_platform != 'cygwin' psycopg==3.3.3 pyasn1==0.6.3 pyasn1-modules==0.4.2 pycparser==3.0 ; (implementation_name != 'PyPy' and implementation_name != 'pypy' and os_name == 'nt') or (implementation_name != 'PyPy' and platform_python_implementation != 'PyPy') pyee==13.0.1 -pygithub==2.8.1 +pygithub==2.9.0 pygments==2.20.0 pyjwt==2.12.1 pynacl==1.6.2 @@ -140,7 +140,7 @@ pysocks==1.7.1 pytest==9.0.2 pytest-asyncio==1.3.0 pytest-base-url==2.1.0 -pytest-cov==7.0.0 +pytest-cov==7.1.0 pytest-html==4.2.0 pytest-httpserver==1.1.5 pytest-json-report==1.5.0 @@ -150,30 +150,30 @@ pytest-playwright==0.7.2 pytest-postgresql==8.0.0 pytest-shard==0.1.2 python-dateutil==2.9.0.post0 -python-irodsclient==3.2.0 +python-irodsclient==3.3.0 python-slugify==8.0.4 pytokens==0.4.1 pywin32-ctypes==0.2.3 ; platform_machine != 'ppc64le' and platform_machine != 's390x' and sys_platform == 'win32' pyyaml==6.0.3 -rdflib==7.5.0 +rdflib==7.6.0 readme-renderer==44.0 referencing==0.37.0 -requests==2.33.0 +requests==2.33.1 requests-cache==1.3.1 requests-oauthlib==2.0.0 requests-toolbelt==1.0.0 responses==0.26.0 rfc3986==2.0.0 rich==13.9.4 +rich-argparse==1.7.2 rich-click==1.9.7 roc-validator==0.8.1 roman-numerals==4.1.0 ; python_full_version >= '3.11' rpds-py==0.30.0 -ruamel-yaml==0.18.17 -ruamel-yaml-clib==0.2.15 ; python_full_version < '3.15' and platform_python_implementation == 'CPython' +ruamel-yaml==0.19.1 rucio-clients==39.4.1 s3transfer==0.16.0 -schema-salad==8.9.20251102115403 +schema-salad==8.9.20260327095315 scipy==1.15.3 ; python_full_version < '3.11' scipy==1.17.1 ; python_full_version >= '3.11' secretstorage==3.5.0 ; platform_machine != 'ppc64le' and platform_machine != 's390x' and sys_platform == 'linux' @@ -202,23 +202,23 @@ testfixtures==11.0.0 ; python_full_version >= '3.11' text-unidecode==1.3 tinydb==4.8.2 toml==0.10.2 -tomli==2.4.0 ; python_full_version <= '3.11' -total-perspective-vortex==3.1.3 +tomli==2.4.1 ; python_full_version <= '3.11' +total-perspective-vortex==3.2.0 trio==0.33.0 trio-websocket==0.12.2 tuspy==1.1.0 twine==6.2.0 -types-cachetools==6.2.0.20251022 -types-requests==2.32.4.20260107 +types-cachetools==6.2.0.20260317 +types-requests==2.33.0.20260402 typing-extensions==4.15.0 -typos==1.44.0 -tzdata==2025.3 ; sys_platform == 'win32' +typos==1.45.0 +tzdata==2026.1 ; sys_platform == 'win32' url-normalize==2.2.1 urllib3==2.6.3 watchdog==6.0.0 wcwidth==0.6.0 websocket-client==1.9.0 -werkzeug==3.1.6 +werkzeug==3.1.8 wsproto==1.3.2 yarl==1.23.0 zipp==3.23.0 ; python_full_version < '3.12' diff --git a/lib/galaxy/dependencies/pinned-lint-requirements.txt b/lib/galaxy/dependencies/pinned-lint-requirements.txt index ee45cbda430..2eb242e2c73 100644 --- a/lib/galaxy/dependencies/pinned-lint-requirements.txt +++ b/lib/galaxy/dependencies/pinned-lint-requirements.txt @@ -1,7 +1,7 @@ -attrs==25.4.0 +attrs==26.1.0 flake8==7.3.0 flake8-bugbear==25.11.29 mccabe==0.7.0 pycodestyle==2.14.0 pyflakes==3.4.0 -ruff==0.15.6 +ruff==0.15.9 diff --git a/lib/galaxy/dependencies/pinned-requirements.txt b/lib/galaxy/dependencies/pinned-requirements.txt index 66a4af0cffd..87880c29c29 100644 --- a/lib/galaxy/dependencies/pinned-requirements.txt +++ b/lib/galaxy/dependencies/pinned-requirements.txt @@ -2,26 +2,26 @@ # uv export --frozen --no-annotate --no-hashes --no-dev a2wsgi==1.10.10 adal==1.2.7 -ag-ui-protocol==0.1.13 -aiobotocore==3.2.1 +ag-ui-protocol==0.1.15 +aiobotocore==3.3.0 aiofile==3.9.0 aiofiles==25.1.0 aiohappyeyeballs==2.6.1 -aiohttp==3.13.4 +aiohttp==3.13.5 aioitertools==0.13.0 aiosignal==1.4.0 alembic==1.18.4 amqp==5.3.1 annotated-doc==0.0.4 annotated-types==0.7.0 -anthropic==0.84.0 -anyio==4.12.1 +anthropic==0.89.0 +anyio==4.13.0 apispec==6.10.0 appdirs==1.4.4 arcp==0.2.1 argcomplete==3.6.3 async-timeout==5.0.1 ; python_full_version < '3.11' -attrs==25.4.0 +attrs==26.1.0 authlib==1.6.9 babel==2.18.0 backports-tarfile==1.2.0 ; python_full_version < '3.12' @@ -36,33 +36,33 @@ bioblend==1.8.0 bleach==6.3.0 boltons==25.0.0 boto==2.49.0 -boto3==1.42.61 -botocore==1.42.61 +boto3==1.42.70 +botocore==1.42.70 bx-python==0.14.0 cachecontrol==0.14.4 cachetools==7.0.5 caio==0.9.25 -celery==5.6.2 +celery==5.6.3 certifi==2026.2.25 cffi==2.0.0 ; implementation_name == 'pypy' or platform_python_implementation != 'PyPy' -charset-normalizer==3.4.5 +charset-normalizer==3.4.7 circus==0.19.0 -click==8.3.1 +click==8.3.2 click-didyoumean==0.3.1 click-plugins==1.1.1.2 click-repl==0.3.0 cloudauthz==0.6.0 cloudbridge==3.2.0 -cohere==5.20.7 ; sys_platform != 'emscripten' +cohere==5.21.1 ; sys_platform != 'emscripten' colorama==0.4.6 ; sys_platform == 'win32' coloredlogs==15.0.1 conda-package-streaming==0.12.0 cryptography==46.0.7 ct3==3.4.0.post5 -cwl-upgrader==1.2.14 -cwl-utils==0.40 -cwltool==3.1.20260108082145 -cyclopts==4.9.0 +cwl-upgrader==1.2.15 +cwl-utils==0.41 +cwltool==3.1.20260315121657 +cyclopts==4.10.1 defusedxml==0.7.1 deprecated==1.3.1 deprecation==2.1.0 @@ -80,37 +80,37 @@ et-xmlfile==2.0.0 eval-type-backport==0.3.1 exceptiongroup==1.3.1 executing==2.2.1 -fastapi==0.135.1 +fastapi==0.135.3 fastavro==1.12.1 ; sys_platform != 'emscripten' fastmcp==3.2.0 filelock==3.25.2 fissix==24.4.24 frozenlist==1.8.0 fs==2.4.16 -fsspec==2026.2.0 +fsspec==2026.3.0 future==1.0.0 -genai-prices==0.0.55 -google-api-core==2.30.0 +genai-prices==0.0.56 +google-api-core==2.30.2 google-auth==2.49.1 -google-cloud-batch==0.20.0 -google-genai==1.67.0 -googleapis-common-protos==1.73.0 +google-cloud-batch==0.21.0 +google-genai==1.70.0 +googleapis-common-protos==1.74.0 gravity==1.2.0 greenlet==3.3.2 ; platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64' -griffelib==2.0.0 -groq==1.1.1 -grpcio==1.78.0 -grpcio-status==1.78.0 -gunicorn==25.0.3 -gxformat2==0.23.0 +griffelib==2.0.2 +groq==1.1.2 +grpcio==1.80.0 +grpcio-status==1.80.0 +gunicorn==25.3.0 +gxformat2==0.24.0 h11==0.16.0 h5grove==3.0.0 h5py==3.16.0 -hf-xet==1.4.2 ; platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64' +hf-xet==1.4.3 ; platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64' httpcore==1.0.9 httpx==0.28.1 httpx-sse==0.4.3 -huggingface-hub==1.7.1 +huggingface-hub==1.9.0 humanfriendly==10.0 idna==3.11 ijson==3.5.0 @@ -121,12 +121,13 @@ isa-rwval==0.10.11 isal==1.8.0 isodate==0.7.2 ; python_full_version < '3.11' jaraco-classes==3.4.0 -jaraco-context==6.1.1 +jaraco-context==6.1.2 jaraco-functools==4.4.0 jeepney==0.9.0 ; sys_platform == 'linux' jinja2==3.1.6 jiter==0.13.0 jmespath==1.1.0 +jsonpath-python==1.1.5 jsonref==1.1.0 jsonschema==4.26.0 jsonschema-path==0.4.5 @@ -136,20 +137,20 @@ kombu==5.6.2 lagom==2.7.7 legacy-cgi==2.6.4 ; python_full_version >= '3.13' limits==5.8.0 -logfire==4.29.0 -logfire-api==4.29.0 +logfire==4.31.0 +logfire-api==4.31.0 lxml==6.0.2 mako==1.3.10 markdown==3.10.2 markdown-it-py==3.0.0 ; python_full_version < '3.11' markdown-it-py==4.0.0 ; python_full_version >= '3.11' markupsafe==3.0.3 -mcp==1.26.0 +mcp==1.27.0 mdurl==0.1.2 -mercurial==7.2 -mistralai==2.0.2 -mistune==3.1.4 -more-itertools==10.8.0 +mercurial==7.2.1 +mistralai==2.3.0 +mistune==3.2.0 +more-itertools==11.0.1 mrcfile==1.5.4 msal==1.35.1 msgpack==1.1.2 @@ -157,13 +158,13 @@ multidict==6.7.1 mypy-extensions==1.1.0 networkx==3.4.2 ; python_full_version < '3.11' networkx==3.6.1 ; python_full_version >= '3.11' -nexus-rpc==1.2.0 +nexus-rpc==1.4.0 nodejs-wheel==22.20.0 nodejs-wheel-binaries==22.20.0 numpy==2.2.6 ; python_full_version < '3.11' -numpy==2.4.3 ; python_full_version >= '3.11' +numpy==2.4.4 ; python_full_version >= '3.11' oauthlib==3.3.1 -openai==2.28.0 +openai==2.30.0 openapi-pydantic==0.5.1 openpyxl==3.1.5 opentelemetry-api==1.39.1 @@ -175,7 +176,7 @@ opentelemetry-proto==1.39.1 opentelemetry-sdk==1.39.1 opentelemetry-semantic-conventions==0.60b1 opentelemetry-util-http==0.60b1 -orjson==3.11.7 +orjson==3.11.8 packaging==25.0 paramiko==4.0.0 parsley==1.3 @@ -183,12 +184,12 @@ paste==3.10.1 pastedeploy==3.1.0 pathable==0.5.0 pebble==5.2.0 -pillow==12.1.1 +pillow==12.2.0 platformdirs==4.9.4 prompt-toolkit==3.0.52 propcache==0.4.1 -proto-plus==1.27.1 -protobuf==6.33.5 +proto-plus==1.27.2 +protobuf==6.33.6 prov==1.5.1 psutil==7.2.2 pulsar-galaxy-lib==0.15.14 @@ -198,17 +199,18 @@ pyasn1-modules==0.4.2 pycparser==3.0 ; (implementation_name != 'PyPy' and platform_python_implementation != 'PyPy') or (implementation_name == 'pypy' and platform_python_implementation == 'PyPy') pycryptodome==3.23.0 pydantic==2.12.5 -pydantic-ai==1.68.0 -pydantic-ai-slim==1.68.0 +pydantic-ai==1.77.0 +pydantic-ai-slim==1.77.0 pydantic-core==2.41.5 -pydantic-evals==1.68.0 -pydantic-graph==1.68.0 +pydantic-evals==1.77.0 +pydantic-graph==1.77.0 +pydantic-handlebars==0.1.0 pydantic-settings==2.13.1 pydantic-tes==0.3.0 pydicom==3.0.2 pydot==4.0.1 pyeventsystem==0.1.0 -pyfaidx==0.9.0.3 +pyfaidx==0.9.0.4 pygments==2.20.0 pyjwt==2.12.1 pykwalify==1.8.0 @@ -230,12 +232,12 @@ pywin32==311 ; sys_platform == 'win32' pywin32-ctypes==0.2.3 ; sys_platform == 'win32' pyyaml==6.0.3 pyzmq==27.1.0 -rdflib==7.5.0 +rdflib==7.6.0 referencing==0.37.0 -refgenconf==0.13.0 -regex==2026.2.28 +refgenconf==0.13.1 +regex==2026.4.4 repoze-lru==0.7 -requests==2.33.0 +requests==2.33.1 requests-oauthlib==2.0.0 requests-toolbelt==1.0.0 requests-unixsocket==0.4.1 @@ -245,11 +247,10 @@ rich-rst==1.3.2 rocrate==0.14.2 routes==2.5.1 rpds-py==0.30.0 -ruamel-yaml==0.18.17 -ruamel-yaml-clib==0.2.15 ; python_full_version < '3.15' and platform_python_implementation == 'CPython' -s3fs==2026.2.0 +ruamel-yaml==0.19.1 +s3fs==2026.3.0 s3transfer==0.16.0 -schema-salad==8.9.20251102115403 +schema-salad==8.9.20260327095315 secretstorage==3.5.0 ; sys_platform == 'linux' setuptools==81.0.0 shellingham==1.5.4 @@ -259,14 +260,14 @@ sniffio==1.3.1 social-auth-core==4.8.5 sortedcontainers==2.4.0 spython==0.3.14 -sqlalchemy==2.0.48 +sqlalchemy==2.0.49 sqlparse==0.5.5 -sse-starlette==3.3.2 -starlette==0.52.1 +sse-starlette==3.3.4 +starlette==1.0.0 starlette-context==0.5.1 supervisor==4.3.0 svgwrite==1.4.3 -temporalio==1.20.0 +temporalio==1.24.0 tenacity==9.1.4 text-unidecode==1.3 tifffile==2025.5.10 ; python_full_version < '3.11' @@ -274,22 +275,22 @@ tifffile==2026.3.3 ; python_full_version >= '3.11' tiktoken==0.12.0 tinydb==4.8.2 tokenizers==0.22.2 ; sys_platform != 'emscripten' -tomli==2.4.0 ; python_full_version < '3.11' +tomli==2.4.1 ; python_full_version < '3.11' tornado==6.5.5 tqdm==4.67.3 tuspy==1.1.0 tuspyserver==4.2.3 typer==0.24.1 -types-protobuf==6.32.1.20260221 -types-requests==2.32.4.20260107 ; sys_platform != 'emscripten' +types-protobuf==7.34.1.20260403 +types-requests==2.33.0.20260402 ; sys_platform != 'emscripten' typing-extensions==4.15.0 typing-inspection==0.4.2 -tzdata==2025.3 +tzdata==2026.1 tzlocal==5.3.1 -ubiquerg==0.9.1 +ubiquerg==0.9.3 uncalled-for==0.2.0 urllib3==2.6.3 -uvicorn==0.41.0 +uvicorn==0.43.0 uvloop==0.22.1 vine==5.1.0 watchfiles==1.1.1 @@ -299,7 +300,7 @@ webob==1.8.9 websockets==16.0 whoosh==2.7.4 wrapt==1.17.3 -xai-sdk==1.8.1 +xai-sdk==1.11.0 yacman==1.0.0 yarl==1.23.0 zipp==3.23.0 diff --git a/lib/galaxy/dependencies/pinned-test-requirements.txt b/lib/galaxy/dependencies/pinned-test-requirements.txt index c330ed359b5..b9cb08198a5 100644 --- a/lib/galaxy/dependencies/pinned-test-requirements.txt +++ b/lib/galaxy/dependencies/pinned-test-requirements.txt @@ -1,27 +1,27 @@ # This file was autogenerated by uv via the following command: # uv export --frozen --no-annotate --no-hashes --only-group=test aiohappyeyeballs==2.6.1 -aiohttp==3.13.4 +aiohttp==3.13.5 aiosignal==1.4.0 -ase==3.27.0 +ase==3.28.0 async-timeout==5.0.1 ; python_full_version < '3.11' -attrs==25.4.0 +attrs==26.1.0 axe-selenium-python==2.1.6 backports-asyncio-runner==1.2.0 ; python_full_version < '3.11' -boto3==1.42.61 -botocore==1.42.61 +boto3==1.42.70 +botocore==1.42.70 cachecontrol==0.14.4 cachetools==7.0.5 cattrs==26.1.0 certifi==2026.2.25 cffi==2.0.0 ; (implementation_name != 'pypy' and os_name == 'nt') or platform_python_implementation != 'PyPy' -charset-normalizer==3.4.5 -click==8.3.1 +charset-normalizer==3.4.7 +click==8.3.2 colorama==0.4.6 ; sys_platform == 'win32' colorlog==6.10.1 contourpy==1.3.2 ; python_full_version < '3.11' contourpy==1.3.3 ; python_full_version >= '3.11' -coverage==7.13.4 +coverage==7.13.5 cryptography==46.0.7 cwltest==2.6.20251216093331 cycler==0.12.1 @@ -34,21 +34,21 @@ filelock==3.25.2 fluent-logger==0.11.1 fonttools==4.62.1 frozenlist==1.8.0 -fsspec==2026.2.0 -gcsfs==2026.2.0 -google-api-core==2.30.0 +fsspec==2026.3.0 +gcsfs==2026.3.0 +google-api-core==2.30.2 google-auth==2.49.1 -google-auth-oauthlib==1.3.0 -google-cloud-core==2.5.0 -google-cloud-storage==3.9.0 -google-cloud-storage-control==1.10.0 +google-auth-oauthlib==1.3.1 +google-cloud-core==2.5.1 +google-cloud-storage==3.10.1 +google-cloud-storage-control==1.11.0 google-crc32c==1.8.0 -google-resumable-media==2.8.0 -googleapis-common-protos==1.73.0 +google-resumable-media==2.8.2 +googleapis-common-protos==1.74.0 greenlet==3.3.2 -grpc-google-iam-v1==0.14.3 -grpcio==1.78.0 -grpcio-status==1.78.0 +grpc-google-iam-v1==0.14.4 +grpcio==1.80.0 +grpcio-status==1.80.0 h11==0.16.0 html5rdf==1.2.1 hvac==2.4.0 @@ -60,7 +60,7 @@ isodate==0.7.2 ; python_full_version < '3.11' jinja2==3.1.6 jmespath==1.1.0 jsonpatch==1.33 -jsonpointer==3.0.0 +jsonpointer==3.1.1 jsonschema==4.26.0 jsonschema-specifications==2025.9.1 junit-xml==1.9 @@ -73,13 +73,13 @@ markupsafe==3.0.3 matplotlib==3.10.8 mdurl==0.1.2 mirakuru==3.0.2 -mistune==3.1.4 +mistune==3.2.0 msgpack==1.1.2 multidict==6.7.1 -mypy==1.19.1 +mypy==1.20.0 mypy-extensions==1.1.0 numpy==2.2.6 ; python_full_version < '3.11' -numpy==2.4.3 ; python_full_version >= '3.11' +numpy==2.4.4 ; python_full_version >= '3.11' oauthlib==3.3.1 onedatafilerestclient==21.2.5.2 outcome==1.3.0.post0 @@ -87,7 +87,7 @@ owlrl==7.1.4 packaging==25.0 pathspec==1.0.4 pfzy==0.3.4 -pillow==12.1.1 +pillow==12.2.0 pkce==1.0.3 platformdirs==4.9.4 playwright==1.58.0 @@ -96,8 +96,8 @@ port-for==1.0.0 prettytable==3.17.0 prompt-toolkit==3.0.52 propcache==0.4.1 -proto-plus==1.27.1 -protobuf==6.33.5 +proto-plus==1.27.2 +protobuf==6.33.6 psutil==7.2.2 ; sys_platform != 'cygwin' psycopg==3.3.3 pyasn1==0.6.3 @@ -111,7 +111,7 @@ pysocks==1.7.1 pytest==9.0.2 pytest-asyncio==1.3.0 pytest-base-url==2.1.0 -pytest-cov==7.0.0 +pytest-cov==7.1.0 pytest-html==4.2.0 pytest-httpserver==1.1.5 pytest-json-report==1.5.0 @@ -121,24 +121,24 @@ pytest-playwright==0.7.2 pytest-postgresql==8.0.0 pytest-shard==0.1.2 python-dateutil==2.9.0.post0 -python-irodsclient==3.2.0 +python-irodsclient==3.3.0 python-slugify==8.0.4 pyyaml==6.0.3 -rdflib==7.5.0 +rdflib==7.6.0 referencing==0.37.0 -requests==2.33.0 +requests==2.33.1 requests-cache==1.3.1 requests-oauthlib==2.0.0 responses==0.26.0 rich==13.9.4 +rich-argparse==1.7.2 rich-click==1.9.7 roc-validator==0.8.1 rpds-py==0.30.0 -ruamel-yaml==0.18.17 -ruamel-yaml-clib==0.2.15 ; python_full_version < '3.15' and platform_python_implementation == 'CPython' +ruamel-yaml==0.19.1 rucio-clients==39.4.1 s3transfer==0.16.0 -schema-salad==8.9.20251102115403 +schema-salad==8.9.20260327095315 scipy==1.15.3 ; python_full_version < '3.11' scipy==1.17.1 ; python_full_version >= '3.11' selenium==4.41.0 @@ -154,22 +154,22 @@ testfixtures==11.0.0 ; python_full_version >= '3.11' text-unidecode==1.3 tinydb==4.8.2 toml==0.10.2 -tomli==2.4.0 ; python_full_version <= '3.11' -total-perspective-vortex==3.1.3 +tomli==2.4.1 ; python_full_version <= '3.11' +total-perspective-vortex==3.2.0 trio==0.33.0 trio-websocket==0.12.2 tuspy==1.1.0 -types-cachetools==6.2.0.20251022 -types-requests==2.32.4.20260107 +types-cachetools==6.2.0.20260317 +types-requests==2.33.0.20260402 typing-extensions==4.15.0 -typos==1.44.0 -tzdata==2025.3 ; sys_platform == 'win32' +typos==1.45.0 +tzdata==2026.1 ; sys_platform == 'win32' url-normalize==2.2.1 urllib3==2.6.3 watchdog==6.0.0 wcwidth==0.6.0 websocket-client==1.9.0 -werkzeug==3.1.6 +werkzeug==3.1.8 wsproto==1.3.2 yarl==1.23.0 zipp==3.23.0 ; python_full_version < '3.12' diff --git a/lib/galaxy/dependencies/pinned-typecheck-requirements.txt b/lib/galaxy/dependencies/pinned-typecheck-requirements.txt index e0925bad565..2ec79cb7773 100644 --- a/lib/galaxy/dependencies/pinned-typecheck-requirements.txt +++ b/lib/galaxy/dependencies/pinned-typecheck-requirements.txt @@ -1,35 +1,35 @@ # This file was autogenerated by uv via the following command: # uv export --frozen --no-annotate --no-hashes --only-group=typecheck annotated-types==0.7.0 -boto3-stubs==1.42.68 +boto3-stubs==1.42.83 botocore-stubs==1.42.41 cffi==2.0.0 ; platform_python_implementation != 'PyPy' cryptography==46.0.7 librt==0.8.1 ; platform_python_implementation != 'PyPy' lxml-stubs==0.5.1 -mypy==1.19.1 -mypy-boto3-s3==1.42.67 +mypy==1.20.0 +mypy-boto3-s3==1.42.80 mypy-extensions==1.1.0 pathspec==1.0.4 pycparser==3.0 ; implementation_name != 'PyPy' and platform_python_implementation != 'PyPy' pydantic==2.12.5 pydantic-core==2.41.5 -tomli==2.4.0 ; python_full_version < '3.11' +tomli==2.4.1 ; python_full_version < '3.11' types-awscrt==0.31.3 -types-bleach==6.3.0.20251115 +types-bleach==6.3.0.20260402 types-boto==2.49.18.20241019 types-contextvars==2.4.7.3 types-dataclasses==0.6.6 -types-docutils==0.22.3.20260223 -types-html5lib==1.1.11.20251117 +types-docutils==0.22.3.20260322 +types-html5lib==1.1.11.20260402 types-markdown==3.10.2.20260211 -types-paramiko==4.0.0.20250822 -types-python-dateutil==2.9.0.20260305 +types-paramiko==4.0.0.20260402 +types-python-dateutil==2.9.0.20260402 types-python-slugify==8.0.2.20240310 types-pyyaml==6.0.12.20250915 -types-requests==2.32.4.20260107 +types-requests==2.33.0.20260402 types-s3transfer==0.16.0 -types-setuptools==82.0.0.20260210 +types-setuptools==82.0.0.20260402 types-six==1.17.0.20251009 types-webencodings==0.5.0.20251108 typing-extensions==4.15.0 From 345efca3e58cd73fab0efdb47962e52477050f8f Mon Sep 17 00:00:00 2001 From: Nicola Soranzo Date: Wed, 1 Apr 2026 11:55:39 +0100 Subject: [PATCH 2/3] Fix type annotation issues reported by mypy 1.20.0 --- lib/galaxy/datatypes/data.py | 1 + lib/galaxy/datatypes/protocols.py | 2 +- lib/galaxy/files/sources/dataverse.py | 2 +- lib/galaxy/job_execution/output_collect.py | 5 ++- lib/galaxy/job_execution/setup.py | 2 + lib/galaxy/jobs/__init__.py | 23 ++++++++--- lib/galaxy/jobs/handler.py | 1 + lib/galaxy/jobs/runners/__init__.py | 1 + lib/galaxy/managers/hdas.py | 5 ++- lib/galaxy/managers/tours.py | 3 +- lib/galaxy/metadata/set_metadata.py | 1 + lib/galaxy/model/__init__.py | 41 +++++++++++++------ .../model/dataset_collections/adapters.py | 2 + .../types/sample_sheet_workbook.py | 2 +- lib/galaxy/model/deferred.py | 5 ++- lib/galaxy/model/dereference.py | 2 +- lib/galaxy/model/metadata.py | 2 + lib/galaxy/model/security.py | 3 +- lib/galaxy/model/store/__init__.py | 13 ++++-- lib/galaxy/model/store/discover.py | 7 +++- lib/galaxy/model/store/ro_crate_utils.py | 2 + lib/galaxy/objectstore/__init__.py | 3 +- .../galaxy_install/tools/data_manager.py | 2 +- lib/galaxy/tools/__init__.py | 7 +++- lib/galaxy/tools/actions/__init__.py | 1 + lib/galaxy/tools/parameters/basic.py | 1 + lib/galaxy/tools/runtime.py | 4 +- .../webapps/galaxy/services/datasets.py | 3 +- .../galaxy/services/history_contents.py | 6 +++ lib/galaxy/workflow/extract.py | 1 + lib/galaxy/workflow/modules.py | 1 + .../metadata/repository_metadata_manager.py | 2 +- lib/tool_shed/webapp/model/__init__.py | 13 ++++-- test/unit/app/tools/test_runtime.py | 1 + test/unit/data/model/test_model_store.py | 2 + .../unit/data/test_dataset_materialization.py | 36 ++++++++++++++++ test/unit/data/test_dereference.py | 5 +++ test/unit/data/test_quota.py | 5 ++- 38 files changed, 171 insertions(+), 47 deletions(-) diff --git a/lib/galaxy/datatypes/data.py b/lib/galaxy/datatypes/data.py index 4cd67dce206..63cb7c5f8e7 100644 --- a/lib/galaxy/datatypes/data.py +++ b/lib/galaxy/datatypes/data.py @@ -401,6 +401,7 @@ class Data(metaclass=DataMeta): self, trans, data: DatasetHasHidProtocol, headers: Headers, do_action: str = "zip" ) -> tuple[Union[ZipstreamWrapper, str], Headers]: # save a composite object into a compressed archive for downloading + assert data.name outfname = data.name[0:150] outfname = "".join(c in FILENAME_VALID_CHARS and c or "_" for c in outfname) archive = ZipstreamWrapper( diff --git a/lib/galaxy/datatypes/protocols.py b/lib/galaxy/datatypes/protocols.py index 4f5bd159337..33a80a3f942 100644 --- a/lib/galaxy/datatypes/protocols.py +++ b/lib/galaxy/datatypes/protocols.py @@ -51,7 +51,7 @@ class HasMetadata(Protocol): class HasName(Protocol): - name: str + name: str | None class HasExtraFilesAndMetadata(HasExtraFilesPath, HasMetadata, Protocol): ... diff --git a/lib/galaxy/files/sources/dataverse.py b/lib/galaxy/files/sources/dataverse.py index 95197ea5f1e..098db13c6df 100644 --- a/lib/galaxy/files/sources/dataverse.py +++ b/lib/galaxy/files/sources/dataverse.py @@ -530,7 +530,7 @@ class DataverseRepositoryInteractor(RDMRepositoryInteractor): if hash_value and hash_type in supported_hashes: return [ RemoteFileHash( - hash_function=cast(HashFunctionNames, hash_type), + hash_function=hash_type, hash_value=str(hash_value), ) ] diff --git a/lib/galaxy/job_execution/output_collect.py b/lib/galaxy/job_execution/output_collect.py index 2eb358982be..5d3feca5bf0 100644 --- a/lib/galaxy/job_execution/output_collect.py +++ b/lib/galaxy/job_execution/output_collect.py @@ -6,6 +6,7 @@ import operator import os import re from collections.abc import Callable +from decimal import Decimal from tempfile import NamedTemporaryFile from typing import ( Any, @@ -388,6 +389,7 @@ def collect_primary_datasets(job_context: BaseJobContext, output: dict[str, Data ): job_context.increment_discovered_file_count() filenames[discovered_file.path] = discovered_file + assert outdata.dataset is not None for filename_index, (filename, discovered_file) in enumerate(filenames.items()): extra_file_collector = discovered_file.collector fields_match = discovered_file.match @@ -450,8 +452,9 @@ def collect_primary_datasets(job_context: BaseJobContext, output: dict[str, Data # Associate new dataset with job job_context.add_output_dataset_association(f"__new_primary_file_{name}|{designation}__", primary_data) except JobOutputNameTooLongError: + assert primary_data.dataset is not None primary_data.dataset.state = Dataset.states.DISCARDED - primary_data.dataset.file_size = 0 + primary_data.dataset.file_size = Decimal(0) job_context.add_datasets_to_history([primary_data], for_output_dataset=outdata) raise job_context.add_datasets_to_history([primary_data], for_output_dataset=outdata) diff --git a/lib/galaxy/job_execution/setup.py b/lib/galaxy/job_execution/setup.py index b7df1a193bf..755e661222e 100644 --- a/lib/galaxy/job_execution/setup.py +++ b/lib/galaxy/job_execution/setup.py @@ -245,6 +245,7 @@ class JobIO(UsesDictVisibleKeys): def get_input_path(self, dataset: DatasetInstance) -> DatasetPath: real_path = dataset.get_file_name() false_path = self.dataset_path_rewriter.rewrite_dataset_path(dataset, "input") + assert dataset.dataset is not None return DatasetPath( dataset.dataset.id, real_path=real_path, @@ -290,6 +291,7 @@ class JobIO(UsesDictVisibleKeys): with open(da_false_path, "ab"): pass real_path = da.dataset.get_file_name(sync_cache=False) + assert da.dataset.dataset is not None false_extra_files_path = os.path.join( os.path.dirname(da_false_path or real_path), da.dataset.dataset.extra_files_path_name ) diff --git a/lib/galaxy/jobs/__init__.py b/lib/galaxy/jobs/__init__.py index 1a723666665..9be1de95e34 100644 --- a/lib/galaxy/jobs/__init__.py +++ b/lib/galaxy/jobs/__init__.py @@ -82,6 +82,7 @@ from galaxy.model import ( Dataset, Job, JobOutputNameTooLongError, + LibraryDatasetDatasetAssociation, store, Task, ) @@ -121,7 +122,7 @@ from galaxy.work.context import WorkRequestContext if TYPE_CHECKING: from galaxy.jobs.handler import BaseJobHandlerQueue - from galaxy.model import DatasetInstance + from galaxy.model import HistoryDatasetAssociation from galaxy.tools import Tool from galaxy.util import ( Element, @@ -1499,9 +1500,9 @@ class MinimalJobWrapper(HasResourceParameters): except Exception: # Failure to update the output of a failed job should not prevent completion of the failure method log.exception( - "(%s) fail(): Failed to update job output dataset with id: %s", + "(%s) fail(): Failed to update job output dataset instance with id: %s", self.get_id_tag(), - dataset.dataset.id, + dataset.id, ) # Pause any dependent jobs (and those jobs' outputs) for dep_job_assoc in dataset.dependent_jobs: @@ -1930,9 +1931,16 @@ class MinimalJobWrapper(HasResourceParameters): self._setup_working_directory(job=job) def _finish_dataset( - self, output_name, dataset: "DatasetInstance", job: Job, context, final_job_state, remote_metadata_directory + self, + output_name: str, + dataset: "HistoryDatasetAssociation | LibraryDatasetDatasetAssociation", + job: Job, + context, + final_job_state, + remote_metadata_directory, ): implicit_collection_jobs = job.implicit_collection_jobs_association + assert dataset.dataset is not None purged = dataset.dataset.purged if not purged and dataset.dataset.external_filename is None: trynum = 0 @@ -2692,7 +2700,9 @@ class MinimalJobWrapper(HasResourceParameters): else: return "anonymous@unknown" - def __update_output(self, job, hda, clean_only=False): + def __update_output( + self, job: Job, hda: "HistoryDatasetAssociation | LibraryDatasetDatasetAssociation", clean_only: bool = False + ): """Handle writing outputs to the object store. This should be called regardless of whether the job was failed or not so @@ -2700,8 +2710,9 @@ class MinimalJobWrapper(HasResourceParameters): cleaned up if the dataset has been purged. """ dataset = hda.dataset + assert dataset is not None dataset.set_total_size() - if dataset not in job.output_library_datasets: + if not isinstance(hda, LibraryDatasetDatasetAssociation): purged = dataset.purged if not purged and not clean_only: self.object_store.update_from_file(dataset, create=True) diff --git a/lib/galaxy/jobs/handler.py b/lib/galaxy/jobs/handler.py index 33b43bf16ae..e87c50dbac6 100644 --- a/lib/galaxy/jobs/handler.py +++ b/lib/galaxy/jobs/handler.py @@ -580,6 +580,7 @@ class JobHandlerQueue(BaseJobHandlerQueue): log.info("(%d) User (%s) is over total walltime limit: job paused", job.id, job.user_id) job.set_state(model.Job.states.PAUSED) for dataset_assoc in job.output_datasets + job.output_library_datasets: + assert dataset_assoc.dataset.dataset is not None dataset_assoc.dataset.dataset.state = model.Dataset.states.PAUSED dataset_assoc.dataset.info = "Execution of this dataset's job is paused because you were over your total job runtime at the time it was ready to run" self.sa_session.add(dataset_assoc.dataset.dataset) diff --git a/lib/galaxy/jobs/runners/__init__.py b/lib/galaxy/jobs/runners/__init__.py index 6b4b5f45c99..5b98b1d6172 100644 --- a/lib/galaxy/jobs/runners/__init__.py +++ b/lib/galaxy/jobs/runners/__init__.py @@ -425,6 +425,7 @@ class BaseJobRunner: def _walk_dataset_outputs(self, job: model.Job): for dataset_assoc in job.output_datasets + job.output_library_datasets: + assert dataset_assoc.dataset.dataset is not None for dataset in ( dataset_assoc.dataset.dataset.history_associations + dataset_assoc.dataset.dataset.library_associations ): diff --git a/lib/galaxy/managers/hdas.py b/lib/galaxy/managers/hdas.py index ba540a2970d..4e3c5ebd0f3 100644 --- a/lib/galaxy/managers/hdas.py +++ b/lib/galaxy/managers/hdas.py @@ -251,13 +251,14 @@ class HDAManager( """ Purge this HDA and the dataset underlying it. """ - user = hda.history.user or None + user = hda.history.user if hda.history is not None else None if user: # Need to calculate this before purging quota_amount_reduction = hda.quota_amount(user) super().purge(hda, flush=flush) # decrease the user's space used if user: + assert hda.dataset is not None quota_source_info = hda.dataset.quota_source_info if quota_amount_reduction and quota_source_info.use: user.adjust_total_disk_usage( @@ -363,6 +364,7 @@ def dereference_input_to_hda( ) -> HistoryDatasetAssociation: permissions = trans.app.security_agent.history_get_default_permissions(history) hda = dereference_to_model(trans.sa_session, trans.user, history, data_request) + assert hda.dataset is not None trans.app.security_agent.set_all_dataset_permissions(hda.dataset, permissions, new=True, flush=False) trans.sa_session.commit() return hda @@ -461,6 +463,7 @@ class HDAStorageCleanerManager(base.StorageCleanerManager): hda: HistoryDatasetAssociation = self.hda_manager.get_owned(hda_id, user) hda.deleted = True quota_amount = int(hda.quota_amount(user)) + assert hda.dataset is not None hda.purge_usage_from_quota(user, hda.dataset.quota_source_info) hda.purged = True dataset_ids_to_remove.add(hda.dataset.id) diff --git a/lib/galaxy/managers/tours.py b/lib/galaxy/managers/tours.py index bf39a426555..a311b5e696d 100644 --- a/lib/galaxy/managers/tours.py +++ b/lib/galaxy/managers/tours.py @@ -214,7 +214,8 @@ class TourGenerator: step.content = f"Select dataset: {hid}: {dataset}" else: step.content = "Select a dataset" - elif input.type == "conditional" and isinstance(input, Conditional): + elif input.type == "conditional": + assert isinstance(input, Conditional) test_param = input.test_param if test_param is None: param_id = f"{input.name}|" diff --git a/lib/galaxy/metadata/set_metadata.py b/lib/galaxy/metadata/set_metadata.py index 73975229660..92bc33b2299 100644 --- a/lib/galaxy/metadata/set_metadata.py +++ b/lib/galaxy/metadata/set_metadata.py @@ -96,6 +96,7 @@ def push_if_necessary(object_store: ObjectStore, dataset: DatasetInstance, exter # or a remote object store from its cache path. # empty files could happen when outputs are discovered from working dir, # empty file check needed for e.g. test/integration/test_extended_metadata_outputs_to_working_directory.py::test_tools[multi_output_assign_primary] + assert dataset.dataset is not None if not dataset.dataset.purged and os.path.getsize(external_filename): object_store.update_from_file(dataset.dataset, file_name=external_filename, create=True) diff --git a/lib/galaxy/model/__init__.py b/lib/galaxy/model/__init__.py index 94d41fdb131..a85cf0d30d0 100644 --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -2047,6 +2047,7 @@ class Job(Base, JobLike, UsesCreateAndUpdateTime, Dictifiable, Serializable): def add_output_dataset(self, name: str, dataset: "HistoryDatasetAssociation"): self._check_name_length(name) joda = JobToOutputDatasetAssociation(name, dataset) + assert dataset.dataset is not None if dataset.dataset.job is None: # Only set job if dataset doesn't already have associated job. # database operation tools that make copies should not modify the job here. @@ -3496,7 +3497,7 @@ class History(Base, HasTags, Dictifiable, UsesAnnotations, HasName, Serializable archive_export_id: Mapped[Optional[int]] = mapped_column(ForeignKey("store_export_association.id"), default=None) datasets: Mapped[list["HistoryDatasetAssociation"]] = relationship( - back_populates="history", order_by=lambda: asc(HistoryDatasetAssociation.hid) # type: ignore[has-type] + back_populates="history", order_by=lambda: asc(HistoryDatasetAssociation.hid) ) exports: Mapped[list["JobExportHistoryArchive"]] = relationship( back_populates="history", @@ -3510,7 +3511,7 @@ class History(Base, HasTags, Dictifiable, UsesAnnotations, HasName, Serializable not_(HistoryDatasetAssociation.deleted), ) ), - order_by=lambda: asc(HistoryDatasetAssociation.hid), # type: ignore[has-type] + order_by=lambda: asc(HistoryDatasetAssociation.hid), viewonly=True, ) dataset_collections: Mapped[list["HistoryDatasetCollectionAssociation"]] = relationship(back_populates="history") @@ -3531,10 +3532,10 @@ class History(Base, HasTags, Dictifiable, UsesAnnotations, HasName, Serializable lambda: and_( HistoryDatasetAssociation.history_id == History.id, not_(HistoryDatasetAssociation.deleted), - HistoryDatasetAssociation.visible, # type: ignore[has-type] + HistoryDatasetAssociation.visible, ) ), - order_by=lambda: asc(HistoryDatasetAssociation.hid), # type: ignore[has-type] + order_by=lambda: asc(HistoryDatasetAssociation.hid), viewonly=True, ) visible_dataset_collections: Mapped[list["HistoryDatasetCollectionAssociation"]] = relationship( @@ -4685,10 +4686,10 @@ class Dataset(Base, StorableObject, Serializable): return self.object_store.size(self) @overload - def get_size(self, nice_size: Literal[False], calculate_size: bool = True) -> int: ... + def get_size(self, nice_size: Literal[True], calculate_size: bool = True) -> str: ... @overload - def get_size(self, nice_size: Literal[True], calculate_size: bool = True) -> str: ... + def get_size(self, nice_size: Literal[False] = False, calculate_size: bool = True) -> int: ... def get_size(self, nice_size: bool = False, calculate_size: bool = True) -> Union[int, str]: """Returns the size of the data on disk""" @@ -4706,7 +4707,7 @@ class Dataset(Base, StorableObject, Serializable): else: return cast(int, self.file_size) or 0 - def set_size(self, no_extra_files=False): + def set_size(self, no_extra_files: bool = False) -> None: """Sets the size of the data on disk. If the caller is sure there are no extra files, pass no_extra_files as True to optimize subsequent @@ -4714,7 +4715,7 @@ class Dataset(Base, StorableObject, Serializable): the file system. """ if not self.file_size: - self.file_size = self._calculate_size() + self.file_size = Decimal(self._calculate_size()) if no_extra_files: self.total_size = self.file_size @@ -5135,7 +5136,10 @@ def datatype_for_extension(extension, datatypes_registry=None) -> "Data": class DatasetInstance(RepresentById, UsesCreateAndUpdateTime, _HasTable): """A base class for all 'dataset instances', HDAs, LDDAs, etc""" + copied_from_history_dataset_association_id: Mapped[Optional[int]] + name: Mapped[Optional[str]] purged: Mapped[Optional[bool]] + visible: Mapped[bool] deleted: Mapped[bool] dataset_id: Mapped[Optional[int]] _state: Mapped[Optional[str]] @@ -5143,6 +5147,7 @@ class DatasetInstance(RepresentById, UsesCreateAndUpdateTime, _HasTable): conversion_messages = Dataset.conversion_messages permitted_actions = Dataset.permitted_actions creating_job_associations: list[Union[JobToOutputDatasetCollectionAssociation, JobToOutputDatasetAssociation]] + dataset: Mapped[Optional[Dataset]] copied_from_history_dataset_association: Optional["HistoryDatasetAssociation"] copied_from_library_dataset_dataset_association: Optional["LibraryDatasetDatasetAssociation"] dependent_jobs: list[JobToInputLibraryDatasetAssociation] @@ -5233,7 +5238,7 @@ class DatasetInstance(RepresentById, UsesCreateAndUpdateTime, _HasTable): @property def has_deferred_data(self) -> bool: - return self.dataset and self.dataset.state == Dataset.states.DEFERRED + return self.dataset is not None and self.dataset.state == Dataset.states.DEFERRED @property def deferred_source_uri(self): @@ -5292,6 +5297,7 @@ class DatasetInstance(RepresentById, UsesCreateAndUpdateTime, _HasTable): replacement.object_store_id = self.dataset.object_store_id self.dataset = replacement self.dataset_id = None + assert self.dataset.object_store is not None self.dataset.object_store.create(self.dataset) self.extension = "expression.json" self.state = self.states.OK @@ -5304,9 +5310,11 @@ class DatasetInstance(RepresentById, UsesCreateAndUpdateTime, _HasTable): self.set_total_size() def get_file_name(self, sync_cache: bool = True) -> str: + assert self.dataset is not None return self.dataset.get_file_name(sync_cache=sync_cache) def set_file_name(self, filename: str): + assert self.dataset is not None return self.dataset.set_file_name(filename) def link_to(self, path): @@ -5829,9 +5837,13 @@ class HistoryDatasetAssociation(DatasetInstance, HasTags, Dictifiable, UsesAnnot history_id: Mapped[Optional[int]] dataset_id: Mapped[Optional[int]] extension: Mapped[str] + _metadata: Mapped[Optional[dict[str, Any]]] + version: Mapped[Optional[int]] + hid: Mapped[Optional[int]] hidden_beneath_collection_instance: Mapped[Optional["HistoryDatasetCollectionAssociation"]] tags: Mapped[list["HistoryDatasetAssociationTagAssociation"]] copied_to_history_dataset_associations: Mapped[list["HistoryDatasetAssociation"]] + history: Mapped[Optional["History"]] def __init__( self, @@ -5987,6 +5999,7 @@ class HistoryDatasetAssociation(DatasetInstance, HasTags, Dictifiable, UsesAnnot """ Copy this HDA to a library optionally replacing an existing LDDA. """ + assert self.dataset is not None if not self.dataset.shareable: raise Exception(CANNOT_SHARE_PRIVATE_DATASET_MESSAGE) @@ -5999,7 +6012,9 @@ class HistoryDatasetAssociation(DatasetInstance, HasTags, Dictifiable, UsesAnnot # applied to the new LibraryDataset, and the current user's DefaultUserPermissions will be applied # to the associated Dataset. library_dataset = LibraryDataset(folder=target_folder, name=self.name, info=self.info) - user = trans.user or self.history.user + user = trans.user + if not user and self.history is not None: + user = self.history.user ldda = LibraryDatasetDatasetAssociation( name=element_identifier or self.name, info=self.info, @@ -10932,9 +10947,9 @@ class MetadataFile(Base, StorableObject, Serializable): self.name = name @property - def dataset(self) -> Optional["DatasetInstance"]: + def dataset(self) -> Dataset | None: da = self.history_dataset or self.library_dataset - return da and da.dataset + return da.dataset if da is not None else None def update_from_file(self, file_name): if not self.dataset: @@ -10953,9 +10968,11 @@ class MetadataFile(Base, StorableObject, Serializable): try: da = self.history_dataset or self.library_dataset assert da is not None + assert da.dataset is not None if self.object_store_id is None: self.object_store_id = da.dataset.object_store_id object_store = da.dataset.object_store + assert object_store is not None store_by = object_store.get_store_by(da.dataset) if store_by == "id" and self.id is None: self.flush() # type: ignore[unreachable] diff --git a/lib/galaxy/model/dataset_collections/adapters.py b/lib/galaxy/model/dataset_collections/adapters.py index a53e8090294..bb847c889b9 100644 --- a/lib/galaxy/model/dataset_collections/adapters.py +++ b/lib/galaxy/model/dataset_collections/adapters.py @@ -158,6 +158,7 @@ class PromoteDatasetToCollection(CollectionAdapter): @property def dataset_action_tuples(self): hda = self._hda + assert hda.dataset is not None return [(permission.action, permission.role_id) for permission in hda.dataset.actions] @property @@ -165,6 +166,7 @@ class PromoteDatasetToCollection(CollectionAdapter): hda = self._hda dbkeys = [hda.dbkey] if hda.dbkey else [] extensions = [hda.extension] if hda.extension else [] + assert hda.dataset is not None states = {hda.dataset.state: 1} if hda.dataset.state else {} deleted = 1 if hda.deleted or (hda.dataset and hda.dataset.deleted) else 0 return CollectionStateSummary(dbkeys=dbkeys, extensions=extensions, states=states, deleted=deleted) diff --git a/lib/galaxy/model/dataset_collections/types/sample_sheet_workbook.py b/lib/galaxy/model/dataset_collections/types/sample_sheet_workbook.py index ca17defe683..7bd15bd9b76 100644 --- a/lib/galaxy/model/dataset_collections/types/sample_sheet_workbook.py +++ b/lib/galaxy/model/dataset_collections/types/sample_sheet_workbook.py @@ -601,7 +601,7 @@ def _list_to_sample_sheet_collection_type(input_collection_type: str) -> SampleS """ # Pass through existing sample_sheet types unchanged if input_collection_type in SAMPLE_SHEET_COLLECTION_TYPES: - return cast(SampleSheetCollectionType, input_collection_type) + return input_collection_type # Convert list types to sample_sheet types if input_collection_type == "list": diff --git a/lib/galaxy/model/deferred.py b/lib/galaxy/model/deferred.py index 17f658a56c1..532edb112a5 100644 --- a/lib/galaxy/model/deferred.py +++ b/lib/galaxy/model/deferred.py @@ -106,6 +106,7 @@ class DatasetInstanceMaterializer: """ attached = self._attached dataset = dataset_instance.dataset + assert dataset is not None if dataset.state != Dataset.states.DEFERRED and isinstance(dataset_instance, HistoryDatasetAssociation): return dataset_instance @@ -117,7 +118,7 @@ class DatasetInstanceMaterializer: materialized_dataset_hashes = [h.copy() for h in dataset.hashes] if in_place: - materialized_dataset = dataset_instance.dataset + materialized_dataset = dataset materialized_dataset.state = Dataset.states.OK else: materialized_dataset = Dataset() @@ -130,7 +131,7 @@ class DatasetInstanceMaterializer: # legacy dataset being copied, new paradigm is to treat transform as # what happened and requested_transform as what should happen - so lets # swap these in this new dataset. - source.requested_transform = source.transform + source.requested_transform = source.transform # type: ignore[assignment] # we have not applied any transforms yet, so we can clear these source.transform = None diff --git a/lib/galaxy/model/dereference.py b/lib/galaxy/model/dereference.py index d9e8c77198f..6886e818704 100644 --- a/lib/galaxy/model/dereference.py +++ b/lib/galaxy/model/dereference.py @@ -239,7 +239,7 @@ def get_replacement_dataset( dataset_sources: list[DatasetSource], dataset_hashes: Sequence[Union[DatasetHash, DatasetSourceHash]], extension: str, - object_store_id: str, + object_store_id: str | None, created_from_basename: Optional[str] = None, ) -> Optional[HistoryDatasetAssociation]: """ diff --git a/lib/galaxy/model/metadata.py b/lib/galaxy/model/metadata.py index 611e2908c52..bc1ada236df 100644 --- a/lib/galaxy/model/metadata.py +++ b/lib/galaxy/model/metadata.py @@ -649,6 +649,8 @@ class FileParameter(MetadataParameter): if target_context.parent is None: return None target_dataset = target_context.parent.dataset + assert target_dataset is not None + assert target_dataset.object_store is not None if value and target_dataset.object_store.exists(target_dataset): # Only copy MetadataFile if the target dataset has been created in an object store. # All current datatypes re-generate MetadataFile objects when setting metadata, diff --git a/lib/galaxy/model/security.py b/lib/galaxy/model/security.py index 7f0bfc2095e..c8742863aa2 100644 --- a/lib/galaxy/model/security.py +++ b/lib/galaxy/model/security.py @@ -870,14 +870,13 @@ WHERE history.user_id != :user_id and history_dataset_association.dataset_id = : permissions[action] = [dhp.role] return permissions - def set_all_dataset_permissions(self, dataset, permissions=None, new=False, flush=True): + def set_all_dataset_permissions(self, dataset: Dataset, permissions: dict, new: bool = False, flush: bool = True): """ Set new full permissions on a dataset, eliminating all current permissions. Permission looks like: { Action : [ Role, Role ] } """ # Make sure that DATASET_MANAGE_PERMISSIONS is associated with at least 1 role has_dataset_manage_permissions = False - permissions = permissions or {} for _ in _walk_action_roles(permissions, self.permitted_actions.DATASET_MANAGE_PERMISSIONS): has_dataset_manage_permissions = True break diff --git a/lib/galaxy/model/store/__init__.py b/lib/galaxy/model/store/__init__.py index 5609b4c7854..8c577e9d9cb 100644 --- a/lib/galaxy/model/store/__init__.py +++ b/lib/galaxy/model/store/__init__.py @@ -435,13 +435,15 @@ class ModelImportStore(metaclass=abc.ABCMeta): dataset_or_file_attrs: dict[str, Any], dataset_instance: model.DatasetInstance, ) -> None: + dataset = dataset_instance.dataset + assert dataset is not None if "hashes" in dataset_or_file_attrs: for hash_attrs in dataset_or_file_attrs["hashes"]: hash_obj = model.DatasetHash() hash_obj.hash_value = hash_attrs["hash_value"] hash_obj.hash_function = hash_attrs["hash_function"] hash_obj.extra_files_path = hash_attrs["extra_files_path"] - dataset_instance.dataset.hashes.append(hash_obj) + dataset.hashes.append(hash_obj) def _attach_dataset_sources( self, @@ -472,6 +474,7 @@ class ModelImportStore(metaclass=abc.ABCMeta): hash_obj.hash_function = hash_attrs["hash_function"] source_obj.hashes.append(hash_obj) + assert dataset_instance.dataset is not None dataset_instance.dataset.sources.append(source_obj) def _import_datasets( @@ -611,6 +614,7 @@ class ModelImportStore(metaclass=abc.ABCMeta): dataset_instance.metadata = metadata self._attach_raw_id_if_editing(dataset_instance, dataset_attrs) + assert dataset_instance.dataset is not None # Older style... if self.import_options.allow_edit: if "uuid" in dataset_attrs: @@ -671,7 +675,6 @@ class ModelImportStore(metaclass=abc.ABCMeta): dataset_instance.deleted = False if isinstance(dataset_instance, model.HistoryDatasetAssociation): dataset_instance.purged = False - assert dataset_instance.dataset dataset_instance.dataset.deleted = False dataset_instance.dataset.purged = False elif ( @@ -688,7 +691,6 @@ class ModelImportStore(metaclass=abc.ABCMeta): dataset_instance.deleted = deleted if isinstance(dataset_instance, model.HistoryDatasetAssociation): dataset_instance.purged = deleted - assert dataset_instance.dataset dataset_instance.dataset.state = target_state dataset_instance.dataset.deleted = deleted dataset_instance.dataset.purged = deleted @@ -2062,6 +2064,7 @@ class DirectoryModelExportStore(ModelExportStore): dir_name = "datasets" dir_path = os.path.join(export_directory, dir_name) + assert dataset.dataset is not None if dataset.dataset.id in self.dataset_id_to_path: file_name, extra_files_path = self.dataset_id_to_path[dataset.dataset.id] if file_name is not None: @@ -2432,6 +2435,7 @@ class DirectoryModelExportStore(ModelExportStore): self.included_datasets[dataset] = (dataset, include_files) def _ensure_dataset_file_exists(self, dataset: model.DatasetInstance) -> None: + assert dataset.dataset is not None state = dataset.dataset.state if state in [model.Dataset.states.OK] and not dataset.get_file_name(): log.error( @@ -2644,7 +2648,7 @@ class WriteCrates: with open(markdown_path, "w") as f: f.write(self._generate_markdown_readme()) - properties = { + properties: dict[str, Any] = { "name": "README.md", "encodingFormat": "text/markdown", "about": {"@id": "./"}, @@ -2656,6 +2660,7 @@ class WriteCrates: ) for dataset, _ in self.included_datasets.values(): + assert dataset.dataset is not None if dataset.dataset.id in self.dataset_id_to_path: file_name, _ = self.dataset_id_to_path[dataset.dataset.id] if file_name is None: diff --git a/lib/galaxy/model/store/discover.py b/lib/galaxy/model/store/discover.py index 1cf2cac2a55..e460537e1a0 100644 --- a/lib/galaxy/model/store/discover.py +++ b/lib/galaxy/model/store/discover.py @@ -13,6 +13,7 @@ from collections.abc import ( Callable, Iterable, ) +from decimal import Decimal from typing import ( Any, NamedTuple, @@ -172,6 +173,7 @@ class ModelPersistenceContext(metaclass=abc.ABCMeta): if metadata_element and metadata_element.set_in_upload: setattr(primary_data.metadata, key, value) + assert primary_data.dataset is not None for source_dict in sources: source = galaxy.model.DatasetSource() source.source_uri = source_dict["source_uri"] @@ -250,10 +252,11 @@ class ModelPersistenceContext(metaclass=abc.ABCMeta): output_name, init_from, ): + assert primary_data.dataset is not None if primary_data.dataset.purged: # metadata won't be set, maybe we should do that, then purge ? - primary_data.dataset.file_size = 0 - primary_data.dataset.total_size = 0 + primary_data.dataset.file_size = Decimal(0) + primary_data.dataset.total_size = Decimal(0) return # Move data from temp location to dataset location if not link_data: diff --git a/lib/galaxy/model/store/ro_crate_utils.py b/lib/galaxy/model/store/ro_crate_utils.py index 988ca22d421..ff2914b06ef 100644 --- a/lib/galaxy/model/store/ro_crate_utils.py +++ b/lib/galaxy/model/store/ro_crate_utils.py @@ -102,6 +102,7 @@ class WorkflowRunCrateProfileBuilder: return crate def _add_file(self, dataset: HistoryDatasetAssociation, properties: dict[Any, Any], crate: ROCrate) -> File: + assert dataset.dataset is not None if dataset.dataset.id in self.model_store.dataset_id_to_path: filename, _ = self.model_store.dataset_id_to_path[dataset.dataset.id] description = "" @@ -576,6 +577,7 @@ class WorkflowRunCrateProfileBuilder: ) def _add_dataset_formal_parameter(self, hda: HistoryDatasetAssociation, crate: ROCrate): + assert hda.dataset is not None return crate.add( ContextEntity( crate, diff --git a/lib/galaxy/objectstore/__init__.py b/lib/galaxy/objectstore/__init__.py index 6e9116d044e..e511f51740e 100644 --- a/lib/galaxy/objectstore/__init__.py +++ b/lib/galaxy/objectstore/__init__.py @@ -2104,6 +2104,7 @@ class ObjectStorePopulator: self.user = user def set_object_store_id(self, data: "DatasetInstance", require_shareable: bool = False) -> None: + assert data.dataset is not None self.set_dataset_object_store_id(data.dataset, require_shareable=require_shareable) def set_dataset_object_store_id(self, dataset: "Dataset", require_shareable: bool = True) -> None: @@ -2126,8 +2127,8 @@ def persist_extra_files( primary_data: "DatasetInstance", extra_files_path_name: Optional[str] = None, ) -> None: + assert primary_data.dataset is not None if not primary_data.dataset.purged and os.path.exists(src_extra_files_path): - assert primary_data.dataset if not extra_files_path_name: extra_files_path_name = primary_data.dataset.extra_files_path_name_from(object_store) assert extra_files_path_name diff --git a/lib/galaxy/tool_shed/galaxy_install/tools/data_manager.py b/lib/galaxy/tool_shed/galaxy_install/tools/data_manager.py index 808dee9485e..4c6e715f11d 100644 --- a/lib/galaxy/tool_shed/galaxy_install/tools/data_manager.py +++ b/lib/galaxy/tool_shed/galaxy_install/tools/data_manager.py @@ -171,7 +171,7 @@ class DataManagerHandler: if data_manager: rval.append(data_manager) elif elem.tag is etree.Comment: # type: ignore[comparison-overlap] - pass + pass # type: ignore[unreachable] else: log.warning(f"Encountered unexpected element '{elem.tag}':\n{xml_to_string(elem)}") config_elems.append(elem) diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py index 39d500645d2..df2398d296a 100644 --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -3227,7 +3227,8 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle): # Map dataset or collection to current history def map_to_history(value): if isinstance(value, HistoryDatasetAssociation): - id: int = value.dataset.id + assert value.dataset is not None + id = value.dataset.id source: Union[ dict[Union[int, str], HistoryDatasetAssociation], dict[Union[int, str], HistoryDatasetCollectionAssociation], @@ -3378,6 +3379,7 @@ class OutputParameterJSONTool(Tool): # allow multiple files to be created file_name = str(wrapped_data) extra_files_path = str(wrapped_data.files_path) + assert data.dataset is not None data_dict = dict( out_data_name=out_name, ext=data.ext, @@ -3592,6 +3594,7 @@ class DataSourceTool(OutputParameterJSONTool): data.extension = cur_data_type file_name = str(wrapped_data) extra_files_path = str(wrapped_data.files_path) + assert data.dataset is not None data_dict = dict( out_data_name=out_name, ext=data.ext, @@ -3766,6 +3769,8 @@ class DataManagerTool(OutputParameterJSONTool): elif data_manager_mode == "bundle": for bundle_path, dataset in data_manager.write_bundle(out_data).items(): hda = cast(HistoryDatasetAssociation, dataset) + assert hda.dataset is not None + assert hda.dataset.object_store is not None hda.dataset.object_store.update_from_file( hda.dataset, extra_dir=hda.dataset.extra_files_path_name, diff --git a/lib/galaxy/tools/actions/__init__.py b/lib/galaxy/tools/actions/__init__.py index 287c32e415e..95ee894de46 100644 --- a/lib/galaxy/tools/actions/__init__.py +++ b/lib/galaxy/tools/actions/__init__.py @@ -591,6 +591,7 @@ class DefaultToolAction(ToolAction): data = HistoryDatasetAssociation( extension=ext, dataset=dataset, create_dataset=create_datasets, flush=False ) + assert data.dataset is not None if create_datasets: from_work_dir = output.from_work_dir if from_work_dir is not None: diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index e3f9dde3b36..17f89ed304a 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -2898,6 +2898,7 @@ def raw_to_galaxy( ) primary_data.state = Dataset.states.DEFERRED permissions = app.security_agent.history_get_default_permissions(history) + assert primary_data.dataset is not None app.security_agent.set_all_dataset_permissions(primary_data.dataset, permissions, new=True, flush=False) app.model.session.add(primary_data) history.stage_addition(primary_data) diff --git a/lib/galaxy/tools/runtime.py b/lib/galaxy/tools/runtime.py index 15eed8790ef..eaf84e16ccf 100644 --- a/lib/galaxy/tools/runtime.py +++ b/lib/galaxy/tools/runtime.py @@ -99,7 +99,7 @@ def setup_for_runtimeify( hda_entry, index = hdas_by_id[hda_id] if not hda_entry: raise ValueError(f"Could not find HDA for dataset id {hda_id}") - size = hda_entry.dataset.get_size() if hda_entry and hda_entry.dataset else 0 + assert hda_entry.dataset is not None properties: dict[str, Any] = { "class": "File", "location": f"step_input://{index}", @@ -107,7 +107,7 @@ def setup_for_runtimeify( "path": ( compute_environment.input_path_rewrite(hda_entry) if compute_environment else hda_entry.get_file_name() ), - "size": int(size), + "size": hda_entry.dataset.get_size(), "listing": [], } set_basename_and_derived_properties(properties, hda_entry.dataset.created_from_basename or hda_entry.name) diff --git a/lib/galaxy/webapps/galaxy/services/datasets.py b/lib/galaxy/webapps/galaxy/services/datasets.py index fa0cdf1f717..aae67a7ec74 100644 --- a/lib/galaxy/webapps/galaxy/services/datasets.py +++ b/lib/galaxy/webapps/galaxy/services/datasets.py @@ -736,7 +736,8 @@ class DatasetsService(ServiceBase, UsesVisualizationMixin): if metadata_spec is None: raise galaxy_exceptions.RequestParameterInvalidException(f"Unknown metadata file: {metadata_file}") file_ext = metadata_spec.get("file_ext", metadata_file) - fname = "".join(c in util.FILENAME_VALID_CHARS and c or "_" for c in hda.name)[0:150] + hda_name = hda.name or "Unnamed dataset" + fname = "".join(c in util.FILENAME_VALID_CHARS and c or "_" for c in hda_name)[0:150] headers = {} headers["Content-Type"] = "application/octet-stream" headers["Content-Disposition"] = f'attachment; filename="Galaxy{hda.hid}-[{fname}].{file_ext}"' diff --git a/lib/galaxy/webapps/galaxy/services/history_contents.py b/lib/galaxy/webapps/galaxy/services/history_contents.py index de8edec9494..581d1dc772e 100644 --- a/lib/galaxy/webapps/galaxy/services/history_contents.py +++ b/lib/galaxy/webapps/galaxy/services/history_contents.py @@ -375,6 +375,8 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto content_name = dataset_collection_instance.name else: raise exceptions.UnknownContentsType(f"Unknown contents type: {contents_type}") + if not content_name: + raise exceptions.RequestParameterInvalidException("Content must have a name") short_term_storage_target = model_store_storage_target( self.short_term_storage_allocator, content_name, @@ -615,6 +617,7 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto payload_dict = payload.model_dump(by_alias=True) hda = self.hda_manager.get_owned(history_content_id, trans.user, current_history=trans.history, trans=trans) assert hda is not None + assert hda.history is not None self.history_manager.error_unless_mutable(hda.history) self.hda_manager.update_permissions(trans, hda, **payload_dict) roles = self.hda_manager.serialize_dataset_association_roles(hda) @@ -881,6 +884,7 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto def __delete_dataset(self, trans, id: DecodedDatabaseIdField, purge: bool, stop_job: bool): hda = self.hda_manager.get_owned(id, trans.user, current_history=trans.history) + assert hda.history is not None self.history_manager.error_unless_mutable(hda.history) self.hda_manager.error_if_uploading(hda) @@ -1237,6 +1241,7 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto def __create_hda_from_copy(self, trans, history: History, original_hda_id: int): original = self.hda_manager.get_accessible(original_hda_id, trans.user) + assert original.history is not None # check for access on history that contains the original hda as well self.history_manager.error_unless_accessible(original.history, trans.user, current_history=trans.history) hda = self.hda_manager.copy(original, history=history) @@ -1508,6 +1513,7 @@ class HistoryItemOperator: self.hda_manager.ensure_can_change_datatype(item) self.hda_manager.ensure_can_set_metadata(item) is_deferred = item.has_deferred_data + assert item.dataset is not None item.state = item.dataset.states.SETTING_METADATA if is_deferred: if params.datatype == "auto": # if `auto` just keep the original guessed datatype diff --git a/lib/galaxy/workflow/extract.py b/lib/galaxy/workflow/extract.py index a5379030675..cdf228166ce 100644 --- a/lib/galaxy/workflow/extract.py +++ b/lib/galaxy/workflow/extract.py @@ -385,6 +385,7 @@ class WorkflowSummary: return hid_in_history = dataset.hid + assert hid_in_history is not None original_hda = self.__original_hda(dataset) self.hda_hid_in_history[original_hda.id] = hid_in_history diff --git a/lib/galaxy/workflow/modules.py b/lib/galaxy/workflow/modules.py index aa733d5b039..9f0d8439e52 100644 --- a/lib/galaxy/workflow/modules.py +++ b/lib/galaxy/workflow/modules.py @@ -172,6 +172,7 @@ def to_cwl( element_identifier = value.element_identifier value = value.element_object if isinstance(value, model.HistoryDatasetAssociation): + assert value.dataset is not None # I think the following two checks are needed but they may # not be needed. if step: diff --git a/lib/tool_shed/metadata/repository_metadata_manager.py b/lib/tool_shed/metadata/repository_metadata_manager.py index e18e566b137..e7097a62cba 100644 --- a/lib/tool_shed/metadata/repository_metadata_manager.py +++ b/lib/tool_shed/metadata/repository_metadata_manager.py @@ -1224,7 +1224,7 @@ def get_repository_metadata(session, repository_id): stmt = ( select(RepositoryMetadata) .where(RepositoryMetadata.repository_id == repository_id) - .order_by(RepositoryMetadata.changeset_revision, RepositoryMetadata.update_time.desc()) # type: ignore[attr-defined] # mapped attribute + .order_by(RepositoryMetadata.changeset_revision, RepositoryMetadata.update_time.desc()) ) return session.scalars(stmt) diff --git a/lib/tool_shed/webapp/model/__init__.py b/lib/tool_shed/webapp/model/__init__.py index dfce40984e2..eaecc037ca4 100644 --- a/lib/tool_shed/webapp/model/__init__.py +++ b/lib/tool_shed/webapp/model/__init__.py @@ -385,13 +385,14 @@ class Repository(Base, Dictifiable): user = relationship("User", back_populates="active_repositories") downloadable_revisions = relationship( "RepositoryMetadata", - primaryjoin=lambda: (Repository.id == RepositoryMetadata.repository_id) & (RepositoryMetadata.downloadable == true()), # type: ignore[has-type] + primaryjoin=lambda: (Repository.id == RepositoryMetadata.repository_id) + & (RepositoryMetadata.downloadable == true()), viewonly=True, - order_by=lambda: desc(RepositoryMetadata.update_time), # type: ignore[attr-defined] + order_by=lambda: desc(RepositoryMetadata.update_time), ) metadata_revisions = relationship( "RepositoryMetadata", - order_by=lambda: desc(RepositoryMetadata.update_time), # type: ignore[attr-defined] + order_by=lambda: desc(RepositoryMetadata.update_time), back_populates="repository", ) roles = relationship("RepositoryRoleAssociation", back_populates="repository") @@ -687,7 +688,11 @@ class Tag(Base): class RepositoryMetadata(Dictifiable): - repository: "Repository" + update_time: Mapped[DateTime] + repository_id: Mapped[Optional[int]] + changeset_revision: Mapped[Optional[str]] + downloadable: Mapped[bool] + repository: Mapped["Repository"] # Once the class has been mapped, all Column items in this table will be available # as instrumented class attributes on RepositoryMetadata. diff --git a/test/unit/app/tools/test_runtime.py b/test/unit/app/tools/test_runtime.py index 6026f59444c..d96be051694 100644 --- a/test/unit/app/tools/test_runtime.py +++ b/test/unit/app/tools/test_runtime.py @@ -59,6 +59,7 @@ def create_model_collection(collection_type, elements_data): hda = HistoryDatasetAssociation(create_dataset=True, flush=False, name=content) hda.id = i + 100 # Fake ID for testing # Also satisfy accessing hda.dataset.created_from_basename or hda.name in generic adapt if needed + assert hda.dataset is not None hda.dataset.id = i + 1000 dce = DatasetCollectionElement(collection=collection, element_identifier=name, element_index=i, element=hda) diff --git a/test/unit/data/model/test_model_store.py b/test/unit/data/model/test_model_store.py index 56ff5e6e0b9..3d3d8f9c60f 100644 --- a/test/unit/data/model/test_model_store.py +++ b/test/unit/data/model/test_model_store.py @@ -212,6 +212,7 @@ def test_import_export_history_with_implicit_conversion_and_extra_files(): app.object_store.update_from_file(implicit_hda.dataset, file_name=TEST_PATH_2_CONVERTED, create=True) d2.dataset.create_extra_files_path() + assert implicit_hda.dataset is not None implicit_hda.dataset.create_extra_files_path() app.write_primary_file(d2, "cool primary file 1") @@ -296,6 +297,7 @@ def test_import_from_dict(): assert imported_hda.state == "deferred" assert not imported_hda.deleted + assert imported_hda.dataset is not None assert len(imported_hda.dataset.hashes) == 1 assert len(imported_hda.dataset.sources) == 1 assert imported_hda.dataset.created_from_basename == "dataset.txt" diff --git a/test/unit/data/test_dataset_materialization.py b/test/unit/data/test_dataset_materialization.py index 4f56c97b076..20ef63e2657 100644 --- a/test/unit/data/test_dataset_materialization.py +++ b/test/unit/data/test_dataset_materialization.py @@ -47,10 +47,12 @@ def test_deferred_hdas_basic_attached(): deferred_hda = fixture_context.history.datasets[0] assert deferred_hda _assert_2_bed_metadata(deferred_hda) + assert deferred_hda.dataset is not None assert deferred_hda.dataset.state == "deferred" materializer = materializer_factory(True, object_store=fixture_context.app.object_store) materialized_hda = materializer.ensure_materialized(deferred_hda) materialized_dataset = materialized_hda.dataset + assert materialized_dataset is not None assert materialized_dataset.state == "ok" # only detached datasets would be created with an external_filename assert not materialized_dataset.external_filename @@ -68,10 +70,12 @@ def test_hash_validate(): deferred_hda = fixture_context.history.datasets[0] assert deferred_hda _assert_2_bed_metadata(deferred_hda) + assert deferred_hda.dataset is not None assert deferred_hda.dataset.state == "deferred" materializer = materializer_factory(True, object_store=fixture_context.app.object_store) materialized_hda = materializer.ensure_materialized(deferred_hda) materialized_dataset = materialized_hda.dataset + assert materialized_dataset is not None assert materialized_dataset.state == "ok" @@ -83,10 +87,12 @@ def test_hash_invalid(): deferred_hda = fixture_context.history.datasets[0] assert deferred_hda _assert_2_bed_metadata(deferred_hda) + assert deferred_hda.dataset is not None assert deferred_hda.dataset.state == "deferred" materializer = materializer_factory(True, object_store=fixture_context.app.object_store) materialized_hda = materializer.ensure_materialized(deferred_hda) materialized_dataset = materialized_hda.dataset + assert materialized_dataset is not None assert materialized_dataset.state == "error" @@ -101,6 +107,7 @@ def test_legacy_transform_actions_on_deferred_hdas_become_requested_actions(): perform_import_from_store_dict(fixture_context, store_dict) deferred_hda = fixture_context.history.datasets[0] deferred_dataset = deferred_hda.dataset + assert deferred_dataset is not None assert deferred_dataset.sources[0].transform is None assert deferred_dataset.sources[0].requested_transform == [{"action": "spaces_to_tabs"}] @@ -114,6 +121,7 @@ def test_requested_transform_actions_on_deferred_hdas_preserved(): perform_import_from_store_dict(fixture_context, store_dict) deferred_hda = fixture_context.history.datasets[0] deferred_dataset = deferred_hda.dataset + assert deferred_dataset is not None assert deferred_dataset.sources[0].transform is None assert deferred_dataset.sources[0].requested_transform == [{"action": "spaces_to_tabs"}] @@ -128,10 +136,12 @@ def test_hash_validate_source_of_download(): deferred_hda = fixture_context.history.datasets[0] assert deferred_hda _assert_2_bed_metadata(deferred_hda) + assert deferred_hda.dataset is not None assert deferred_hda.dataset.state == "deferred" materializer = materializer_factory(True, object_store=fixture_context.app.object_store) materialized_hda = materializer.ensure_materialized(deferred_hda) materialized_dataset = materialized_hda.dataset + assert materialized_dataset is not None assert materialized_dataset.state == "ok", materialized_hda.info @@ -145,10 +155,12 @@ def test_hash_invalid_source_of_download(): deferred_hda = fixture_context.history.datasets[0] assert deferred_hda _assert_2_bed_metadata(deferred_hda) + assert deferred_hda.dataset is not None assert deferred_hda.dataset.state == "deferred" materializer = materializer_factory(True, object_store=fixture_context.app.object_store) materialized_hda = materializer.ensure_materialized(deferred_hda) materialized_dataset = materialized_hda.dataset + assert materialized_dataset is not None assert materialized_dataset.state == "error", materialized_hda.info @@ -160,10 +172,12 @@ def test_deferred_hdas_basic_attached_store_by_uuid(): deferred_hda = fixture_context.history.datasets[0] assert deferred_hda _assert_2_bed_metadata(deferred_hda) + assert deferred_hda.dataset is not None assert deferred_hda.dataset.state == "deferred" materializer = materializer_factory(True, object_store=fixture_context.app.object_store) materialized_hda = materializer.ensure_materialized(deferred_hda) materialized_dataset = materialized_hda.dataset + assert materialized_dataset is not None assert materialized_dataset.state == "ok" # only detached datasets would be created with an external_filename assert not materialized_dataset.external_filename @@ -180,10 +194,12 @@ def test_deferred_hdas_basic_detached(tmpdir): deferred_hda = fixture_context.history.datasets[0] assert deferred_hda _assert_2_bed_metadata(deferred_hda) + assert deferred_hda.dataset is not None assert deferred_hda.dataset.state == "deferred" materializer = materializer_factory(False, transient_directory=tmpdir) materialized_hda = materializer.ensure_materialized(deferred_hda) materialized_dataset = materialized_hda.dataset + assert materialized_dataset is not None assert materialized_dataset.state == "ok" external_filename = materialized_dataset.external_filename assert external_filename @@ -198,12 +214,14 @@ def test_deferred_datasets_with_legacy_transforms_respect_transform(tmpdir): perform_import_from_store_dict(fixture_context, store_dict) deferred_hda = fixture_context.history.datasets[0] assert deferred_hda + assert deferred_hda.dataset is not None assert deferred_hda.dataset.state == "deferred" assert deferred_hda.dataset.sources[0].transform is None assert deferred_hda.dataset.sources[0].requested_transform == [{"action": "spaces_to_tabs"}] materializer = materializer_factory(False, transient_directory=tmpdir) materialized_hda = materializer.ensure_materialized(deferred_hda) materialized_dataset = materialized_hda.dataset + assert materialized_dataset is not None assert materialized_dataset.sources[0].transform == [{"action": "spaces_to_tabs"}] assert materialized_dataset.sources[0].requested_transform == [{"action": "spaces_to_tabs"}] assert materialized_dataset.state == "ok" @@ -219,6 +237,7 @@ def test_deferred_datasets_with_requested_transforms_respect_transform(tmpdir): perform_import_from_store_dict(fixture_context, store_dict) deferred_hda = fixture_context.history.datasets[0] assert deferred_hda + assert deferred_hda.dataset is not None assert deferred_hda.dataset.state == "deferred" assert deferred_hda.dataset.sources[0].transform is None assert deferred_hda.dataset.sources[0].requested_transform == [ @@ -228,6 +247,7 @@ def test_deferred_datasets_with_requested_transforms_respect_transform(tmpdir): materializer = materializer_factory(False, transient_directory=tmpdir) materialized_hda = materializer.ensure_materialized(deferred_hda) materialized_dataset = materialized_hda.dataset + assert materialized_dataset is not None assert materialized_dataset.sources[0].transform == [{"action": "spaces_to_tabs"}] assert materialized_dataset.sources[0].requested_transform == [ {"action": "datatype_groom"}, @@ -246,12 +266,14 @@ def test_deferred_datasets_do_not_apply_unspecified_transforms_legacy(tmpdir): perform_import_from_store_dict(fixture_context, store_dict) deferred_hda = fixture_context.history.datasets[0] assert deferred_hda + assert deferred_hda.dataset is not None assert deferred_hda.dataset.state == "deferred" assert deferred_hda.dataset.sources[0].transform is None assert deferred_hda.dataset.sources[0].requested_transform == [] materializer = materializer_factory(False, transient_directory=tmpdir) materialized_hda = materializer.ensure_materialized(deferred_hda) materialized_dataset = materialized_hda.dataset + assert materialized_dataset is not None assert materialized_dataset.sources[0].transform == [] assert materialized_dataset.sources[0].requested_transform == [] assert materialized_dataset.state == "ok" @@ -267,12 +289,14 @@ def test_deferred_datasets_do_not_apply_unspecified_transforms(tmpdir): perform_import_from_store_dict(fixture_context, store_dict) deferred_hda = fixture_context.history.datasets[0] assert deferred_hda + assert deferred_hda.dataset is not None assert deferred_hda.dataset.state == "deferred" assert deferred_hda.dataset.sources[0].transform is None assert deferred_hda.dataset.sources[0].requested_transform == [{"action": "datatype_groom"}] materializer = materializer_factory(False, transient_directory=tmpdir) materialized_hda = materializer.ensure_materialized(deferred_hda) materialized_dataset = materialized_hda.dataset + assert materialized_dataset is not None assert materialized_dataset.sources[0].transform == [] assert materialized_dataset.sources[0].requested_transform == [{"action": "datatype_groom"}] assert materialized_dataset.state == "ok" @@ -291,10 +315,12 @@ def test_deferred_hdas_basic_detached_from_detached_hda(tmpdir): _ensure_relations_attached_and_expunge(deferred_hda, fixture_context) + assert deferred_hda.dataset is not None assert deferred_hda.dataset.state == "deferred" materializer = materializer_factory(False, transient_directory=tmpdir) materialized_hda = materializer.ensure_materialized(deferred_hda) materialized_dataset = materialized_hda.dataset + assert materialized_dataset is not None assert materialized_dataset.state == "ok" external_filename = materialized_dataset.external_filename assert external_filename @@ -312,12 +338,14 @@ def test_deferred_hdas_basic_attached_from_detached_hda(): _ensure_relations_attached_and_expunge(deferred_hda, fixture_context) + assert deferred_hda.dataset is not None assert deferred_hda.dataset.state == "deferred" materializer = materializer_factory( True, object_store=fixture_context.app.object_store, sa_session=fixture_context.sa_session() ) materialized_hda = materializer.ensure_materialized(deferred_hda) materialized_dataset = materialized_hda.dataset + assert materialized_dataset is not None assert materialized_dataset.state == "ok" # only detached datasets would be created with an external_filename assert not materialized_dataset.external_filename @@ -337,12 +365,14 @@ def test_deferred_ldda_basic_attached(): perform_import_from_store_dict(fixture_context, store_dict, import_options=import_options) deferred_ldda = fixture_context.sa_session.scalars(select(LibraryDatasetDatasetAssociation)).all()[0] assert deferred_ldda + assert deferred_ldda.dataset is not None assert deferred_ldda.dataset.state == "deferred" materializer = materializer_factory(True, object_store=fixture_context.app.object_store) materialized_hda = materializer.ensure_materialized(deferred_ldda) assert materialized_hda.history is None materialized_dataset = materialized_hda.dataset + assert materialized_dataset is not None assert materialized_dataset.state == "ok" # only detached datasets would be created with an external_filename assert not materialized_dataset.external_filename @@ -365,10 +395,12 @@ def test_deferred_hdas_basic_attached_file_sources(tmpdir): perform_import_from_store_dict(fixture_context, store_dict) deferred_hda = fixture_context.history.datasets[0] assert deferred_hda + assert deferred_hda.dataset is not None assert deferred_hda.dataset.state == "deferred" materializer = materializer_factory(True, object_store=fixture_context.app.object_store, file_sources=file_sources) materialized_hda = materializer.ensure_materialized(deferred_hda) materialized_dataset = materialized_hda.dataset + assert materialized_dataset is not None assert materialized_dataset.state == "ok" # only detached datasets would be created with an external_filename assert not materialized_dataset.external_filename @@ -385,10 +417,12 @@ def test_deferred_hdas_with_deferred_metadata(): perform_import_from_store_dict(fixture_context, store_dict) deferred_hda = fixture_context.history.datasets[0] assert deferred_hda + assert deferred_hda.dataset is not None assert deferred_hda.dataset.state == "deferred" materializer = materializer_factory(True, object_store=fixture_context.app.object_store) materialized_hda = materializer.ensure_materialized(deferred_hda) materialized_dataset = materialized_hda.dataset + assert materialized_dataset is not None assert not materialized_hda.metadata_deferred assert materialized_dataset.state == "ok" # only detached datasets would be created with an external_filename @@ -448,6 +482,7 @@ def _test_hdca( perform_import_from_store_dict(fixture_context, store_dict) deferred_hda = fixture_context.history.datasets[0] sa_session.add(deferred_hda) + assert deferred_hda.dataset is not None assert deferred_hda.dataset.state == "deferred" hda_fh = tmpdir.join("file.txt") hda_fh.write("Moo Cow") @@ -503,6 +538,7 @@ def _deferred_element_count(dataset_collection: DatasetCollection) -> int: def _ensure_relations_attached_and_expunge(deferred_hda: HistoryDatasetAssociation, fixture_context) -> None: # make sure everything needed is in session (sources, hashes, and metadata)... # point here is exercise deferred_hda.history throws a detached error. + assert deferred_hda.dataset is not None [s.hashes for s in deferred_hda.dataset.sources] deferred_hda.dataset.hashes # noqa: B018 deferred_hda._metadata # noqa: B018 diff --git a/test/unit/data/test_dereference.py b/test/unit/data/test_dereference.py index 6efdb3ee10e..908c8f71766 100644 --- a/test/unit/data/test_dereference.py +++ b/test/unit/data/test_dereference.py @@ -14,6 +14,7 @@ def test_dereference(): uri_request = DataRequestUri(url=TEST_URI, ext="bed") hda = dereference_to_model(sa_session, user, history, uri_request) assert hda.name == "1.bed" + assert hda.dataset is not None assert hda.dataset.sources[0].source_uri == TEST_URI assert hda.ext == "bed" @@ -23,6 +24,7 @@ def test_dereference_dbkey(): uri_request = DataRequestUri(url=TEST_URI, ext="bed", dbkey="hg19") hda = dereference_to_model(sa_session, user, history, uri_request) assert hda.name == "1.bed" + assert hda.dataset is not None assert hda.dataset.sources[0].source_uri == TEST_URI assert hda.dbkey == "hg19" @@ -40,6 +42,7 @@ def test_dereference_md5(): ) hda = dereference_to_model(sa_session, user, history, uri_request) assert hda.name == "foobar.txt" + assert hda.dataset is not None assert hda.dataset.sources[0].source_uri == TEST_BASE64_URI assert hda.dataset.sources[0].hashes[0] assert hda.dataset.sources[0].hashes[0].hash_function == "MD5" @@ -53,7 +56,9 @@ def test_dereference_to_posix(): ) hda = dereference_to_model(sa_session, user, history, uri_request) assert hda.name == "foobar.txt" + assert hda.dataset is not None assert hda.dataset.sources[0].source_uri == TEST_BASE64_URI + assert hda.dataset.sources[0].requested_transform is not None assert hda.dataset.sources[0].requested_transform[0]["action"] == "datatype_groom" assert hda.dataset.sources[0].requested_transform[1]["action"] == "spaces_to_tabs" assert hda.dataset.state == hda.states.DEFERRED diff --git a/test/unit/data/test_quota.py b/test/unit/data/test_quota.py index 8476afbad25..a67842530d9 100644 --- a/test/unit/data/test_quota.py +++ b/test/unit/data/test_quota.py @@ -37,7 +37,8 @@ class TestPurgeUsage(BaseModelTestCase): d1 = model.HistoryDatasetAssociation( extension="txt", history=self.h, create_dataset=True, sa_session=self.model.session ) - d1.dataset.total_size = 10 + assert d1.dataset is not None + d1.dataset.total_size = Decimal(10) self.persist(d1) return d1 @@ -86,6 +87,7 @@ class TestCalculateUsage(BaseModelTestCase): d1 = model.HistoryDatasetAssociation( extension="txt", history=self.h, create_dataset=True, sa_session=self.model.session ) + assert d1.dataset is not None d1.dataset.total_size = total_size d1.dataset.object_store_id = object_store_id self.persist(d1) @@ -567,6 +569,7 @@ backends: d1 = model.HistoryDatasetAssociation( extension="txt", history=self.h, create_dataset=True, sa_session=self.model.session ) + assert d1.dataset is not None d1.dataset.total_size = total_size d1.dataset.object_store_id = object_store_id self.persist(d1) From 0376130bd585f7e537d003db22a3adb8935e523c Mon Sep 17 00:00:00 2001 From: Nicola Soranzo Date: Tue, 7 Apr 2026 13:53:13 +0100 Subject: [PATCH 3/3] Update integration test job_conf syntax for TPV 3.2.0 xref https://github.com/galaxyproject/total-perspective-vortex/pull/167 --- test/integration/embedded_pulsar_tpv_job_conf.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/embedded_pulsar_tpv_job_conf.yml b/test/integration/embedded_pulsar_tpv_job_conf.yml index 2e65c0ee666..ebebe710037 100644 --- a/test/integration/embedded_pulsar_tpv_job_conf.yml +++ b/test/integration/embedded_pulsar_tpv_job_conf.yml @@ -25,7 +25,7 @@ execution: GALAXY_SLOTS: '{cores}' scheduling: accept: - - support_user_defined + - tool_type_user_defined params: remote_metadata: true docker_enabled: true @@ -41,4 +41,4 @@ execution: user_defined-*: scheduling: require: - - support_user_defined + - tool_type_user_defined